summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjardin <jardin>2003-12-23 08:09:43 +0000
committerjardin <jardin>2003-12-23 08:09:43 +0000
commiteb5d44eb8dcf25a1b328e57d1eabb1f89e3bc59b (patch)
tree2973e8563fcbd4a8cf901d211ff4f8de00c36381
parent3dbf99698a3be2e920871c3127ea089e061a127c (diff)
Initial revision
-rw-r--r--isisd/AUTHORS3
-rw-r--r--isisd/COPYING339
-rw-r--r--isisd/ChangeLog69
-rw-r--r--isisd/INSTALL-0.0.418
-rw-r--r--isisd/Makefile.am55
-rw-r--r--isisd/Makefile.in463
-rw-r--r--isisd/README20
-rw-r--r--isisd/TODO10
-rw-r--r--isisd/dict.c1496
-rw-r--r--isisd/dict.h144
-rw-r--r--isisd/include-netbsd/clnp.h547
-rw-r--r--isisd/include-netbsd/esis.h146
-rw-r--r--isisd/include-netbsd/iso.h208
-rw-r--r--isisd/isis_adjacency.c508
-rw-r--r--isisd/isis_adjacency.h126
-rw-r--r--isisd/isis_circuit.c2200
-rw-r--r--isisd/isis_circuit.h158
-rw-r--r--isisd/isis_common.h65
-rw-r--r--isisd/isis_constants.h151
-rw-r--r--isisd/isis_csm.c186
-rw-r--r--isisd/isis_csm.h47
-rw-r--r--isisd/isis_dr.c373
-rw-r--r--isisd/isis_dr.h42
-rw-r--r--isisd/isis_dynhn.c124
-rw-r--r--isisd/isis_dynhn.h42
-rw-r--r--isisd/isis_events.c336
-rw-r--r--isisd/isis_events.h54
-rw-r--r--isisd/isis_flags.c71
-rw-r--r--isisd/isis_flags.h58
-rw-r--r--isisd/isis_lsp.c2419
-rw-r--r--isisd/isis_lsp.h132
-rw-r--r--isisd/isis_main.c330
-rw-r--r--isisd/isis_misc.c438
-rw-r--r--isisd/isis_misc.h94
-rw-r--r--isisd/isis_network.c622
-rw-r--r--isisd/isis_network.h37
-rw-r--r--isisd/isis_pdu.c2478
-rw-r--r--isisd/isis_pdu.h257
-rw-r--r--isisd/isis_route.c615
-rw-r--r--isisd/isis_route.h61
-rw-r--r--isisd/isis_routemap.c100
-rw-r--r--isisd/isis_spf.c1293
-rw-r--r--isisd/isis_spf.h85
-rw-r--r--isisd/isis_tlv.c1014
-rw-r--r--isisd/isis_tlv.h268
-rw-r--r--isisd/isis_zebra.c592
-rw-r--r--isisd/isis_zebra.h33
-rw-r--r--isisd/isisd.c1989
-rw-r--r--isisd/isisd.conf.sample39
-rw-r--r--isisd/isisd.h147
-rw-r--r--isisd/iso_checksum.c192
-rw-r--r--isisd/iso_checksum.h29
-rw-r--r--isisd/modified/Makefile.am17
-rw-r--r--isisd/modified/Makefile.in462
-rw-r--r--isisd/modified/README4
-rw-r--r--isisd/modified/acconfig.h162
-rw-r--r--isisd/modified/command.c2983
-rw-r--r--isisd/modified/command.h311
-rw-r--r--isisd/modified/config.h.in368
-rwxr-xr-xisisd/modified/configure8277
-rwxr-xr-xisisd/modified/configure.in882
-rw-r--r--isisd/modified/log.c484
-rw-r--r--isisd/modified/log.h129
-rw-r--r--isisd/modified/memory.c527
-rw-r--r--isisd/modified/memory.h257
-rw-r--r--isisd/modified/rib.c3321
-rw-r--r--isisd/modified/thread.c713
-rw-r--r--isisd/modified/thread.h141
-rw-r--r--isisd/modified/vty.c2786
-rw-r--r--isisd/modified/zebra.h313
-rw-r--r--isisd/topology/Makefile.am23
-rw-r--r--isisd/topology/random.c154
-rw-r--r--isisd/topology/spacyc.c483
-rw-r--r--isisd/topology/spgrid.c729
-rw-r--r--isisd/topology/spgrid.h45
-rw-r--r--isisd/topology/sprand.c499
76 files changed, 45393 insertions, 0 deletions
diff --git a/isisd/AUTHORS b/isisd/AUTHORS
new file mode 100644
index 00000000..d9f98b22
--- /dev/null
+++ b/isisd/AUTHORS
@@ -0,0 +1,3 @@
+Sampo Saaristo <sambo@cs.tut.fi>
+Ofer Wald <ofersf@islands.co.il>
+Hannes Gredler <hannes@gredler.at>
diff --git a/isisd/COPYING b/isisd/COPYING
new file mode 100644
index 00000000..08d6e50e
--- /dev/null
+++ b/isisd/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/isisd/ChangeLog b/isisd/ChangeLog
new file mode 100644
index 00000000..78580ea1
--- /dev/null
+++ b/isisd/ChangeLog
@@ -0,0 +1,69 @@
+Version 0.0.7 to 0.0.8
+======================
+
+o A bug in handling of other ISs fragments fixed
+o hello interval now specified in *seconds*
+o replaced the adj->ipv[46]_addr tables with linked lists
+
+Version 0.0.6 to 0.0.7 (Oct 29 2002)
+======================
+
+o changed to zebra-0.93b
+o fixed a seg in SPF
+o handling/generation of LSP fragments
+o domain/area/circuit password
+
+Version 0.0.5 to 0.0.6 (Jul 4 2002)
+======================
+
+o lots of changes to SPF
+ - runs the SPF for IPv4 and IPv6 separately
+ - a number of bugs fixed
+ - simplified the implementation
+ - "7.2.7 Removal of excess paths" implemented
+o ported to freebsd (tested in 4.5-STABLE and 4.6-STABLE)
+o moved to zebra-0.93-pre2
+o "show isis topology" command added
+o "show (ip|ipv6) route isis commands added to zebra
+o a number of fixes and additions (e.g. checksum calculation and DIS state
+change event) by BeomSeok Gwak added
+
+Version 0.0.4 to 0.0.5 (Apr 26 2002)
+======================
+
+o changed to zebra-0.93-pre1
+o number of memory leaks + small bugs fixed
+o a bug related to processing of neigbors when installing routes fixed
+
+Version 0.0.3 to 0.0.4 (Feb 27 2002)
+======================
+
+o initial version of SPT algorithm
+o installing routes though zebrad
+o isis debug commands
+o work on IS-IS events (e.g. circuit state change)
+
+Version 0.0.2 to 0.0.3 (Jan 17 2002)
+======================
+
+o LSP handling improved
+o generation of pseudonode LSPs
+o DR election enhanced
+o support for p2p interfaces
+o support for topology simulation
+o more detailed output for show commands
+
+Version 0.0.1 to 0.0.2 (Dec 13 2001)
+======================
+
+o circuit state machine (isis_csm.[ch]) added
+o lot of work on LSP generation
+o ISO checksum
+o uses DGRAM sockets instead of RAW
+o gets IP(v6) addresses from zebra
+o debug can be controlled with "debug isis" command
+o read support for TE tlvs
+o work started on p2p interfaces
+o work started on isis events
+
+
diff --git a/isisd/INSTALL-0.0.4 b/isisd/INSTALL-0.0.4
new file mode 100644
index 00000000..c9843915
--- /dev/null
+++ b/isisd/INSTALL-0.0.4
@@ -0,0 +1,18 @@
+ISISd package for zebra 0.92a installation instructions:
+
+1. grab the zebra 0.92a package from www.zebra.org
+2. unpack the package using tar -zxvf zebra-0.92a.tar.gz
+3. enter the zebra-092a directory
+4. copy the contents of the isisd package into the zebra dir
+5. enter the isisd/modified directory
+6. use the README file and copy the files to the appropriate zebra dirs
+ (the simplest way to do so would be 'source README')
+7. enter the main zebra directory and issue 'automake','autoconf' and
+ 'autoheader'. if using automake version 1.5 and up use the '-i' option.
+8. run './configure --enable-isisd' (you may use other zebra config commands)
+9. run 'make'
+10. find your self something entertaining to do for the next couple of minutes
+11. you can issue 'make install' or simply work from the isisd directory
+
+for any problems, contact the developers at the sourceforge site
+http://www.sf.net/projects/isisd
diff --git a/isisd/Makefile.am b/isisd/Makefile.am
new file mode 100644
index 00000000..b9a0c7cb
--- /dev/null
+++ b/isisd/Makefile.am
@@ -0,0 +1,55 @@
+## Process this file with automake to produce Makefile.in.
+
+# INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -Itopology
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+LIBS = @LIBS@
+noinst_LIBRARIES = libisis.a
+sbin_PROGRAMS = isisd
+
+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_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
+ isis_spf.c isis_route.c isis_routemap.c
+
+
+noinst_HEADERS = \
+ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \
+ 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
+
+isisd_SOURCES = \
+ isis_main.c $(libisis_a_SOURCES)
+
+isisd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = isisd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+
+install-sysconfDATA: $(sysconf_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+ fi; fi; \
+ done
+
+depend:
+ @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c
+
+## File dependency.
+isis_adjacency.o : isis_adjacency.c ../lib/version.h ../lib/log.h \
+ ../isisd/isis_adjacency.h
+isis_pdu.o : isis_pdu.c ../lib/log.h ../isisd/isisd.h \
+ ../isisd/isis_constants.h ../isisd/isis_adjacency.h \
+ ../isisd/isis_pdu.h
+isis_circuit.o : isis_circuit.c ../isisd/isis_circuit.h
diff --git a/isisd/Makefile.in b/isisd/Makefile.in
new file mode 100644
index 00000000..46aae735
--- /dev/null
+++ b/isisd/Makefile.in
@@ -0,0 +1,463 @@
+# Makefile.in generated by automake 1.6.2 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+
+EXEEXT = @EXEEXT@
+OBJEXT = @OBJEXT@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+AMTAR = @AMTAR@
+AR = @AR@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CPP = @CPP@
+CURSES = @CURSES@
+DEPDIR = @DEPDIR@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+# INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -Itopology
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+ISISD = @ISISD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LIBPAM = @LIBPAM@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA = @INSTALL@ -m 600
+LIBS = @LIBS@
+noinst_LIBRARIES = libisis.a
+sbin_PROGRAMS = isisd
+
+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_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
+ isis_spf.c isis_route.c isis_routemap.c
+
+
+noinst_HEADERS = \
+ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \
+ 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
+
+
+isisd_SOURCES = \
+ isis_main.c $(libisis_a_SOURCES)
+
+
+isisd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = isisd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+subdir = isisd
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libisis_a_AR = $(AR) cru
+libisis_a_LIBADD =
+am_libisis_a_OBJECTS = isis_adjacency.$(OBJEXT) isis_lsp.$(OBJEXT) \
+ dict.$(OBJEXT) isis_circuit.$(OBJEXT) isis_pdu.$(OBJEXT) \
+ isis_tlv.$(OBJEXT) isisd.$(OBJEXT) isis_misc.$(OBJEXT) \
+ isis_network.$(OBJEXT) isis_zebra.$(OBJEXT) isis_dr.$(OBJEXT) \
+ isis_flags.$(OBJEXT) isis_dynhn.$(OBJEXT) \
+ iso_checksum.$(OBJEXT) isis_csm.$(OBJEXT) isis_events.$(OBJEXT) \
+ isis_spf.$(OBJEXT) isis_route.$(OBJEXT) isis_routemap.$(OBJEXT)
+libisis_a_OBJECTS = $(am_libisis_a_OBJECTS)
+sbin_PROGRAMS = isisd$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = isis_adjacency.$(OBJEXT) isis_lsp.$(OBJEXT) \
+ dict.$(OBJEXT) isis_circuit.$(OBJEXT) isis_pdu.$(OBJEXT) \
+ isis_tlv.$(OBJEXT) isisd.$(OBJEXT) isis_misc.$(OBJEXT) \
+ isis_network.$(OBJEXT) isis_zebra.$(OBJEXT) isis_dr.$(OBJEXT) \
+ isis_flags.$(OBJEXT) isis_dynhn.$(OBJEXT) \
+ iso_checksum.$(OBJEXT) isis_csm.$(OBJEXT) isis_events.$(OBJEXT) \
+ isis_spf.$(OBJEXT) isis_route.$(OBJEXT) isis_routemap.$(OBJEXT)
+am_isisd_OBJECTS = isis_main.$(OBJEXT) $(am__objects_1)
+isisd_OBJECTS = $(am_isisd_OBJECTS)
+isisd_DEPENDENCIES = ../lib/libzebra.a
+isisd_LDFLAGS =
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/dict.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_adjacency.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_circuit.Po ./$(DEPDIR)/isis_csm.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_dr.Po ./$(DEPDIR)/isis_dynhn.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_events.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_flags.Po ./$(DEPDIR)/isis_lsp.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_main.Po ./$(DEPDIR)/isis_misc.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_network.Po ./$(DEPDIR)/isis_pdu.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_route.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_routemap.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_spf.Po ./$(DEPDIR)/isis_tlv.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/isis_zebra.Po ./$(DEPDIR)/isisd.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/iso_checksum.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = README $(noinst_HEADERS) AUTHORS COPYING ChangeLog \
+ Makefile.am Makefile.in TODO
+SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu isisd/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libisis.a: $(libisis_a_OBJECTS) $(libisis_a_DEPENDENCIES)
+ -rm -f libisis.a
+ $(libisis_a_AR) libisis.a $(libisis_a_OBJECTS) $(libisis_a_LIBADD)
+ $(RANLIB) libisis.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ p1=`echo "$$p1" | sed -e 's,^.*/,,'`; \
+ f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ f=`echo "$$f" | sed -e 's,^.*/,,'`; \
+ echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+ rm -f $(DESTDIR)$(sbindir)/$$f; \
+ done
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+isisd$(EXEEXT): $(isisd_OBJECTS) $(isisd_DEPENDENCIES)
+ @rm -f isisd$(EXEEXT)
+ $(LINK) $(isisd_LDFLAGS) $(isisd_OBJECTS) $(isisd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_adjacency.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_circuit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_csm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dynhn.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_events.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_flags.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_lsp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_misc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_pdu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_spf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_tlv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isisd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iso_checksum.Po@am__quote@
+
+distclean-depend:
+ -rm -rf ./$(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+
+uninstall-sysconfDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \
+ rm -f $(DESTDIR)$(sysconfdir)/$$f; \
+ done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+ uninstall-sysconfDATA
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES clean-sbinPROGRAMS distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-tags distdir dvi dvi-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-sbinPROGRAMS install-strip install-sysconfDATA \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic tags uninstall uninstall-am \
+ uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ @list='$(sysconf_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+ $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+ fi; fi; \
+ done
+
+depend:
+ @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c
+
+isis_adjacency.o : isis_adjacency.c ../lib/version.h ../lib/log.h \
+ ../isisd/isis_adjacency.h
+isis_pdu.o : isis_pdu.c ../lib/log.h ../isisd/isisd.h \
+ ../isisd/isis_constants.h ../isisd/isis_adjacency.h \
+ ../isisd/isis_pdu.h
+isis_circuit.o : isis_circuit.c ../isisd/isis_circuit.h
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/isisd/README b/isisd/README
new file mode 100644
index 00000000..6e2198dc
--- /dev/null
+++ b/isisd/README
@@ -0,0 +1,20 @@
+Modified files in the ZEBRA-0.92a package.
+
+ ../configure.in
+ ../Makefile.am
+ ../acconfig.h
+ ../lib/log.h
+ ../lib/memory.h
+ ../lib/vty.c
+ - case ISIS_NODE:
+ ../lib/command.c
+ - case ISIS_NODE:
+ ../lib/command.h
+ - ISIS_NODE, /* IS-IS protocol mode */
+ - str #definitions
+
+
+Constraints
+
+ o Maximum number of interfaces 255
+
diff --git a/isisd/TODO b/isisd/TODO
new file mode 100644
index 00000000..e3c1352e
--- /dev/null
+++ b/isisd/TODO
@@ -0,0 +1,10 @@
+Things in the TODO list for the near future
+
+o select nearest L2 when running SPF for L1
+o remove the routes when holding time for nexthop expires
+o redist
+o autosummary
+
+Not so urgent:
+
+o Mesh groups
diff --git a/isisd/dict.c b/isisd/dict.c
new file mode 100644
index 00000000..4c787ac5
--- /dev/null
+++ b/isisd/dict.c
@@ -0,0 +1,1496 @@
+/*
+ * Dictionary Abstract Data Type
+ * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
+ *
+ * Free Software License:
+ *
+ * All rights are reserved by the author, with the following exceptions:
+ * Permission is granted to freely reproduce and distribute this software,
+ * possibly in exchange for a fee, provided that this copyright notice appears
+ * intact. Permission is also granted to adapt this software to produce
+ * derivative works, as long as the modified versions carry this copyright
+ * notice and additional notices stating that the work has been modified.
+ * This source code may be translated into executable form and incorporated
+ * into proprietary software; there is no requirement for such software to
+ * contain a copyright notice related to this source.
+ *
+ * $Id: dict.c,v 1.1 2003/12/23 08:09:47 jardin Exp $
+ * $Name: $
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+#define DICT_IMPLEMENTATION
+#include "dict.h"
+
+#ifdef KAZLIB_RCSID
+static const char rcsid[] = "$Id: dict.c,v 1.1 2003/12/23 08:09:47 jardin Exp $";
+#endif
+
+/*
+ * These macros provide short convenient names for structure members,
+ * which are embellished with dict_ prefixes so that they are
+ * properly confined to the documented namespace. It's legal for a
+ * program which uses dict to define, for instance, a macro called ``parent''.
+ * Such a macro would interfere with the dnode_t struct definition.
+ * In general, highly portable and reusable C modules which expose their
+ * structures need to confine structure member names to well-defined spaces.
+ * The resulting identifiers aren't necessarily convenient to use, nor
+ * readable, in the implementation, however!
+ */
+
+#define left dict_left
+#define right dict_right
+#define parent dict_parent
+#define color dict_color
+#define key dict_key
+#define data dict_data
+
+#define nilnode dict_nilnode
+#define nodecount dict_nodecount
+#define maxcount dict_maxcount
+#define compare dict_compare
+#define allocnode dict_allocnode
+#define freenode dict_freenode
+#define context dict_context
+#define dupes dict_dupes
+
+#define dictptr dict_dictptr
+
+#define dict_root(D) ((D)->nilnode.left)
+#define dict_nil(D) (&(D)->nilnode)
+#define DICT_DEPTH_MAX 64
+
+static dnode_t *dnode_alloc(void *context);
+static void dnode_free(dnode_t *node, void *context);
+
+/*
+ * Perform a ``left rotation'' adjustment on the tree. The given node P and
+ * its right child C are rearranged so that the P instead becomes the left
+ * child of C. The left subtree of C is inherited as the new right subtree
+ * for P. The ordering of the keys within the tree is thus preserved.
+ */
+
+static void rotate_left(dnode_t *upper)
+{
+ dnode_t *lower, *lowleft, *upparent;
+
+ lower = upper->right;
+ upper->right = lowleft = lower->left;
+ lowleft->parent = upper;
+
+ lower->parent = upparent = upper->parent;
+
+ /* don't need to check for root node here because root->parent is
+ the sentinel nil node, and root->parent->left points back to root */
+
+ if (upper == upparent->left) {
+ upparent->left = lower;
+ } else {
+ assert (upper == upparent->right);
+ upparent->right = lower;
+ }
+
+ lower->left = upper;
+ upper->parent = lower;
+}
+
+/*
+ * This operation is the ``mirror'' image of rotate_left. It is
+ * the same procedure, but with left and right interchanged.
+ */
+
+static void rotate_right(dnode_t *upper)
+{
+ dnode_t *lower, *lowright, *upparent;
+
+ lower = upper->left;
+ upper->left = lowright = lower->right;
+ lowright->parent = upper;
+
+ lower->parent = upparent = upper->parent;
+
+ if (upper == upparent->right) {
+ upparent->right = lower;
+ } else {
+ assert (upper == upparent->left);
+ upparent->left = lower;
+ }
+
+ lower->right = upper;
+ upper->parent = lower;
+}
+
+/*
+ * Do a postorder traversal of the tree rooted at the specified
+ * node and free everything under it. Used by dict_free().
+ */
+
+static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
+{
+ if (node == nil)
+ return;
+ free_nodes(dict, node->left, nil);
+ free_nodes(dict, node->right, nil);
+ dict->freenode(node, dict->context);
+}
+
+/*
+ * This procedure performs a verification that the given subtree is a binary
+ * search tree. It performs an inorder traversal of the tree using the
+ * dict_next() successor function, verifying that the key of each node is
+ * strictly lower than that of its successor, if duplicates are not allowed,
+ * or lower or equal if duplicates are allowed. This function is used for
+ * debugging purposes.
+ */
+
+static int verify_bintree(dict_t *dict)
+{
+ dnode_t *first, *next;
+
+ first = dict_first(dict);
+
+ if (dict->dupes) {
+ while (first && (next = dict_next(dict, first))) {
+ if (dict->compare(first->key, next->key) > 0)
+ return 0;
+ first = next;
+ }
+ } else {
+ while (first && (next = dict_next(dict, first))) {
+ if (dict->compare(first->key, next->key) >= 0)
+ return 0;
+ first = next;
+ }
+ }
+ return 1;
+}
+
+
+/*
+ * This function recursively verifies that the given binary subtree satisfies
+ * three of the red black properties. It checks that every red node has only
+ * black children. It makes sure that each node is either red or black. And it
+ * checks that every path has the same count of black nodes from root to leaf.
+ * It returns the blackheight of the given subtree; this allows blackheights to
+ * be computed recursively and compared for left and right siblings for
+ * mismatches. It does not check for every nil node being black, because there
+ * is only one sentinel nil node. The return value of this function is the
+ * black height of the subtree rooted at the node ``root'', or zero if the
+ * subtree is not red-black.
+ */
+
+static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
+{
+ unsigned height_left, height_right;
+
+ if (root != nil) {
+ height_left = verify_redblack(nil, root->left);
+ height_right = verify_redblack(nil, root->right);
+ if (height_left == 0 || height_right == 0)
+ return 0;
+ if (height_left != height_right)
+ return 0;
+ if (root->color == dnode_red) {
+ if (root->left->color != dnode_black)
+ return 0;
+ if (root->right->color != dnode_black)
+ return 0;
+ return height_left;
+ }
+ if (root->color != dnode_black)
+ return 0;
+ return height_left + 1;
+ }
+ return 1;
+}
+
+/*
+ * Compute the actual count of nodes by traversing the tree and
+ * return it. This could be compared against the stored count to
+ * detect a mismatch.
+ */
+
+static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
+{
+ if (root == nil)
+ return 0;
+ else
+ return 1 + verify_node_count(nil, root->left)
+ + verify_node_count(nil, root->right);
+}
+
+/*
+ * Verify that the tree contains the given node. This is done by
+ * traversing all of the nodes and comparing their pointers to the
+ * given pointer. Returns 1 if the node is found, otherwise
+ * returns zero. It is intended for debugging purposes.
+ */
+
+static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
+{
+ if (root != nil) {
+ return root == node
+ || verify_dict_has_node(nil, root->left, node)
+ || verify_dict_has_node(nil, root->right, node);
+ }
+ return 0;
+}
+
+
+/*
+ * Dynamically allocate and initialize a dictionary object.
+ */
+
+dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
+{
+ dict_t *new = malloc(sizeof *new);
+
+ if (new) {
+ new->compare = comp;
+ new->allocnode = dnode_alloc;
+ new->freenode = dnode_free;
+ new->context = NULL;
+ new->nodecount = 0;
+ new->maxcount = maxcount;
+ new->nilnode.left = &new->nilnode;
+ new->nilnode.right = &new->nilnode;
+ new->nilnode.parent = &new->nilnode;
+ new->nilnode.color = dnode_black;
+ new->dupes = 0;
+ }
+ return new;
+}
+
+/*
+ * Select a different set of node allocator routines.
+ */
+
+void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
+ dnode_free_t fr, void *context)
+{
+ assert (dict_count(dict) == 0);
+ assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
+
+ dict->allocnode = al ? al : dnode_alloc;
+ dict->freenode = fr ? fr : dnode_free;
+ dict->context = context;
+}
+
+/*
+ * Free a dynamically allocated dictionary object. Removing the nodes
+ * from the tree before deleting it is required.
+ */
+
+void dict_destroy(dict_t *dict)
+{
+ assert (dict_isempty(dict));
+ free(dict);
+}
+
+/*
+ * Free all the nodes in the dictionary by using the dictionary's
+ * installed free routine. The dictionary is emptied.
+ */
+
+void dict_free_nodes(dict_t *dict)
+{
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
+ free_nodes(dict, root, nil);
+ dict->nodecount = 0;
+ dict->nilnode.left = &dict->nilnode;
+ dict->nilnode.right = &dict->nilnode;
+}
+
+/*
+ * Obsolescent function, equivalent to dict_free_nodes
+ */
+
+void dict_free(dict_t *dict)
+{
+#ifdef KAZLIB_OBSOLESCENT_DEBUG
+ assert ("call to obsolescent function dict_free()" && 0);
+#endif
+ dict_free_nodes(dict);
+}
+
+/*
+ * Initialize a user-supplied dictionary object.
+ */
+
+dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
+{
+ dict->compare = comp;
+ dict->allocnode = dnode_alloc;
+ dict->freenode = dnode_free;
+ dict->context = NULL;
+ dict->nodecount = 0;
+ dict->maxcount = maxcount;
+ dict->nilnode.left = &dict->nilnode;
+ dict->nilnode.right = &dict->nilnode;
+ dict->nilnode.parent = &dict->nilnode;
+ dict->nilnode.color = dnode_black;
+ dict->dupes = 0;
+ return dict;
+}
+
+/*
+ * Initialize a dictionary in the likeness of another dictionary
+ */
+
+void dict_init_like(dict_t *dict, const dict_t *template)
+{
+ dict->compare = template->compare;
+ dict->allocnode = template->allocnode;
+ dict->freenode = template->freenode;
+ dict->context = template->context;
+ dict->nodecount = 0;
+ dict->maxcount = template->maxcount;
+ dict->nilnode.left = &dict->nilnode;
+ dict->nilnode.right = &dict->nilnode;
+ dict->nilnode.parent = &dict->nilnode;
+ dict->nilnode.color = dnode_black;
+ dict->dupes = template->dupes;
+
+ assert (dict_similar(dict, template));
+}
+
+/*
+ * Remove all nodes from the dictionary (without freeing them in any way).
+ */
+
+static void dict_clear(dict_t *dict)
+{
+ dict->nodecount = 0;
+ dict->nilnode.left = &dict->nilnode;
+ dict->nilnode.right = &dict->nilnode;
+ dict->nilnode.parent = &dict->nilnode;
+ assert (dict->nilnode.color == dnode_black);
+}
+
+
+/*
+ * Verify the integrity of the dictionary structure. This is provided for
+ * debugging purposes, and should be placed in assert statements. Just because
+ * this function succeeds doesn't mean that the tree is not corrupt. Certain
+ * corruptions in the tree may simply cause undefined behavior.
+ */
+
+int dict_verify(dict_t *dict)
+{
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
+
+ /* check that the sentinel node and root node are black */
+ if (root->color != dnode_black)
+ return 0;
+ if (nil->color != dnode_black)
+ return 0;
+ if (nil->right != nil)
+ return 0;
+ /* nil->left is the root node; check that its parent pointer is nil */
+ if (nil->left->parent != nil)
+ return 0;
+ /* perform a weak test that the tree is a binary search tree */
+ if (!verify_bintree(dict))
+ return 0;
+ /* verify that the tree is a red-black tree */
+ if (!verify_redblack(nil, root))
+ return 0;
+ if (verify_node_count(nil, root) != dict_count(dict))
+ return 0;
+ return 1;
+}
+
+/*
+ * Determine whether two dictionaries are similar: have the same comparison and
+ * allocator functions, and same status as to whether duplicates are allowed.
+ */
+
+int dict_similar(const dict_t *left, const dict_t *right)
+{
+ if (left->compare != right->compare)
+ return 0;
+
+ if (left->allocnode != right->allocnode)
+ return 0;
+
+ if (left->freenode != right->freenode)
+ return 0;
+
+ if (left->context != right->context)
+ return 0;
+
+ if (left->dupes != right->dupes)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Locate a node in the dictionary having the given key.
+ * If the node is not found, a null a pointer is returned (rather than
+ * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
+ * located node is returned.
+ */
+
+dnode_t *dict_lookup(dict_t *dict, const void *key)
+{
+ dnode_t *root = dict_root(dict);
+ dnode_t *nil = dict_nil(dict);
+ dnode_t *saved;
+ int result;
+
+ /* simple binary search adapted for trees that contain duplicate keys */
+
+ while (root != nil) {
+ result = dict->compare(key, root->key);
+ if (result < 0)
+ root = root->left;
+ else if (result > 0)
+ root = root->right;
+ else {
+ if (!dict->dupes) { /* no duplicates, return match */
+ return root;
+ } else { /* could be dupes, find leftmost one */
+ do {
+ saved = root;
+ root = root->left;
+ while (root != nil && dict->compare(key, root->key))
+ root = root->right;
+ } while (root != nil);
+ return saved;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Look for the node corresponding to the lowest key that is equal to or
+ * greater than the given key. If there is no such node, return null.
+ */
+
+dnode_t *dict_lower_bound(dict_t *dict, const void *key)
+{
+ dnode_t *root = dict_root(dict);
+ dnode_t *nil = dict_nil(dict);
+ dnode_t *tentative = 0;
+
+ while (root != nil) {
+ int result = dict->compare(key, root->key);
+
+ if (result > 0) {
+ root = root->right;
+ } else if (result < 0) {
+ tentative = root;
+ root = root->left;
+ } else {
+ if (!dict->dupes) {
+ return root;
+ } else {
+ tentative = root;
+ root = root->left;
+ }
+ }
+ }
+
+ return tentative;
+}
+
+/*
+ * Look for the node corresponding to the greatest key that is equal to or
+ * lower than the given key. If there is no such node, return null.
+ */
+
+dnode_t *dict_upper_bound(dict_t *dict, const void *key)
+{
+ dnode_t *root = dict_root(dict);
+ dnode_t *nil = dict_nil(dict);
+ dnode_t *tentative = 0;
+
+ while (root != nil) {
+ int result = dict->compare(key, root->key);
+
+ if (result < 0) {
+ root = root->left;
+ } else if (result > 0) {
+ tentative = root;
+ root = root->right;
+ } else {
+ if (!dict->dupes) {
+ return root;
+ } else {
+ tentative = root;
+ root = root->right;
+ }
+ }
+ }
+
+ return tentative;
+}
+
+/*
+ * Insert a node into the dictionary. The node should have been
+ * initialized with a data field. All other fields are ignored.
+ * The behavior is undefined if the user attempts to insert into
+ * a dictionary that is already full (for which the dict_isfull()
+ * function returns true).
+ */
+
+void dict_insert(dict_t *dict, dnode_t *node, const void *key)
+{
+ dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
+ dnode_t *parent = nil, *uncle, *grandpa;
+ int result = -1;
+
+ node->key = key;
+
+ assert (!dict_isfull(dict));
+ assert (!dict_contains(dict, node));
+ assert (!dnode_is_in_a_dict(node));
+
+ /* basic binary tree insert */
+
+ while (where != nil) {
+ parent = where;
+ result = dict->compare(key, where->key);
+ /* trap attempts at duplicate key insertion unless it's explicitly allowed */
+ assert (dict->dupes || result != 0);
+ if (result < 0)
+ where = where->left;
+ else
+ where = where->right;
+ }
+
+ assert (where == nil);
+
+ if (result < 0)
+ parent->left = node;
+ else
+ parent->right = node;
+
+ node->parent = parent;
+ node->left = nil;
+ node->right = nil;
+
+ dict->nodecount++;
+
+ /* red black adjustments */
+
+ node->color = dnode_red;
+
+ while (parent->color == dnode_red) {
+ grandpa = parent->parent;
+ if (parent == grandpa->left) {
+ uncle = grandpa->right;
+ if (uncle->color == dnode_red) { /* red parent, red uncle */
+ parent->color = dnode_black;
+ uncle->color = dnode_black;
+ grandpa->color = dnode_red;
+ node = grandpa;
+ parent = grandpa->parent;
+ } else { /* red parent, black uncle */
+ if (node == parent->right) {
+ rotate_left(parent);
+ parent = node;
+ assert (grandpa == parent->parent);
+ /* rotation between parent and child preserves grandpa */
+ }
+ parent->color = dnode_black;
+ grandpa->color = dnode_red;
+ rotate_right(grandpa);
+ break;
+ }
+ } else { /* symmetric cases: parent == parent->parent->right */
+ uncle = grandpa->left;
+ if (uncle->color == dnode_red) {
+ parent->color = dnode_black;
+ uncle->color = dnode_black;
+ grandpa->color = dnode_red;
+ node = grandpa;
+ parent = grandpa->parent;
+ } else {
+ if (node == parent->left) {
+ rotate_right(parent);
+ parent = node;
+ assert (grandpa == parent->parent);
+ }
+ parent->color = dnode_black;
+ grandpa->color = dnode_red;
+ rotate_left(grandpa);
+ break;
+ }
+ }
+ }
+
+ dict_root(dict)->color = dnode_black;
+
+ assert (dict_verify(dict));
+}
+
+/*
+ * Delete the given node from the dictionary. If the given node does not belong
+ * to the given dictionary, undefined behavior results. A pointer to the
+ * deleted node is returned.
+ */
+
+dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
+{
+ dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
+
+ /* basic deletion */
+
+ assert (!dict_isempty(dict));
+ assert (dict_contains(dict, delete));
+
+ /*
+ * If the node being deleted has two children, then we replace it with its
+ * successor (i.e. the leftmost node in the right subtree.) By doing this,
+ * we avoid the traditional algorithm under which the successor's key and
+ * value *only* move to the deleted node and the successor is spliced out
+ * from the tree. We cannot use this approach because the user may hold
+ * pointers to the successor, or nodes may be inextricably tied to some
+ * other structures by way of embedding, etc. So we must splice out the
+ * node we are given, not some other node, and must not move contents from
+ * one node to another behind the user's back.
+ */
+
+ if (delete->left != nil && delete->right != nil) {
+ dnode_t *next = dict_next(dict, delete);
+ dnode_t *nextparent = next->parent;
+ dnode_color_t nextcolor = next->color;
+
+ assert (next != nil);
+ assert (next->parent != nil);
+ assert (next->left == nil);
+
+ /*
+ * First, splice out the successor from the tree completely, by
+ * moving up its right child into its place.
+ */
+
+ child = next->right;
+ child->parent = nextparent;
+
+ if (nextparent->left == next) {
+ nextparent->left = child;
+ } else {
+ assert (nextparent->right == next);
+ nextparent->right = child;
+ }
+
+ /*
+ * Now that the successor has been extricated from the tree, install it
+ * in place of the node that we want deleted.
+ */
+
+ next->parent = delparent;
+ next->left = delete->left;
+ next->right = delete->right;
+ next->left->parent = next;
+ next->right->parent = next;
+ next->color = delete->color;
+ delete->color = nextcolor;
+
+ if (delparent->left == delete) {
+ delparent->left = next;
+ } else {
+ assert (delparent->right == delete);
+ delparent->right = next;
+ }
+
+ } else {
+ assert (delete != nil);
+ assert (delete->left == nil || delete->right == nil);
+
+ child = (delete->left != nil) ? delete->left : delete->right;
+
+ child->parent = delparent = delete->parent;
+
+ if (delete == delparent->left) {
+ delparent->left = child;
+ } else {
+ assert (delete == delparent->right);
+ delparent->right = child;
+ }
+ }
+
+ delete->parent = NULL;
+ delete->right = NULL;
+ delete->left = NULL;
+
+ dict->nodecount--;
+
+ assert (verify_bintree(dict));
+
+ /* red-black adjustments */
+
+ if (delete->color == dnode_black) {
+ dnode_t *parent, *sister;
+
+ dict_root(dict)->color = dnode_red;
+
+ while (child->color == dnode_black) {
+ parent = child->parent;
+ if (child == parent->left) {
+ sister = parent->right;
+ assert (sister != nil);
+ if (sister->color == dnode_red) {
+ sister->color = dnode_black;
+ parent->color = dnode_red;
+ rotate_left(parent);
+ sister = parent->right;
+ assert (sister != nil);
+ }
+ if (sister->left->color == dnode_black
+ && sister->right->color == dnode_black) {
+ sister->color = dnode_red;
+ child = parent;
+ } else {
+ if (sister->right->color == dnode_black) {
+ assert (sister->left->color == dnode_red);
+ sister->left->color = dnode_black;
+ sister->color = dnode_red;
+ rotate_right(sister);
+ sister = parent->right;
+ assert (sister != nil);
+ }
+ sister->color = parent->color;
+ sister->right->color = dnode_black;
+ parent->color = dnode_black;
+ rotate_left(parent);
+ break;
+ }
+ } else { /* symmetric case: child == child->parent->right */
+ assert (child == parent->right);
+ sister = parent->left;
+ assert (sister != nil);
+ if (sister->color == dnode_red) {
+ sister->color = dnode_black;
+ parent->color = dnode_red;
+ rotate_right(parent);
+ sister = parent->left;
+ assert (sister != nil);
+ }
+ if (sister->right->color == dnode_black
+ && sister->left->color == dnode_black) {
+ sister->color = dnode_red;
+ child = parent;
+ } else {
+ if (sister->left->color == dnode_black) {
+ assert (sister->right->color == dnode_red);
+ sister->right->color = dnode_black;
+ sister->color = dnode_red;
+ rotate_left(sister);
+ sister = parent->left;
+ assert (sister != nil);
+ }
+ sister->color = parent->color;
+ sister->left->color = dnode_black;
+ parent->color = dnode_black;
+ rotate_right(parent);
+ break;
+ }
+ }
+ }
+
+ child->color = dnode_black;
+ dict_root(dict)->color = dnode_black;
+ }
+
+ assert (dict_verify(dict));
+
+ return delete;
+}
+
+/*
+ * Allocate a node using the dictionary's allocator routine, give it
+ * the data item.
+ */
+
+int dict_alloc_insert(dict_t *dict, const void *key, void *data)
+{
+ dnode_t *node = dict->allocnode(dict->context);
+
+ if (node) {
+ dnode_init(node, data);
+ dict_insert(dict, node, key);
+ return 1;
+ }
+ return 0;
+}
+
+void dict_delete_free(dict_t *dict, dnode_t *node)
+{
+ dict_delete(dict, node);
+ dict->freenode(node, dict->context);
+}
+
+/*
+ * Return the node with the lowest (leftmost) key. If the dictionary is empty
+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
+ */
+
+dnode_t *dict_first(dict_t *dict)
+{
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
+
+ if (root != nil)
+ while ((left = root->left) != nil)
+ root = left;
+
+ return (root == nil) ? NULL : root;
+}
+
+/*
+ * Return the node with the highest (rightmost) key. If the dictionary is empty
+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
+ */
+
+dnode_t *dict_last(dict_t *dict)
+{
+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
+
+ if (root != nil)
+ while ((right = root->right) != nil)
+ root = right;
+
+ return (root == nil) ? NULL : root;
+}
+
+/*
+ * Return the given node's successor node---the node which has the
+ * next key in the the left to right ordering. If the node has
+ * no successor, a null pointer is returned rather than a pointer to
+ * the nil node.
+ */
+
+dnode_t *dict_next(dict_t *dict, dnode_t *curr)
+{
+ dnode_t *nil = dict_nil(dict), *parent, *left;
+
+ if (curr->right != nil) {
+ curr = curr->right;
+ while ((left = curr->left) != nil)
+ curr = left;
+ return curr;
+ }
+
+ parent = curr->parent;
+
+ while (parent != nil && curr == parent->right) {
+ curr = parent;
+ parent = curr->parent;
+ }
+
+ return (parent == nil) ? NULL : parent;
+}
+
+/*
+ * Return the given node's predecessor, in the key order.
+ * The nil sentinel node is returned if there is no predecessor.
+ */
+
+dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
+{
+ dnode_t *nil = dict_nil(dict), *parent, *right;
+
+ if (curr->left != nil) {
+ curr = curr->left;
+ while ((right = curr->right) != nil)
+ curr = right;
+ return curr;
+ }
+
+ parent = curr->parent;
+
+ while (parent != nil && curr == parent->left) {
+ curr = parent;
+ parent = curr->parent;
+ }
+
+ return (parent == nil) ? NULL : parent;
+}
+
+void dict_allow_dupes(dict_t *dict)
+{
+ dict->dupes = 1;
+}
+
+#undef dict_count
+#undef dict_isempty
+#undef dict_isfull
+#undef dnode_get
+#undef dnode_put
+#undef dnode_getkey
+
+dictcount_t dict_count(dict_t *dict)
+{
+ return dict->nodecount;
+}
+
+int dict_isempty(dict_t *dict)
+{
+ return dict->nodecount == 0;
+}
+
+int dict_isfull(dict_t *dict)
+{
+ return dict->nodecount == dict->maxcount;
+}
+
+int dict_contains(dict_t *dict, dnode_t *node)
+{
+ return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
+}
+
+static dnode_t *dnode_alloc(void *context)
+{
+ return malloc(sizeof *dnode_alloc(NULL));
+}
+
+static void dnode_free(dnode_t *node, void *context)
+{
+ free(node);
+}
+
+dnode_t *dnode_create(void *data)
+{
+ dnode_t *new = malloc(sizeof *new);
+ if (new) {
+ new->data = data;
+ new->parent = NULL;
+ new->left = NULL;
+ new->right = NULL;
+ }
+ return new;
+}
+
+dnode_t *dnode_init(dnode_t *dnode, void *data)
+{
+ dnode->data = data;
+ dnode->parent = NULL;
+ dnode->left = NULL;
+ dnode->right = NULL;
+ return dnode;
+}
+
+void dnode_destroy(dnode_t *dnode)
+{
+ assert (!dnode_is_in_a_dict(dnode));
+ free(dnode);
+}
+
+void *dnode_get(dnode_t *dnode)
+{
+ return dnode->data;
+}
+
+const void *dnode_getkey(dnode_t *dnode)
+{
+ return dnode->key;
+}
+
+void dnode_put(dnode_t *dnode, void *data)
+{
+ dnode->data = data;
+}
+
+int dnode_is_in_a_dict(dnode_t *dnode)
+{
+ return (dnode->parent && dnode->left && dnode->right);
+}
+
+void dict_process(dict_t *dict, void *context, dnode_process_t function)
+{
+ dnode_t *node = dict_first(dict), *next;
+
+ while (node != NULL) {
+ /* check for callback function deleting */
+ /* the next node from under us */
+ assert (dict_contains(dict, node));
+ next = dict_next(dict, node);
+ function(dict, node, context);
+ node = next;
+ }
+}
+
+static void load_begin_internal(dict_load_t *load, dict_t *dict)
+{
+ load->dictptr = dict;
+ load->nilnode.left = &load->nilnode;
+ load->nilnode.right = &load->nilnode;
+}
+
+void dict_load_begin(dict_load_t *load, dict_t *dict)
+{
+ assert (dict_isempty(dict));
+ load_begin_internal(load, dict);
+}
+
+void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
+{
+ dict_t *dict = load->dictptr;
+ dnode_t *nil = &load->nilnode;
+
+ assert (!dnode_is_in_a_dict(newnode));
+ assert (dict->nodecount < dict->maxcount);
+
+ #ifndef NDEBUG
+ if (dict->nodecount > 0) {
+ if (dict->dupes)
+ assert (dict->compare(nil->left->key, key) <= 0);
+ else
+ assert (dict->compare(nil->left->key, key) < 0);
+ }
+ #endif
+
+ newnode->key = key;
+ nil->right->left = newnode;
+ nil->right = newnode;
+ newnode->left = nil;
+ dict->nodecount++;
+}
+
+void dict_load_end(dict_load_t *load)
+{
+ dict_t *dict = load->dictptr;
+ dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
+ dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
+ dnode_t *complete = 0;
+ dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
+ dictcount_t botrowcount;
+ unsigned baselevel = 0, level = 0, i;
+
+ assert (dnode_red == 0 && dnode_black == 1);
+
+ while (fullcount >= nodecount && fullcount)
+ fullcount >>= 1;
+
+ botrowcount = nodecount - fullcount;
+
+ for (curr = loadnil->left; curr != loadnil; curr = next) {
+ next = curr->left;
+
+ if (complete == NULL && botrowcount-- == 0) {
+ assert (baselevel == 0);
+ assert (level == 0);
+ baselevel = level = 1;
+ complete = tree[0];
+
+ if (complete != 0) {
+ tree[0] = 0;
+ complete->right = dictnil;
+ while (tree[level] != 0) {
+ tree[level]->right = complete;
+ complete->parent = tree[level];
+ complete = tree[level];
+ tree[level++] = 0;
+ }
+ }
+ }
+
+ if (complete == NULL) {
+ curr->left = dictnil;
+ curr->right = dictnil;
+ curr->color = level % 2;
+ complete = curr;
+
+ assert (level == baselevel);
+ while (tree[level] != 0) {
+ tree[level]->right = complete;
+ complete->parent = tree[level];
+ complete = tree[level];
+ tree[level++] = 0;
+ }
+ } else {
+ curr->left = complete;
+ curr->color = (level + 1) % 2;
+ complete->parent = curr;
+ tree[level] = curr;
+ complete = 0;
+ level = baselevel;
+ }
+ }
+
+ if (complete == NULL)
+ complete = dictnil;
+
+ for (i = 0; i < DICT_DEPTH_MAX; i++) {
+ if (tree[i] != 0) {
+ tree[i]->right = complete;
+ complete->parent = tree[i];
+ complete = tree[i];
+ }
+ }
+
+ dictnil->color = dnode_black;
+ dictnil->right = dictnil;
+ complete->parent = dictnil;
+ complete->color = dnode_black;
+ dict_root(dict) = complete;
+
+ assert (dict_verify(dict));
+}
+
+void dict_merge(dict_t *dest, dict_t *source)
+{
+ dict_load_t load;
+ dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
+
+ assert (dict_similar(dest, source));
+
+ if (source == dest)
+ return;
+
+ dest->nodecount = 0;
+ load_begin_internal(&load, dest);
+
+ for (;;) {
+ if (leftnode != NULL && rightnode != NULL) {
+ if (dest->compare(leftnode->key, rightnode->key) < 0)
+ goto copyleft;
+ else
+ goto copyright;
+ } else if (leftnode != NULL) {
+ goto copyleft;
+ } else if (rightnode != NULL) {
+ goto copyright;
+ } else {
+ assert (leftnode == NULL && rightnode == NULL);
+ break;
+ }
+
+ copyleft:
+ {
+ dnode_t *next = dict_next(dest, leftnode);
+ #ifndef NDEBUG
+ leftnode->left = NULL; /* suppress assertion in dict_load_next */
+ #endif
+ dict_load_next(&load, leftnode, leftnode->key);
+ leftnode = next;
+ continue;
+ }
+
+ copyright:
+ {
+ dnode_t *next = dict_next(source, rightnode);
+ #ifndef NDEBUG
+ rightnode->left = NULL;
+ #endif
+ dict_load_next(&load, rightnode, rightnode->key);
+ rightnode = next;
+ continue;
+ }
+ }
+
+ dict_clear(source);
+ dict_load_end(&load);
+}
+
+#ifdef KAZLIB_TEST_MAIN
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+typedef char input_t[256];
+
+static int tokenize(char *string, ...)
+{
+ char **tokptr;
+ va_list arglist;
+ int tokcount = 0;
+
+ va_start(arglist, string);
+ tokptr = va_arg(arglist, char **);
+ while (tokptr) {
+ while (*string && isspace((unsigned char) *string))
+ string++;
+ if (!*string)
+ break;
+ *tokptr = string;
+ while (*string && !isspace((unsigned char) *string))
+ string++;
+ tokptr = va_arg(arglist, char **);
+ tokcount++;
+ if (!*string)
+ break;
+ *string++ = 0;
+ }
+ va_end(arglist);
+
+ return tokcount;
+}
+
+static int comparef(const void *key1, const void *key2)
+{
+ return strcmp(key1, key2);
+}
+
+static char *dupstring(char *str)
+{
+ int sz = strlen(str) + 1;
+ char *new = malloc(sz);
+ if (new)
+ memcpy(new, str, sz);
+ return new;
+}
+
+static dnode_t *new_node(void *c)
+{
+ static dnode_t few[5];
+ static int count;
+
+ if (count < 5)
+ return few + count++;
+
+ return NULL;
+}
+
+static void del_node(dnode_t *n, void *c)
+{
+}
+
+static int prompt = 0;
+
+static void construct(dict_t *d)
+{
+ input_t in;
+ int done = 0;
+ dict_load_t dl;
+ dnode_t *dn;
+ char *tok1, *tok2, *val;
+ const char *key;
+ char *help =
+ "p turn prompt on\n"
+ "q finish construction\n"
+ "a <key> <val> add new entry\n";
+
+ if (!dict_isempty(d))
+ puts("warning: dictionary not empty!");
+
+ dict_load_begin(&dl, d);
+
+ while (!done) {
+ if (prompt)
+ putchar('>');
+ fflush(stdout);
+
+ if (!fgets(in, sizeof(input_t), stdin))
+ break;
+
+ switch (in[0]) {
+ case '?':
+ puts(help);
+ break;
+ case 'p':
+ prompt = 1;
+ break;
+ case 'q':
+ done = 1;
+ break;
+ case 'a':
+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
+ puts("what?");
+ break;
+ }
+ key = dupstring(tok1);
+ val = dupstring(tok2);
+ dn = dnode_create(val);
+
+ if (!key || !val || !dn) {
+ puts("out of memory");
+ free((void *) key);
+ free(val);
+ if (dn)
+ dnode_destroy(dn);
+ }
+
+ dict_load_next(&dl, dn, key);
+ break;
+ default:
+ putchar('?');
+ putchar('\n');
+ break;
+ }
+ }
+
+ dict_load_end(&dl);
+}
+
+int main(void)
+{
+ input_t in;
+ dict_t darray[10];
+ dict_t *d = &darray[0];
+ dnode_t *dn;
+ int i;
+ char *tok1, *tok2, *val;
+ const char *key;
+
+ char *help =
+ "a <key> <val> add value to dictionary\n"
+ "d <key> delete value from dictionary\n"
+ "l <key> lookup value in dictionary\n"
+ "( <key> lookup lower bound\n"
+ ") <key> lookup upper bound\n"
+ "# <num> switch to alternate dictionary (0-9)\n"
+ "j <num> <num> merge two dictionaries\n"
+ "f free the whole dictionary\n"
+ "k allow duplicate keys\n"
+ "c show number of entries\n"
+ "t dump whole dictionary in sort order\n"
+ "m make dictionary out of sorted items\n"
+ "p turn prompt on\n"
+ "s switch to non-functioning allocator\n"
+ "q quit";
+
+ for (i = 0; i < sizeof darray / sizeof *darray; i++)
+ dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
+
+ for (;;) {
+ if (prompt)
+ putchar('>');
+ fflush(stdout);
+
+ if (!fgets(in, sizeof(input_t), stdin))
+ break;
+
+ switch(in[0]) {
+ case '?':
+ puts(help);
+ break;
+ case 'a':
+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
+ puts("what?");
+ break;
+ }
+ key = dupstring(tok1);
+ val = dupstring(tok2);
+
+ if (!key || !val) {
+ puts("out of memory");
+ free((void *) key);
+ free(val);
+ }
+
+ if (!dict_alloc_insert(d, key, val)) {
+ puts("dict_alloc_insert failed");
+ free((void *) key);
+ free(val);
+ break;
+ }
+ break;
+ case 'd':
+ if (tokenize(in+1, &tok1, (char **) 0) != 1) {
+ puts("what?");
+ break;
+ }
+ dn = dict_lookup(d, tok1);
+ if (!dn) {
+ puts("dict_lookup failed");
+ break;
+ }
+ val = dnode_get(dn);
+ key = dnode_getkey(dn);
+ dict_delete_free(d, dn);
+
+ free(val);
+ free((void *) key);
+ break;
+ case 'f':
+ dict_free(d);
+ break;
+ case 'l':
+ case '(':
+ case ')':
+ if (tokenize(in+1, &tok1, (char **) 0) != 1) {
+ puts("what?");
+ break;
+ }
+ dn = 0;
+ switch (in[0]) {
+ case 'l':
+ dn = dict_lookup(d, tok1);
+ break;
+ case '(':
+ dn = dict_lower_bound(d, tok1);
+ break;
+ case ')':
+ dn = dict_upper_bound(d, tok1);
+ break;
+ }
+ if (!dn) {
+ puts("lookup failed");
+ break;
+ }
+ val = dnode_get(dn);
+ puts(val);
+ break;
+ case 'm':
+ construct(d);
+ break;
+ case 'k':
+ dict_allow_dupes(d);
+ break;
+ case 'c':
+ printf("%lu\n", (unsigned long) dict_count(d));
+ break;
+ case 't':
+ for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
+ printf("%s\t%s\n", (char *) dnode_getkey(dn),
+ (char *) dnode_get(dn));
+ }
+ break;
+ case 'q':
+ exit(0);
+ break;
+ case '\0':
+ break;
+ case 'p':
+ prompt = 1;
+ break;
+ case 's':
+ dict_set_allocator(d, new_node, del_node, NULL);
+ break;
+ case '#':
+ if (tokenize(in+1, &tok1, (char **) 0) != 1) {
+ puts("what?");
+ break;
+ } else {
+ int dictnum = atoi(tok1);
+ if (dictnum < 0 || dictnum > 9) {
+ puts("invalid number");
+ break;
+ }
+ d = &darray[dictnum];
+ }
+ break;
+ case 'j':
+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
+ puts("what?");
+ break;
+ } else {
+ int dict1 = atoi(tok1), dict2 = atoi(tok2);
+ if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
+ puts("invalid number");
+ break;
+ }
+ dict_merge(&darray[dict1], &darray[dict2]);
+ }
+ break;
+ default:
+ putchar('?');
+ putchar('\n');
+ break;
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/isisd/dict.h b/isisd/dict.h
new file mode 100644
index 00000000..2977a90f
--- /dev/null
+++ b/isisd/dict.h
@@ -0,0 +1,144 @@
+/*
+ * Dictionary Abstract Data Type
+ * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
+ *
+ * Free Software License:
+ *
+ * All rights are reserved by the author, with the following exceptions:
+ * Permission is granted to freely reproduce and distribute this software,
+ * possibly in exchange for a fee, provided that this copyright notice appears
+ * intact. Permission is also granted to adapt this software to produce
+ * derivative works, as long as the modified versions carry this copyright
+ * notice and additional notices stating that the work has been modified.
+ * This source code may be translated into executable form and incorporated
+ * into proprietary software; there is no requirement for such software to
+ * contain a copyright notice related to this source.
+ *
+ * $Id: dict.h,v 1.1 2003/12/23 08:09:48 jardin Exp $
+ * $Name: $
+ */
+
+#ifndef DICT_H
+#define DICT_H
+
+#include <limits.h>
+#ifdef KAZLIB_SIDEEFFECT_DEBUG
+#include "sfx.h"
+#endif
+
+/*
+ * Blurb for inclusion into C++ translation units
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned long dictcount_t;
+#define DICTCOUNT_T_MAX ULONG_MAX
+
+/*
+ * The dictionary is implemented as a red-black tree
+ */
+
+typedef enum { dnode_red, dnode_black } dnode_color_t;
+
+typedef struct dnode_t {
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
+ struct dnode_t *dict_left;
+ struct dnode_t *dict_right;
+ struct dnode_t *dict_parent;
+ dnode_color_t dict_color;
+ const void *dict_key;
+ void *dict_data;
+ #else
+ int dict_dummy;
+ #endif
+} dnode_t;
+
+typedef int (*dict_comp_t)(const void *, const void *);
+typedef dnode_t *(*dnode_alloc_t)(void *);
+typedef void (*dnode_free_t)(dnode_t *, void *);
+
+typedef struct dict_t {
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
+ dnode_t dict_nilnode;
+ dictcount_t dict_nodecount;
+ dictcount_t dict_maxcount;
+ dict_comp_t dict_compare;
+ dnode_alloc_t dict_allocnode;
+ dnode_free_t dict_freenode;
+ void *dict_context;
+ int dict_dupes;
+ #else
+ int dict_dummmy;
+ #endif
+} dict_t;
+
+typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
+
+typedef struct dict_load_t {
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
+ dict_t *dict_dictptr;
+ dnode_t dict_nilnode;
+ #else
+ int dict_dummmy;
+ #endif
+} dict_load_t;
+
+extern dict_t *dict_create(dictcount_t, dict_comp_t);
+extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *);
+extern void dict_destroy(dict_t *);
+extern void dict_free_nodes(dict_t *);
+extern void dict_free(dict_t *);
+extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t);
+extern void dict_init_like(dict_t *, const dict_t *);
+extern int dict_verify(dict_t *);
+extern int dict_similar(const dict_t *, const dict_t *);
+extern dnode_t *dict_lookup(dict_t *, const void *);
+extern dnode_t *dict_lower_bound(dict_t *, const void *);
+extern dnode_t *dict_upper_bound(dict_t *, const void *);
+extern void dict_insert(dict_t *, dnode_t *, const void *);
+extern dnode_t *dict_delete(dict_t *, dnode_t *);
+extern int dict_alloc_insert(dict_t *, const void *, void *);
+extern void dict_delete_free(dict_t *, dnode_t *);
+extern dnode_t *dict_first(dict_t *);
+extern dnode_t *dict_last(dict_t *);
+extern dnode_t *dict_next(dict_t *, dnode_t *);
+extern dnode_t *dict_prev(dict_t *, dnode_t *);
+extern dictcount_t dict_count(dict_t *);
+extern int dict_isempty(dict_t *);
+extern int dict_isfull(dict_t *);
+extern int dict_contains(dict_t *, dnode_t *);
+extern void dict_allow_dupes(dict_t *);
+extern int dnode_is_in_a_dict(dnode_t *);
+extern dnode_t *dnode_create(void *);
+extern dnode_t *dnode_init(dnode_t *, void *);
+extern void dnode_destroy(dnode_t *);
+extern void *dnode_get(dnode_t *);
+extern const void *dnode_getkey(dnode_t *);
+extern void dnode_put(dnode_t *, void *);
+extern void dict_process(dict_t *, void *, dnode_process_t);
+extern void dict_load_begin(dict_load_t *, dict_t *);
+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 *);
+
+#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
+#ifdef KAZLIB_SIDEEFFECT_DEBUG
+#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
+#else
+#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount)
+#endif
+#define dict_count(D) ((D)->dict_nodecount)
+#define dict_isempty(D) ((D)->dict_nodecount == 0)
+#define dnode_get(N) ((N)->dict_data)
+#define dnode_getkey(N) ((N)->dict_key)
+#define dnode_put(N, X) ((N)->dict_data = (X))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/isisd/include-netbsd/clnp.h b/isisd/include-netbsd/clnp.h
new file mode 100644
index 00000000..6bc3d257
--- /dev/null
+++ b/isisd/include-netbsd/clnp.h
@@ -0,0 +1,547 @@
+/* $NetBSD: clnp.h,v 1.13 2001/08/20 12:00:54 wiz Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clnp.h 8.2 (Berkeley) 4/16/94
+ */
+
+/***********************************************************
+ Copyright IBM Corporation 1987
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+
+/* should be config option but cpp breaks with too many #defines */
+#define DECBIT
+
+/*
+ * Return true if the mbuf is a cluster mbuf
+ */
+#define IS_CLUSTER(m) ((m)->m_flags & M_EXT)
+
+/*
+ * Move the halfword into the two characters
+ */
+#define HTOC(msb, lsb, hword)\
+ (msb) = (u_char)((hword) >> 8);\
+ (lsb) = (u_char)((hword) & 0xff)
+/*
+ * Move the two charcters into the halfword
+ */
+#define CTOH(msb, lsb, hword)\
+ (hword) = ((msb) << 8) | (lsb)
+
+/*
+ * Return true if the checksum has been set - ie. the checksum is
+ * not zero
+ */
+#define CKSUM_REQUIRED(clnp)\
+ (((clnp)->cnf_cksum_msb != 0) || ((clnp)->cnf_cksum_lsb != 0))
+
+/*
+ * Fixed part of clnp header
+ */
+struct clnp_fixed {
+ u_char cnf_proto_id; /* network layer protocol identifier */
+ u_char cnf_hdr_len; /* length indicator (octets) */
+ u_char cnf_vers; /* version/protocol identifier
+ * extension */
+ u_char cnf_ttl;/* lifetime (500 milliseconds) */
+ u_char cnf_type; /* type code */
+ /* Includes err_ok, more_segs, and seg_ok */
+ u_char cnf_seglen_msb; /* pdu segment length (octets) high
+ * byte */
+ u_char cnf_seglen_lsb; /* pdu segment length (octets) low
+ * byte */
+ u_char cnf_cksum_msb; /* checksum high byte */
+ u_char cnf_cksum_lsb; /* checksum low byte */
+} __attribute__((packed));
+#define CNF_TYPE 0x1f
+#define CNF_ERR_OK 0x20
+#define CNF_MORE_SEGS 0x40
+#define CNF_SEG_OK 0x80
+
+#define CLNP_CKSUM_OFF 0x07 /* offset of checksum */
+
+#define clnl_fixed clnp_fixed
+
+/*
+ * Segmentation part of clnp header
+ */
+struct clnp_segment {
+ u_short cng_id; /* data unit identifier */
+ u_short cng_off;/* segment offset */
+ u_short cng_tot_len; /* total length */
+};
+
+/*
+ * Clnp fragment reassembly structures:
+ *
+ * All packets undergoing reassembly are linked together in
+ * clnp_fragl structures. Each clnp_fragl structure contains a
+ * pointer to the original clnp packet header, as well as a
+ * list of packet fragments. Each packet fragment
+ * is headed by a clnp_frag structure. This structure contains the
+ * offset of the first and last byte of the fragment, as well as
+ * a pointer to the data (an mbuf chain) of the fragment.
+ */
+
+/*
+ * NOTE:
+ * The clnp_frag structure is stored in an mbuf immedately
+ * preceding the fragment data. Since there are words in
+ * this struct, it must be word aligned.
+ *
+ * NOTE:
+ * All the fragment code assumes that the entire clnp header is
+ * contained in the first mbuf.
+ */
+struct clnp_frag {
+ u_int cfr_first; /* offset of first byte of this frag */
+ u_int cfr_last; /* offset of last byte of this frag */
+ u_int cfr_bytes; /* bytes to shave to get to data */
+ struct mbuf *cfr_data; /* ptr to data for this frag */
+ struct clnp_frag *cfr_next; /* next fragment in list */
+};
+
+struct clnp_fragl {
+ struct iso_addr cfl_src;/* source of the pkt */
+ struct iso_addr cfl_dst;/* destination of the pkt */
+ u_short cfl_id; /* id of the pkt */
+ u_char cfl_ttl;/* current ttl of pkt */
+ u_short cfl_last; /* offset of last byte of packet */
+ struct mbuf *cfl_orighdr; /* ptr to original header */
+ struct clnp_frag *cfl_frags; /* linked list of fragments for pkt */
+ struct clnp_fragl *cfl_next; /* next pkt being reassembled */
+};
+
+/*
+ * The following structure is used to index into an options section
+ * of a clnp datagram. These values can be used without worry that
+ * offset or length fields are invalid or too big, etc. That is,
+ * the consistancy of the options will be guaranteed before this
+ * structure is filled in. Any pointer (field ending in p) is
+ * actually the offset from the beginning of the mbuf the option
+ * is contained in. A value of NULL for any pointer
+ * means that the option is not present. The length any option
+ * does not include the option code or option length fields.
+ */
+struct clnp_optidx {
+ u_short cni_securep; /* ptr to start of security option */
+ char cni_secure_len; /* length of entire security option */
+
+ u_short cni_srcrt_s; /* offset of start of src rt option */
+ u_short cni_srcrt_len; /* length of entire src rt option */
+
+ u_short cni_recrtp; /* ptr to beginning of recrt option */
+ char cni_recrt_len; /* length of entire recrt option */
+
+ char cni_priorp; /* ptr to priority option */
+
+ u_short cni_qos_formatp; /* ptr to format of qos
+ * option */
+ char cni_qos_len; /* length of entire qos option */
+
+ u_char cni_er_reason; /* reason from ER pdu option */
+
+ /* ESIS options */
+
+ u_short cni_esct; /* value from ISH ESCT option */
+
+ u_short cni_netmaskp; /* ptr to beginning of netmask option */
+ char cni_netmask_len; /* length of entire netmask
+ * option */
+
+ u_short cni_snpamaskp; /* ptr to start of snpamask option */
+ char cni_snpamask_len; /* length of entire snpamask
+ * option */
+
+};
+
+#define ER_INVALREAS 0xff /* code for invalid ER pdu discard reason */
+
+/* given an mbuf and addr of option, return offset from data of mbuf */
+#define CLNP_OPTTOOFF(m, opt) ((u_short) (opt - mtod(m, caddr_t)))
+
+/* given an mbuf and offset of option, return address of option */
+#define CLNP_OFFTOOPT(m, off) ((caddr_t) (mtod(m, caddr_t) + off))
+
+/* return true iff src route is valid */
+#define CLNPSRCRT_VALID(oidx) ((oidx) && (oidx->cni_srcrt_s))
+
+/* return the offset field of the src rt */
+#define CLNPSRCRT_OFF(oidx, options)\
+ (*((u_char *)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + 1)))
+
+/* return the type field of the src rt */
+#define CLNPSRCRT_TYPE(oidx, options)\
+ ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s))))
+
+/* return the length of the current address */
+#define CLNPSRCRT_CLEN(oidx, options)\
+ ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options) - 1)))
+
+/* return the address of the current address */
+#define CLNPSRCRT_CADDR(oidx, options)\
+ ((caddr_t)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options)))
+
+/*
+ * return true if the src route has run out of routes this is true if the
+ * offset of next route is greater than the end of the rt
+ */
+#define CLNPSRCRT_TERM(oidx, options)\
+ (CLNPSRCRT_OFF(oidx, options) > oidx->cni_srcrt_len)
+
+/*
+ * Options a user can set/get
+ */
+#define CLNPOPT_FLAGS 0x01 /* flags: seg permitted, no er xmit, etc */
+#define CLNPOPT_OPTS 0x02 /* datagram options */
+
+/*
+ * Values for particular datagram options
+ */
+#define CLNPOVAL_PAD 0xcc /* padding */
+#define CLNPOVAL_SECURE 0xc5 /* security */
+#define CLNPOVAL_SRCRT 0xc8 /* source routing */
+#define CLNPOVAL_RECRT 0xcb /* record route */
+#define CLNPOVAL_QOS 0xc3 /* quality of service */
+#define CLNPOVAL_PRIOR 0xcd /* priority */
+#define CLNPOVAL_ERREAS 0xc1 /* ER PDU ONLY: reason for discard */
+
+#define CLNPOVAL_SRCSPEC 0x40 /* source address specific */
+#define CLNPOVAL_DSTSPEC 0x80 /* destination address specific */
+#define CLNPOVAL_GLOBAL 0xc0 /* globally unique */
+
+/* Globally Unique QOS */
+#define CLNPOVAL_SEQUENCING 0x10 /* sequencing preferred */
+#define CLNPOVAL_CONGESTED 0x08 /* congestion experienced */
+#define CLNPOVAL_LOWDELAY 0x04 /* low transit delay */
+
+#define CLNPOVAL_PARTRT 0x00 /* partial source routing */
+#define CLNPOVAL_COMPRT 0x01 /* complete source routing */
+
+/*
+ * Clnp flags used in a control block flags field.
+ * NOTE: these must be out of the range of bits defined in ../net/raw_cb.h
+ */
+#define CLNP_NO_SEG 0x010 /* segmentation not permitted */
+#define CLNP_NO_ER 0x020 /* do not generate ERs */
+#define CLNP_SEND_RAW 0x080 /* send pkt as RAW DT not TP DT */
+#define CLNP_NO_CKSUM 0x100 /* don't use clnp checksum */
+#define CLNP_ECHO 0x200 /* send echo request */
+#define CLNP_NOCACHE 0x400 /* don't store cache information */
+#define CLNP_ECHOR 0x800 /* send echo reply */
+
+/* valid clnp flags */
+#define CLNP_VFLAGS \
+ (CLNP_SEND_RAW|CLNP_NO_SEG|CLNP_NO_ER|CLNP_NO_CKSUM|\
+ CLNP_ECHO|CLNP_NOCACHE|CLNP_ECHOR)
+
+/*
+ * Constants used by clnp
+ */
+#define CLNP_HDR_MIN (sizeof (struct clnp_fixed))
+#define CLNP_HDR_MAX (254)
+#define CLNP_TTL_UNITS 2 /* 500 milliseconds */
+#define CLNP_TTL 15*CLNP_TTL_UNITS /* time to live (seconds) */
+#define ISO8473_V1 0x01
+
+/*
+ * Clnp packet types
+ * In order to test raw clnp and tp/clnp simultaneously, a third type of
+ * packet has been defined: CLNP_RAW. This is done so that the input
+ * routine can switch to the correct input routine (rclnp_input or
+ * tpclnp_input) based on the type field. If clnp had a higher level
+ * protocol field, this would not be necessary.
+ */
+#define CLNP_DT 0x1C /* normal data */
+#define CLNP_ER 0x01 /* error report */
+#define CLNP_RAW 0x1D /* debug only */
+#define CLNP_EC 0x1E /* echo packet */
+#define CLNP_ECR 0x1F /* echo reply */
+
+/*
+ * ER pdu error codes
+ */
+#define GEN_NOREAS 0x00 /* reason not specified */
+#define GEN_PROTOERR 0x01 /* protocol procedure error */
+#define GEN_BADCSUM 0x02 /* incorrect checksum */
+#define GEN_CONGEST 0x03 /* pdu discarded due to congestion */
+#define GEN_HDRSYNTAX 0x04 /* header syntax error */
+#define GEN_SEGNEEDED 0x05 /* need segmentation but not allowed */
+#define GEN_INCOMPLETE 0x06 /* incomplete pdu received */
+#define GEN_DUPOPT 0x07 /* duplicate option */
+
+/* address errors */
+#define ADDR_DESTUNREACH 0x80 /* destination address unreachable */
+#define ADDR_DESTUNKNOWN 0x81 /* destination address unknown */
+
+/* source routing */
+#define SRCRT_UNSPECERR 0x90 /* unspecified src rt error */
+#define SRCRT_SYNTAX 0x91 /* syntax error in src rt field */
+#define SRCRT_UNKNOWNADDR 0x92 /* unknown addr in src rt field */
+#define SRCRT_BADPATH 0x93 /* path not acceptable */
+
+/* lifetime */
+#define TTL_EXPTRANSIT 0xa0 /* lifetime expired during transit */
+#define TTL_EXPREASS 0xa1 /* lifetime expired during reassembly */
+
+/* pdu discarded */
+#define DISC_UNSUPPOPT 0xb0 /* unsupported option not specified? */
+#define DISC_UNSUPPVERS 0xb1 /* unsupported protocol version */
+#define DISC_UNSUPPSECURE 0xb2 /* unsupported security option */
+#define DISC_UNSUPPSRCRT 0xb3 /* unsupported src rt option */
+#define DISC_UNSUPPRECRT 0xb4 /* unsupported rec rt option */
+
+/* reassembly */
+#define REASS_INTERFERE 0xc0 /* reassembly interference */
+#define CLNP_ERRORS 22
+
+
+#ifdef CLNP_ER_CODES
+u_char clnp_er_codes[CLNP_ERRORS] = {
+ GEN_NOREAS, GEN_PROTOERR, GEN_BADCSUM, GEN_CONGEST,
+ GEN_HDRSYNTAX, GEN_SEGNEEDED, GEN_INCOMPLETE, GEN_DUPOPT,
+ ADDR_DESTUNREACH, ADDR_DESTUNKNOWN,
+ SRCRT_UNSPECERR, SRCRT_SYNTAX, SRCRT_UNKNOWNADDR, SRCRT_BADPATH,
+ TTL_EXPTRANSIT, TTL_EXPREASS,
+ DISC_UNSUPPOPT, DISC_UNSUPPVERS, DISC_UNSUPPSECURE,
+ DISC_UNSUPPSRCRT, DISC_UNSUPPRECRT, REASS_INTERFERE
+};
+#endif
+
+#ifdef TROLL
+
+#define TR_DUPEND 0x01 /* duplicate end of fragment */
+#define TR_DUPPKT 0x02 /* duplicate entire packet */
+#define TR_DROPPKT 0x04 /* drop packet on output */
+#define TR_TRIM 0x08 /* trim bytes from packet */
+#define TR_CHANGE 0x10 /* change bytes in packet */
+#define TR_MTU 0x20 /* delta to change device mtu */
+#define TR_CHUCK 0x40 /* drop packet in rclnp_input */
+#define TR_BLAST 0x80 /* force rclnp_output to blast many
+ * packet */
+#define TR_RAWLOOP 0x100 /* make if_loop call clnpintr
+ * directly */
+struct troll {
+ int tr_ops; /* operations to perform */
+ float tr_dup_size; /* % to duplicate */
+ float tr_dup_freq; /* frequency to duplicate packets */
+ float tr_drop_freq; /* frequence to drop packets */
+ int tr_mtu_adj; /* delta to adjust if mtu */
+ int tr_blast_cnt; /* # of pkts to blast out */
+};
+
+#define SN_OUTPUT(clcp, m)\
+ troll_output(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt)
+
+#define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\
+ rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))\
+ - trollctl.tr_mtu_adj)
+
+#ifdef _KERNEL
+extern float troll_random;
+#endif
+
+#else /* NO TROLL */
+
+#define SN_OUTPUT(clcp, m)\
+ (*clcp->clc_ifp->if_output)(clcp->clc_ifp, m, clcp->clc_firsthop, \
+ clcp->clc_rt)
+
+#define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\
+ rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__)))
+
+#endif /* TROLL */
+
+/*
+ * Macro to remove an address from a clnp header
+ */
+#define CLNP_EXTRACT_ADDR(isoa, hoff, hend)\
+ {\
+ isoa.isoa_len = (u_char)*hoff;\
+ if ((((++hoff) + isoa.isoa_len) > hend) ||\
+ (isoa.isoa_len > 20) || (isoa.isoa_len == 0)) {\
+ hoff = (caddr_t)0;\
+ } else {\
+ (void) bcopy(hoff, (caddr_t)isoa.isoa_genaddr, \
+ isoa.isoa_len);\
+ hoff += isoa.isoa_len;\
+ }\
+ }
+
+/*
+ * Macro to insert an address into a clnp header
+ */
+#define CLNP_INSERT_ADDR(hoff, isoa)\
+ *hoff++ = (isoa).isoa_len;\
+ (void) bcopy((caddr_t)((isoa).isoa_genaddr), hoff, (isoa).isoa_len);\
+ hoff += (isoa).isoa_len;
+
+/*
+ * Clnp hdr cache. Whenever a clnp packet is sent, a copy of the
+ * header is made and kept in this cache. In addition to a copy of
+ * the cached clnp hdr, the cache contains
+ * information necessary to determine whether the new packet
+ * to send requires a new header to be built.
+ */
+struct clnp_cache {
+ /* these fields are used to check the validity of the cache */
+ struct iso_addr clc_dst;/* destination of packet */
+ struct mbuf *clc_options; /* ptr to options mbuf */
+ int clc_flags; /* flags passed to clnp_output */
+
+ /* these fields are state that clnp_output requires to finish the pkt */
+ int clc_segoff; /* offset of seg part of header */
+ struct rtentry *clc_rt; /* ptr to rtentry (points into the route
+ * structure) */
+ struct sockaddr *clc_firsthop; /* first hop of packet */
+ struct ifnet *clc_ifp;/* ptr to interface structure */
+ struct iso_ifaddr
+ *clc_ifa;/* ptr to interface address */
+ struct mbuf *clc_hdr;/* cached pkt hdr (finally)! */
+};
+
+#ifdef _KERNEL
+struct iso_addr;
+struct sockaddr_iso;
+struct mbuf;
+struct clnp_segment;
+struct sockaddr;
+struct rt_entry;
+struct clnp_fragl;
+struct clnp_optidx;
+struct isopcb;
+struct snpa_hdr;
+struct iso_ifaddr;
+struct route_iso;
+
+/* clnp_debug.c */
+char *clnp_hexp __P((char *, int, char *));
+char *clnp_iso_addrp __P((struct iso_addr *));
+char *clnp_saddr_isop __P((struct sockaddr_iso *));
+
+/* clnp_er.c */
+void clnp_er_input __P((struct mbuf *, struct iso_addr *, u_int));
+void clnp_discard __P((struct mbuf *, u_int));
+void clnp_emit_er __P((struct mbuf *, u_int));
+int clnp_er_index __P((u_int));
+
+int clnp_fragment __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+ int, int, int, struct rtentry *));
+struct mbuf *clnp_reass __P((struct mbuf *, struct iso_addr *,
+ struct iso_addr *, struct clnp_segment *));
+int clnp_newpkt __P((struct mbuf *, struct iso_addr *, struct iso_addr *,
+ struct clnp_segment *));
+void clnp_insert_frag __P((struct clnp_fragl *, struct mbuf *,
+ struct clnp_segment *));
+struct mbuf *clnp_comp_pdu __P((struct clnp_fragl *));
+#ifdef TROLL
+float troll_random __P((void));
+int troll_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *));
+#endif
+
+/* clnp_input.c */
+void clnp_init __P((void));
+void clnlintr __P((void));
+void clnp_input __P((struct mbuf *, ...));
+
+/* clnp_options.c */
+void clnp_update_srcrt __P((struct mbuf *, struct clnp_optidx *));
+void clnp_dooptions __P((struct mbuf *, struct clnp_optidx *, struct ifnet *,
+ struct iso_addr *));
+int clnp_set_opts __P((struct mbuf **, struct mbuf **));
+int clnp_opt_sanity __P((struct mbuf *, caddr_t, int, struct clnp_optidx *));
+
+/* clnp_output.c */
+int clnp_output __P((struct mbuf *, ...));
+void clnp_ctloutput __P((void));
+
+/* clnp_raw.c */
+void rclnp_input __P((struct mbuf *, ...));
+int rclnp_output __P((struct mbuf *, ...));
+int rclnp_ctloutput __P((int, struct socket *, int, int, struct mbuf **));
+int clnp_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *,
+ struct mbuf *, struct proc *));
+
+/* clnp_subr.c */
+struct mbuf *clnp_data_ck __P((struct mbuf *, int));
+caddr_t clnp_extract_addr __P((caddr_t, int, struct iso_addr *,
+ struct iso_addr *));
+int clnp_ours __P((struct iso_addr *));
+void clnp_forward __P((struct mbuf *, int, struct iso_addr *,
+ struct clnp_optidx *, int, struct snpa_hdr *));
+caddr_t clnp_insert_addr __P((caddr_t, struct iso_addr *, struct iso_addr *));
+int clnp_route __P((struct iso_addr *, struct route_iso *, int,
+ struct sockaddr **, struct iso_ifaddr **));
+int clnp_srcroute __P((struct mbuf *, struct clnp_optidx *, struct route_iso *,
+ struct sockaddr **, struct iso_ifaddr **,
+ struct iso_addr *));
+int clnp_echoreply __P((struct mbuf *, int, struct sockaddr_iso *,
+ struct sockaddr_iso *, struct clnp_optidx *));
+int clnp_badmtu __P((struct ifnet *, struct rtentry *, int, char *));
+void clnp_ypocb __P((caddr_t, caddr_t, u_int));
+
+/* clnp_timer.c */
+struct clnp_fragl *clnp_freefrags __P((struct clnp_fragl *));
+void clnp_slowtimo __P((void));
+void clnp_drain __P((void));
+
+#ifdef TROLL
+struct troll trollctl;
+#endif /* TROLL */
+
+#endif /* _KERNEL */
diff --git a/isisd/include-netbsd/esis.h b/isisd/include-netbsd/esis.h
new file mode 100644
index 00000000..ded864e6
--- /dev/null
+++ b/isisd/include-netbsd/esis.h
@@ -0,0 +1,146 @@
+/* $NetBSD: esis.h,v 1.11 1997/11/03 15:01:19 is Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)esis.h 8.1 (Berkeley) 6/10/93
+ */
+
+/***********************************************************
+ Copyright IBM Corporation 1987
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+
+#include <machine/endian.h>
+
+#define SNPAC_AGE 60 /* seconds */
+#define ESIS_CONFIG 60 /* seconds */
+#define ESIS_HT (ESIS_CONFIG * 2)
+
+/*
+ * Fixed part of an ESIS header
+ */
+struct esis_fixed {
+ u_char esis_proto_id; /* network layer protocol identifier */
+ u_char esis_hdr_len; /* length indicator (octets) */
+ u_char esis_vers; /* version/protocol identifier
+ * extension */
+ u_char esis_res1; /* reserved */
+ u_char esis_type; /* type code */
+ /* technically, type should be &='d 0x1f */
+#define ESIS_ESH 0x02 /* End System Hello */
+#define ESIS_ISH 0x04 /* Intermediate System Hello */
+#define ESIS_RD 0x06 /* Redirect */
+ u_char esis_ht_msb; /* holding time (seconds) high byte */
+ u_char esis_ht_lsb; /* holding time (seconds) low byte */
+ u_char esis_cksum_msb; /* checksum high byte */
+ u_char esis_cksum_lsb; /* checksum low byte */
+} __attribute__((packed));
+/*
+ * Values for ESIS datagram options
+ */
+#define ESISOVAL_NETMASK 0xe1 /* address mask option, RD PDU only */
+#define ESISOVAL_SNPAMASK 0xe2 /* snpa mask option, RD PDU only */
+#define ESISOVAL_ESCT 0xc6 /* end system conf. timer, ISH PDU
+ * only */
+
+
+#define ESIS_CKSUM_OFF 0x07
+#define ESIS_CKSUM_REQUIRED(pdu)\
+ ((pdu->esis_cksum_msb != 0) || (pdu->esis_cksum_lsb != 0))
+
+#define ESIS_VERSION 1
+
+struct esis_stat {
+ u_short es_nomem; /* insufficient memory to send hello */
+ u_short es_badcsum; /* incorrect checksum */
+ u_short es_badvers; /* incorrect version number */
+ u_short es_badtype; /* unknown pdu type field */
+ u_short es_toosmall; /* packet too small */
+ u_short es_eshsent; /* ESH sent */
+ u_short es_eshrcvd; /* ESH rcvd */
+ u_short es_ishsent; /* ISH sent */
+ u_short es_ishrcvd; /* ISH rcvd */
+ u_short es_rdsent; /* RD sent */
+ u_short es_rdrcvd; /* RD rcvd */
+};
+
+#ifdef _KERNEL
+struct esis_stat esis_stat;
+struct socket;
+struct mbuf;
+struct snpa_hdr;
+struct clnp_optidx;
+struct iso_addr;
+struct rtentry;
+struct sockaddr_dl;
+
+void esis_init __P((void));
+int esis_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *,
+ struct mbuf *, struct proc *));
+void esis_input __P((struct mbuf *, ...));
+void esis_rdoutput __P((struct snpa_hdr *, struct mbuf *, struct clnp_optidx *,
+ struct iso_addr *, struct rtentry *));
+int esis_insert_addr __P((caddr_t *, int *, struct iso_addr *, struct mbuf *,
+ int));
+void esis_eshinput __P((struct mbuf *, struct snpa_hdr *));
+void esis_ishinput __P((struct mbuf *, struct snpa_hdr *));
+void esis_rdinput __P((struct mbuf *, struct snpa_hdr *));
+void esis_config __P((void *));
+void esis_shoutput __P((struct ifnet *, int, int, caddr_t, int,
+ struct iso_addr *));
+void isis_input __P((struct mbuf *, ...));
+int isis_output __P((struct mbuf *, ...));
+void *esis_ctlinput __P((int, struct sockaddr *, void *));
+#endif /* _KERNEL */
diff --git a/isisd/include-netbsd/iso.h b/isisd/include-netbsd/iso.h
new file mode 100644
index 00000000..714b42d6
--- /dev/null
+++ b/isisd/include-netbsd/iso.h
@@ -0,0 +1,208 @@
+/* $NetBSD: iso.h,v 1.13 2000/07/28 12:13:34 kleink Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)iso.h 8.1 (Berkeley) 6/10/93
+ */
+
+/***********************************************************
+ Copyright IBM Corporation 1987
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+
+#ifndef _NETISO_ISO_H_
+#define _NETISO_ISO_H_
+
+#if 0
+#include <sys/ansi.h>
+#endif
+
+#if 0
+#ifndef sa_family_t
+typedef __sa_family_t sa_family_t;
+#define sa_family_t __sa_family_t
+#endif
+#endif
+/*
+ * Return true if this is a multicast address
+ * This assumes that the bit transmission is lsb first. This
+ * assumption is valid for 802.3 but not 802.5. There is a
+ * kludge to get around this for 802.5 -- see if_lan.c
+ * where subnetwork header is setup.
+ */
+#define IS_MULTICAST(snpa)\
+ ((snpa)[0] & 0x01)
+
+/*
+ * Protocols
+ */
+#define ISOPROTO_TCP 6 /* IETF experiment */
+#define ISOPROTO_UDP 17 /* IETF experiment */
+#define ISOPROTO_TP0 25 /* connection oriented transport protocol */
+#define ISOPROTO_TP1 26 /* not implemented */
+#define ISOPROTO_TP2 27 /* not implemented */
+#define ISOPROTO_TP3 28 /* not implemented */
+#define ISOPROTO_TP4 29 /* connection oriented transport protocol */
+#define ISOPROTO_TP ISOPROTO_TP4 /* tp-4 with negotiation */
+#define ISOPROTO_CLTP 30 /* connectionless transport (not yet impl.) */
+#define ISOPROTO_CLNP 31 /* connectionless internetworking protocol */
+#define ISOPROTO_X25 32 /* cons */
+#define ISOPROTO_INACT_NL 33 /* inactive network layer! */
+#define ISOPROTO_ESIS 34 /* ES-IS protocol */
+#define ISOPROTO_INTRAISIS 35 /* IS-IS protocol */
+#define ISOPROTO_IDRP 36 /* Interdomain Routing Protocol */
+
+#define ISOPROTO_RAW 255 /* raw clnp */
+#define ISOPROTO_MAX 256
+
+#define ISO_PORT_RESERVED 1024
+#define ISO_PORT_USERRESERVED 5000
+/*
+ * Port/socket numbers: standard network functions
+ * NOT PRESENTLY USED
+ */
+#define ISO_PORT_MAINT 501
+#define ISO_PORT_ECHO 507
+#define ISO_PORT_DISCARD 509
+#define ISO_PORT_SYSTAT 511
+#define ISO_PORT_NETSTAT 515
+/*
+ * Port/socket numbers: non-standard application functions
+ */
+#define ISO_PORT_LOGIN 513
+/*
+ * Port/socket numbers: public use
+ */
+#define ISO_PORT_PUBLIC 1024 /* high bit set --> public */
+
+/*
+ * Network layer protocol identifiers
+ */
+#define ISO8473_CLNP 0x81
+#define ISO9542_ESIS 0x82
+#define ISO9542X25_ESIS 0x8a
+#define ISO10589_ISIS 0x83
+#define ISO8878A_CONS 0x84
+#define ISO10747_IDRP 0x85
+
+
+#ifndef IN_CLASSA_NET
+#include <netinet/in.h>
+#endif /* IN_CLASSA_NET */
+
+
+
+/*
+ * The following looks like a sockaddr to facilitate using tree lookup
+ * routines
+ */
+struct iso_addr {
+ u_char isoa_len; /* length (in bytes) */
+ char isoa_genaddr[20]; /* general opaque address */
+};
+
+struct sockaddr_iso {
+ u_char siso_len; /* length */
+ sa_family_t siso_family; /* family */
+ u_char siso_plen; /* presentation selector length */
+ u_char siso_slen; /* session selector length */
+ u_char siso_tlen; /* transport selector length */
+ struct iso_addr siso_addr; /* network address */
+ u_char siso_pad[6]; /* space for gosip v2 sels */
+ /* makes struct 32 bytes long */
+};
+#define siso_nlen siso_addr.isoa_len
+#define siso_data siso_addr.isoa_genaddr
+
+#define TSEL(s) ((caddr_t)((s)->siso_data + (s)->siso_nlen))
+
+#define SAME_ISOADDR(a, b) \
+ (bcmp((a)->siso_data, (b)->siso_data, (unsigned)(a)->siso_nlen)==0)
+#define SAME_ISOIFADDR(a, b) (bcmp((a)->siso_data, (b)->siso_data, \
+ (unsigned)((b)->siso_nlen - (b)->siso_tlen)) == 0)
+/*
+ * The following are specific values for siso->siso_data[0],
+ * otherwise known as the AFI:
+ */
+#define AFI_37 0x37 /* bcd of "37" */
+#define AFI_OSINET 0x47 /* bcd of "47" */
+#define AFI_RFC986 0x47 /* bcd of "47" */
+#define AFI_SNA 0x00 /* SubNetwork Address; invalid really... */
+
+#ifdef _KERNEL
+
+extern struct domain isodomain;
+extern struct protosw isosw[];
+
+#define satosiso(sa) ((struct sockaddr_iso *)(sa))
+#define sisotosa(siso) ((struct sockaddr *)(siso))
+
+#else
+/* user utilities definitions from the iso library */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct iso_addr *iso_addr __P((const char *));
+char *iso_ntoa __P((const struct iso_addr *));
+
+/* THESE DON'T EXIST YET */
+struct hostent *iso_gethostbyname __P((const char *));
+struct hostent *iso_gethostbyaddr __P((const char *, int, int));
+__END_DECLS
+
+#endif /* _KERNEL */
+
+#endif /* _NETISO_ISO_H_ */
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
new file mode 100644
index 00000000..8079bd17
--- /dev/null
+++ b/isisd/isis_adjacency.c
@@ -0,0 +1,508 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_adjacency.c
+ * handling of IS-IS adjacencies
+ *
+ * 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 <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+
+#include "log.h"
+#include "memory.h"
+#include "hash.h"
+#include "vty.h"
+#include "linklist.h"
+#include "thread.h"
+#include "if.h"
+#include "stream.h"
+
+#include "isisd/dict.h"
+#include "isisd/include-netbsd/iso.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_pdu.h"
+
+
+extern struct isis *isis;
+
+
+struct isis_adjacency *
+adj_alloc (u_char *id)
+{
+ struct isis_adjacency *adj;
+
+ adj = XMALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
+ memset (adj, 0, sizeof (struct isis_adjacency));
+ memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
+
+ return adj;
+}
+
+struct isis_adjacency *
+isis_new_adj (u_char *id, u_char *snpa, int level,
+ struct isis_circuit *circuit)
+{
+
+ struct isis_adjacency *adj;
+ int i;
+
+ adj = adj_alloc (id); /* P2P kludge */
+
+ if (adj == NULL){
+ zlog_err ("Out of memory!");
+ return NULL;
+ }
+
+ memcpy (adj->snpa, snpa, 6);
+ adj->circuit = circuit;
+ adj->level = level;
+ adj->flaps = 0;
+ adj->last_flap = time (NULL);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ listnode_add (circuit->u.bc.adjdb[level-1], adj);
+ adj->dischanges[level - 1] = 0;
+ for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
+ {
+ adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
+ = ISIS_UNKNOWN_DIS;
+ adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
+ = time (NULL);
+ }
+ }
+
+ return adj;
+}
+
+struct isis_adjacency *
+isis_adj_lookup (u_char *sysid, struct list *adjdb)
+{
+ struct isis_adjacency *adj;
+ struct listnode *node;
+
+ for (node = listhead (adjdb); node; nextnode (node)) {
+ adj = getdata (node);
+ if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
+ return adj;
+ }
+
+ return NULL;
+}
+
+
+struct isis_adjacency *
+isis_adj_lookup_snpa (u_char *ssnpa, struct list *adjdb)
+{
+ struct listnode *node;
+ struct isis_adjacency *adj;
+
+ for (node = listhead (adjdb); node; nextnode (node)) {
+ adj = getdata (node);
+ if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
+ return adj;
+ }
+
+ return NULL;
+}
+
+/*
+ * When we recieve a NULL list, we will know its p2p
+ */
+void
+isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
+{
+ struct isis_adjacency *adj2;
+ struct listnode *node;
+
+ if (adjdb) {
+ for (node = listhead (adjdb); node; nextnode (node)) {
+ adj2 = getdata (node);
+ if (adj2 == adj)
+ break;
+ }
+ listnode_delete (adjdb, node);
+ }
+
+ if (adj->ipv4_addrs)
+ list_delete (adj->ipv4_addrs);
+#ifdef HAVE_IPV6
+ if (adj->ipv6_addrs)
+ list_delete (adj->ipv6_addrs);
+#endif
+ if (adj) {
+ XFREE (MTYPE_ISIS_ADJACENCY,adj);
+ } else {
+ zlog_info ("tried to delete a non-existent adjacency");
+ }
+
+
+
+ return;
+}
+
+void
+isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
+ char *reason)
+
+{
+ int old_state;
+ int level = adj->level;
+ struct isis_circuit *circuit;
+
+ old_state = adj->adj_state;
+ adj->adj_state = state;
+
+ circuit = adj->circuit;
+
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_info ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
+ circuit->area->area_tag,
+ old_state,
+ state,
+ reason ? reason : "unspecified");
+ }
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ if (state == ISIS_ADJ_UP)
+ circuit->upadjcount[level-1]++;
+ if (state == ISIS_ADJ_DOWN) {
+ isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
+ circuit->upadjcount[level-1]--;
+ }
+
+ 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]);
+ } else if (state == ISIS_ADJ_UP) { /* p2p interface */
+ if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
+ send_hello (circuit, 1);
+
+ /* update counter & timers for debugging purposes */
+ adj->last_flap = time(NULL);
+ adj->flaps++;
+
+ /* 7.3.17 - going up on P2P -> send CSNP */
+ /* FIXME: yup, I know its wrong... but i will do it! (for now) */
+ send_csnp (circuit,1);
+ send_csnp (circuit,2);
+ } else if (state == ISIS_ADJ_DOWN) { /* p2p interface */
+ adj->circuit->u.p2p.neighbor = NULL;
+ isis_delete_adj (adj, NULL);
+ }
+ return;
+}
+
+
+void
+isis_adj_print (struct isis_adjacency *adj)
+{
+ struct isis_dynhn *dyn;
+ struct listnode *node;
+ struct in_addr *ipv4_addr;
+#ifdef HAVE_IPV6
+ struct in6_addr *ipv6_addr;
+ u_char ip6 [INET6_ADDRSTRLEN];
+#endif /* HAVE_IPV6 */
+
+ if(!adj)
+ return;
+ dyn = dynhn_find_by_id (adj->sysid);
+ if (dyn)
+ zlog_info ("%s", dyn->name.name);
+
+ zlog_info ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
+ adj->sysid ? sysid_print (adj->sysid) : "unknown" ,
+ snpa_print (adj->snpa),
+ adj->level, adj->hold_time);
+ if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) {
+ zlog_info ("IPv4 Addresses:");
+
+ for (node = listhead (adj->ipv4_addrs); node; nextnode (node)) {
+ ipv4_addr = getdata (node);
+ zlog_info ("%s", inet_ntoa(*ipv4_addr));
+ }
+ }
+
+#ifdef HAVE_IPV6
+ if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) {
+ zlog_info ("IPv6 Addresses:");
+ for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) {
+ ipv6_addr = getdata (node);
+ inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
+ zlog_info ("%s", ip6);
+ }
+ }
+#endif /* HAVE_IPV6 */
+ zlog_info ("Speaks: %s", nlpid2string(&adj->nlpids));
+
+
+ return;
+}
+
+int
+isis_adj_expire (struct thread *thread)
+{
+ struct isis_adjacency *adj;
+ int level;
+
+ /*
+ * Get the adjacency
+ */
+ adj = THREAD_ARG (thread);
+ assert (adj);
+ level = adj->level;
+
+ /* trigger the adj expire event */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
+
+ return 0;
+}
+
+const char *
+adj_state2string (int state)
+{
+
+ switch (state) {
+ case ISIS_ADJ_INITIALIZING:
+ return "Initializing";
+ case ISIS_ADJ_UP:
+ return "Up";
+ case ISIS_ADJ_DOWN:
+ return "Down";
+ default:
+ return "Unknown";
+ }
+
+ return NULL; /* not reached */
+}
+
+/*
+ * show clns/isis neighbor (detail)
+ */
+void
+isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
+{
+
+#ifdef HAVE_IPV6
+ struct in6_addr *ipv6_addr;
+ u_char ip6 [INET6_ADDRSTRLEN];
+#endif /* HAVE_IPV6 */
+ struct in_addr *ip_addr;
+ time_t now;
+ struct isis_dynhn *dyn;
+ int level;
+ struct listnode *node;
+
+ dyn = dynhn_find_by_id (adj->sysid);
+ if (dyn)
+ vty_out (vty, " %-20s", dyn->name.name);
+ else if (adj->sysid){
+ vty_out (vty, " %-20s", sysid_print (adj->sysid));
+ } else {
+ vty_out (vty, " unknown ");
+ }
+
+ if (detail == ISIS_UI_LEVEL_BRIEF) {
+ if (adj->circuit)
+ vty_out (vty, "%-12s",adj->circuit->interface->name);
+ else
+ vty_out (vty, "NULL circuit!");
+ vty_out (vty, "%-3u", adj->level); /* level */
+ vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
+ now = time (NULL);
+ vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
+ vty_out (vty, "%-10s", snpa_print (adj->snpa));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ if (detail == ISIS_UI_LEVEL_DETAIL) {
+ level = adj->level;
+ if (adj->circuit)
+ vty_out (vty, "%s Interface: %s",
+ VTY_NEWLINE,
+ adj->circuit->interface->name); /* interface name */
+ else
+ vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
+ vty_out (vty, ", Level: %u", adj->level); /* level */
+ vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
+ now = time (NULL);
+ vty_out (vty, ", Expires in %s",
+ time2string (adj->last_upd + adj->hold_time - now));
+ vty_out (vty, "%s Adjacency flaps: %u",
+ VTY_NEWLINE,
+ adj->flaps);
+ vty_out (vty, ", Last: %s ago", time2string(now - adj->last_flap));
+ vty_out (vty, "%s Circuit type: %s",
+ VTY_NEWLINE,
+ circuit_t2string(adj->circuit_t));
+ vty_out (vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
+ vty_out (vty, "%s SNPA: %s",
+ VTY_NEWLINE,
+ snpa_print (adj->snpa));
+ dyn = dynhn_find_by_id (adj->lanid);
+ if (dyn)
+ vty_out (vty, ", LAN id: %s.%02x",
+ dyn->name.name,
+ adj->lanid[ISIS_SYS_ID_LEN]);
+ else
+ vty_out (vty, ", LAN id: %s.%02x",
+ sysid_print (adj->lanid),
+ adj->lanid[ISIS_SYS_ID_LEN]);
+
+ vty_out (vty, "%s Priority: %u",
+ VTY_NEWLINE,
+ adj->prio[adj->level-1]);
+
+ vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
+ isis_disflag2string(adj->dis_record[ISIS_LEVELS+level-1].dis),
+ adj->dischanges[level-1],
+ time2string (now -
+ (adj->dis_record[ISIS_LEVELS + level - 1].last_dis_change)),
+ VTY_NEWLINE);
+
+ if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) {
+ vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE);
+ for (node = listhead (adj->ipv4_addrs);node; nextnode (node)) {
+ ip_addr = getdata (node);
+ vty_out (vty, " %s%s", inet_ntoa(*ip_addr), VTY_NEWLINE);
+ }
+ }
+#ifdef HAVE_IPV6
+ if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) {
+ vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
+ for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) {
+ ipv6_addr = getdata (node);
+ inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
+ vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
+ }
+ }
+#endif /* HAVE_IPV6 */
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ return;
+}
+
+void
+isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty) {
+ isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
+}
+
+void
+isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) {
+ isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
+}
+
+void
+isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) {
+ isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
+}
+
+void
+isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
+{
+ isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
+}
+
+void
+isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
+{
+ isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
+}
+
+void
+isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
+{
+ isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
+}
+
+void
+isis_adjdb_iterate (struct list *adjdb, void (*func)(struct isis_adjacency*,
+ void *), void *arg)
+{
+ struct listnode *node;
+ struct isis_adjacency *adj;
+ for (node = listhead (adjdb); node; nextnode (node)) {
+ adj = getdata (node);
+ (*func)(adj, arg);
+ }
+}
+
+void
+isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
+
+{
+ struct isis_adjacency *adj;
+ struct listnode *node;
+
+
+ if (!list) {
+ zlog_warn ("isis_adj_build_neigh_list(): NULL list");
+ return;
+ }
+
+ for (node = listhead (adjdb); node; nextnode (node)) {
+ adj = getdata (node);
+ if (!adj) {
+ zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
+ return;
+ }
+
+ if ((adj->adj_state == ISIS_ADJ_UP ||
+ adj->adj_state == ISIS_ADJ_INITIALIZING))
+ listnode_add (list, adj->snpa);
+ }
+ return;
+}
+
+void
+isis_adj_build_up_list (struct list *adjdb, struct list *list)
+{
+ struct isis_adjacency *adj;
+ struct listnode *node;
+
+ if (!list) {
+ zlog_warn ("isis_adj_build_up_list(): NULL list");
+ return;
+ }
+
+ for (node = listhead (adjdb); node; nextnode (node)) {
+ adj = getdata (node);
+
+ if (!adj) {
+ zlog_warn ("isis_adj_build_up_list(): NULL adj");
+ return;
+ }
+
+ if (adj->adj_state == ISIS_ADJ_UP)
+ listnode_add (list, adj);
+ }
+
+ return;
+}
+
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
new file mode 100644
index 00000000..5c0772cc
--- /dev/null
+++ b/isisd/isis_adjacency.h
@@ -0,0 +1,126 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_adjacency.h
+ * IS-IS adjacency handling
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_ADJACENCY_H
+#define _ZEBRA_ISIS_ADJACENCY_H
+
+enum isis_adj_usage
+{
+ ISIS_ADJ_NONE,
+ ISIS_ADJ_LEVEL1,
+ ISIS_ADJ_LEVEL2,
+ ISIS_ADJ_LEVEL1AND2
+};
+
+enum isis_system_type
+{
+ ISIS_SYSTYPE_UNKNOWN,
+ ISIS_SYSTYPE_ES,
+ ISIS_SYSTYPE_IS,
+ ISIS_SYSTYPE_L1_IS,
+ ISIS_SYSTYPE_L2_IS
+};
+
+enum isis_adj_state
+{
+ ISIS_ADJ_INITIALIZING,
+ ISIS_ADJ_UP,
+ ISIS_ADJ_DOWN
+};
+
+/*
+ * we use the following codes to give an indication _why_
+ * a specific adjacency is up or down
+ */
+enum isis_adj_updown_reason
+{
+ ISIS_ADJ_REASON_SEENSELF,
+ ISIS_ADJ_REASON_AREA_MISMATCH,
+ ISIS_ADJ_REASON_HOLDTIMER_EXPIRED,
+ ISIS_ADJ_REASON_AUTH_FAILED,
+ ISIS_ADJ_REASON_CHECKSUM_FAILED
+};
+
+#define DIS_RECORDS 8 /* keep the last 8 DIS state changes on record */
+
+struct isis_dis_record {
+ int dis; /* is our neighbor the DIS ? */ time_t last_dis_change; /* timestamp for last dis change */
+};
+
+struct isis_adjacency{
+ u_char snpa[ETH_ALEN]; /* NeighbourSNPAAddress */
+ u_char sysid[ISIS_SYS_ID_LEN]; /* neighbourSystemIdentifier */
+ u_char lanid[ISIS_SYS_ID_LEN+1]; /* LAN id on bcast circuits */
+ int dischanges[ISIS_LEVELS]; /* how many DIS changes ?*/
+ /* an array of N levels for M records */
+ struct isis_dis_record dis_record[DIS_RECORDS * ISIS_LEVELS];
+ enum isis_adj_state adj_state; /* adjacencyState */
+ enum isis_adj_usage adj_usage; /* adjacencyUsage */
+ struct list *area_addrs; /* areaAdressesOfNeighbour */
+ struct nlpids nlpids; /* protocols spoken ... */
+ struct list *ipv4_addrs;
+#ifdef HAVE_IPV6
+ struct list *ipv6_addrs;
+#endif /* HAVE_IPV6 */
+ u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS*/
+ int circuit_t; /* from hello PDU hdr */
+ int level; /* level (1 or 2) */
+ enum isis_system_type sys_type; /* neighbourSystemType */
+ u_int16_t hold_time; /* entryRemainingTime */
+ u_int32_t last_upd;
+ u_int32_t last_flap; /* last time the adj flapped */
+ int flaps; /* number of adjacency flaps */
+ struct thread *t_expire; /* expire after hold_time */
+ struct isis_circuit *circuit; /* back pointer */
+};
+
+
+struct isis_adjacency *isis_adj_lookup (u_char *sysid, struct list *adjdb);
+struct isis_adjacency *isis_adj_lookup_snpa (u_char *ssnpa,
+ struct list *adjdb);
+struct isis_adjacency *isis_new_adj (u_char *id, u_char *snpa, int level,
+ struct isis_circuit *circuit);
+void isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb);
+void isis_adj_state_change (struct isis_adjacency *adj,
+ enum isis_adj_state state, char *reason);
+void isis_adj_print (struct isis_adjacency *adj);
+int isis_adj_expire (struct thread *thread);
+void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty);
+void isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty);
+void isis_adj_print_vty_extensive (struct isis_adjacency *adj,
+ struct vty *vty);
+void isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty);
+void isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj,
+ struct vty *vty);
+void isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj,
+ struct vty *vty);
+
+void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
+void isis_adj_build_up_list (struct list *adjdb, struct list *list);
+void isis_adjdb_iterate (struct list *adjdb,
+ void (*func)(struct isis_adjacency*,
+ void *), void *arg);
+
+#endif /* ISIS_ADJACENCY_H */
+
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
new file mode 100644
index 00000000..f37c314e
--- /dev/null
+++ b/isisd/isis_circuit.c
@@ -0,0 +1,2200 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_circuit.h
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "log.h"
+#include "memory.h"
+#include "if.h"
+#include "linklist.h"
+#include "command.h"
+#include "thread.h"
+#include "hash.h"
+#include "prefix.h"
+#include "stream.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_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_events.h"
+
+extern struct thread_master *master;
+extern struct isis *isis;
+
+struct isis_circuit *
+isis_circuit_new ()
+{
+ struct isis_circuit *circuit;
+ int i;
+
+ circuit = XMALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit));
+ if (circuit) {
+ memset (circuit, 0, sizeof (struct isis_circuit));
+ /* set default metrics for circuit */
+ for (i = 0; i < 2; i++) {
+ circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRICS;
+ circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED;
+ circuit->metrics[i].metric_error = METRICS_UNSUPPORTED;
+ circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED;
+ }
+ } else {
+ zlog_err ("Can't malloc isis circuit");
+ return NULL;
+ }
+
+ return circuit;
+}
+
+
+void
+isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
+{
+ int i;
+ circuit->area = area;
+ /*
+ * The level for the circuit is same as for the area, unless configured
+ * otherwise.
+ */
+ circuit->circuit_is_type = area->is_type;
+ /*
+ * Default values
+ */
+ for (i = 0; i < 2; i++) {
+ circuit->hello_interval[i] = HELLO_INTERVAL;
+ circuit->hello_multiplier[i] = HELLO_MULTIPLIER;
+ circuit->csnp_interval[i] = CSNP_INTERVAL;
+ circuit->psnp_interval[i] = PSNP_INTERVAL;
+ circuit->u.bc.priority[i] = DEFAULT_PRIORITY;
+ }
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ circuit->u.bc.adjdb[0] = list_new ();
+ circuit->u.bc.adjdb[1] = list_new ();
+ circuit->u.bc.pad_hellos = 1;
+ }
+ circuit->lsp_interval = LSP_INTERVAL;
+
+ /*
+ * Add the circuit into area
+ */
+ listnode_add (area->circuit_list, circuit);
+
+ circuit->idx = flags_get_index (&area->flags);
+ circuit->lsp_queue = list_new ();
+
+ return;
+}
+
+void
+isis_circuit_deconfigure (struct isis_circuit *circuit,
+ struct isis_area *area)
+{
+
+ /* Remove circuit from area */
+ listnode_delete (area->circuit_list, circuit);
+ /* Free the index of SRM and SSN flags */
+ flags_free_index (&area->flags, circuit->idx);
+
+ return;
+}
+
+struct isis_circuit *
+circuit_lookup_by_ifp (struct interface *ifp, struct list *list)
+{
+ struct isis_circuit *circuit = NULL;
+ struct listnode *node;
+
+ if (!list)
+ return NULL;
+
+ for (node = listhead (list); node; nextnode (node)) {
+ circuit = getdata (node);
+ if (circuit->interface == ifp)
+ return circuit;
+ }
+
+ return NULL;
+}
+
+struct isis_circuit *
+circuit_scan_by_ifp (struct interface *ifp)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ if (!isis->area_list)
+ return NULL;
+
+ for (node = listhead (isis->area_list); node; nextnode (node)) {
+ area = getdata (node);
+ circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ if (circuit)
+ return circuit;
+ }
+
+ return circuit_lookup_by_ifp (ifp, isis->init_circ_list);
+}
+
+void
+isis_circuit_del (struct isis_circuit *circuit)
+{
+
+ if (!circuit)
+ return;
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ /* destroy adjacency databases */
+ list_delete (circuit->u.bc.adjdb[0]);
+ list_delete (circuit->u.bc.adjdb[1]);
+ /* destroy neighbour lists */
+ if (circuit->u.bc.lan_neighs[0])
+ list_delete (circuit->u.bc.lan_neighs[0]);
+ if (circuit->u.bc.lan_neighs[1])
+ list_delete (circuit->u.bc.lan_neighs[1]);
+ /* destroy addresses */
+ }
+ if (circuit->ip_addrs)
+ list_delete (circuit->ip_addrs);
+#ifdef HAVE_IPV6
+ if (circuit->ipv6_link)
+ list_delete (circuit->ipv6_link);
+ if (circuit->ipv6_non_link)
+ list_delete (circuit->ipv6_non_link);
+#endif /* HAVE_IPV6 */
+
+ /* and lastly the circuit itself */
+ XFREE (MTYPE_ISIS_CIRCUIT, circuit);
+
+ return;
+}
+
+void
+isis_circuit_add_addr (struct isis_circuit *circuit,
+ struct connected *conn)
+{
+ struct prefix_ipv4 *ipv4;
+ u_char buf [BUFSIZ];
+#ifdef HAVE_IPV6
+ struct prefix_ipv6 *ipv6;
+#endif /* HAVE_IPV6 */
+ if (!circuit->ip_addrs) {
+ circuit->ip_addrs = list_new ();
+ }
+#ifdef HAVE_IPV6
+ if (!circuit->ipv6_link) {
+ circuit->ipv6_link = list_new ();
+ }
+ if (!circuit->ipv6_non_link) {
+ circuit->ipv6_non_link = list_new ();
+ }
+#endif /* HAVE_IPV6 */
+
+ memset (&buf, 0, BUFSIZ);
+ if (conn->address->family == AF_INET) {
+ ipv4 = prefix_ipv4_new ();
+ ipv4->prefixlen = conn->address->prefixlen;
+ ipv4->prefix = conn->address->u.prefix4;
+ listnode_add (circuit->ip_addrs, ipv4);
+ prefix2str (conn->address, buf, BUFSIZ);
+#ifdef EXTREME_DEBUG
+ zlog_info ("Added IP address %s to circuit %d", buf,
+ circuit->circuit_id);
+#endif /* EXTREME_DEBUG */
+ }
+#ifdef HAVE_IPV6
+ if (conn->address->family == AF_INET6) {
+ ipv6 = prefix_ipv6_new ();
+ ipv6->prefixlen = conn->address->prefixlen;
+ ipv6->prefix = conn->address->u.prefix6;
+ if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) {
+ listnode_add (circuit->ipv6_link, ipv6);
+ } else {
+ listnode_add (circuit->ipv6_non_link, ipv6);
+ }
+ prefix2str (conn->address, buf, BUFSIZ);
+#ifdef EXTREME_DEBUG
+ zlog_info ("Added IPv6 address %s to circuit %d", buf,
+ circuit->circuit_id);
+#endif /* EXTREME_DEBUG */
+ }
+#endif /* HAVE_IPV6 */
+
+
+ return;
+}
+
+void
+isis_circuit_del_addr (struct isis_circuit *circuit,
+ struct connected *connected)
+{
+
+}
+
+void
+isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
+{
+ struct listnode *node;
+ struct connected *conn;
+
+ circuit->interface = ifp;
+ ifp->info = circuit;
+
+ circuit->circuit_id = ifp->ifindex % 255; /* FIXME: Why not ? */
+
+ /* isis_circuit_update_addrs (circuit, ifp); */
+
+ if (if_is_broadcast (ifp)) {
+ circuit->circ_type = CIRCUIT_T_BROADCAST;
+ /*
+ * Get the Hardware Address
+ */
+#ifdef HAVE_SOCKADDR_DL
+ 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);
+#else
+ if (circuit->interface->hw_addr_len != ETH_ALEN) {
+ zlog_warn ("unsupported link layer");
+ } else {
+ memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
+ }
+#ifdef EXTREME_DEGUG
+ zlog_info ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
+ circuit->interface->ifindex, ISO_MTU (circuit),
+ snpa_print (circuit->u.bc.snpa));
+
+#endif /* EXTREME_DEBUG */
+#endif /* HAVE_SOCKADDR_DL */
+ } else if (if_is_pointopoint (ifp)) {
+ circuit->circ_type = CIRCUIT_T_P2P;
+ } else {
+ zlog_warn ("isis_circuit_if_add: unsupported media");
+ }
+
+ for (node = ifp->connected ? listhead (ifp->connected) : NULL; node;
+ nextnode (node)) {
+ conn = getdata (node);
+ isis_circuit_add_addr (circuit, conn);
+ }
+
+ return;
+}
+
+void
+isis_circuit_update_params (struct isis_circuit *circuit,
+ struct interface *ifp)
+{
+ assert (circuit);
+
+ if (circuit->circuit_id != ifp->ifindex) {
+ zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id,
+ ifp->ifindex);
+ circuit->circuit_id = ifp->ifindex % 255;
+ }
+
+ /* FIXME: Why is this needed? shouldn't we compare to the area's mtu */
+ /* Ofer, this was here in case someone changes the mtu (e.g. with ifconfig)
+ The areas MTU is the minimum of mtu's of circuits in the area
+ now we can't catch the change
+ if (circuit->mtu != ifp->mtu) {
+ zlog_warn ("changing circuit mtu %d->%d", circuit->mtu,
+ ifp->mtu);
+ circuit->mtu = ifp->mtu;
+ }
+ */
+ /*
+ * Get the Hardware Address
+ */
+#ifdef HAVE_SOCKADDR_DL
+ 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);
+#else
+ if (circuit->interface->hw_addr_len != ETH_ALEN) {
+ zlog_warn ("unsupported link layer");
+ } else {
+ if (memcmp(circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN)) {
+ zlog_warn ("changing circuit snpa %s->%s",
+ snpa_print (circuit->u.bc.snpa),
+ snpa_print (circuit->interface->hw_addr));
+ }
+ }
+#endif
+
+
+
+ if (if_is_broadcast (ifp)) {
+ circuit->circ_type = CIRCUIT_T_BROADCAST;
+ } else if (if_is_pointopoint (ifp)) {
+ circuit->circ_type = CIRCUIT_T_P2P;
+ } else {
+ zlog_warn ("isis_circuit_update_params: unsupported media");
+ }
+
+ return;
+}
+
+void
+isis_circuit_if_del (struct isis_circuit *circuit)
+{
+ circuit->interface->info = NULL;
+ circuit->interface = NULL;
+
+ return;
+}
+
+void
+isis_circuit_up (struct isis_circuit *circuit)
+{
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ if (circuit->area->min_bcast_mtu == 0 ||
+ ISO_MTU(circuit) < circuit->area->min_bcast_mtu )
+ circuit->area->min_bcast_mtu = ISO_MTU(circuit);
+ /*
+ * ISO 10589 - 8.4.1 Enabling of broadcast circuits
+ */
+
+ /* initilizing the hello sending threads
+ * for a broadcast IF
+ */
+
+ /* 8.4.1 a) commence sending of IIH PDUs */
+
+ if (circuit->circuit_is_type & IS_LEVEL_1) {
+ thread_add_event (master, send_lan_l1_hello, circuit, 0);
+ circuit->u.bc.lan_neighs[0] = list_new ();
+ }
+
+ if (circuit->circuit_is_type & IS_LEVEL_2) {
+ thread_add_event (master, send_lan_l2_hello, circuit, 0);
+ circuit->u.bc.lan_neighs[1] = list_new ();
+ }
+
+ /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
+ /* 8.4.1 c) FIXME: listen for ESH PDUs */
+
+ /* 8.4.1 d) */
+ /* dr election will commence in... */
+ if (circuit->circuit_is_type & IS_LEVEL_1)
+ circuit->u.bc.t_run_dr[0] =
+ thread_add_timer (master, isis_run_dr_l1, circuit,
+ 2 * circuit->hello_multiplier[0] * circuit->hello_interval[0]);
+ if (circuit->circuit_is_type & IS_LEVEL_2)
+ circuit->u.bc.t_run_dr[1] =
+ thread_add_timer (master, isis_run_dr_l2, circuit,
+ 2 * circuit->hello_multiplier[1] * circuit->hello_interval[1]);
+ } else {
+ /* initializing the hello send threads
+ * for a ptp IF
+ */
+ thread_add_event (master, send_p2p_hello, circuit, 0);
+
+ }
+
+ /* initializing PSNP timers */
+ if (circuit->circuit_is_type & IS_LEVEL_1) {
+ circuit->t_send_psnp[0] = thread_add_timer (master,
+ send_l1_psnp,
+ circuit,
+ isis_jitter
+ (circuit->psnp_interval[0],
+ PSNP_JITTER));
+ }
+
+ if (circuit->circuit_is_type & IS_LEVEL_2) {
+ circuit->t_send_psnp[1] = thread_add_timer (master,
+ send_l2_psnp,
+ circuit,
+ isis_jitter
+ (circuit->psnp_interval[1],
+ PSNP_JITTER));
+
+ }
+
+ /* initialize the circuit streams */
+ 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
+ circuit->t_read = thread_add_read (master, isis_receive, circuit,
+ circuit->fd);
+#else
+ circuit->t_read = thread_add_timer (master, isis_receive, circuit,
+ circuit->fd);
+#endif
+ return;
+}
+
+void
+isis_circuit_down (struct isis_circuit *circuit)
+{
+ /* Cancel all active threads -- FIXME: wrong place*/
+ if (circuit->t_read)
+ thread_cancel (circuit->t_read);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ if (circuit->u.bc.t_send_lan_hello[0])
+ thread_cancel (circuit->u.bc.t_send_lan_hello[0]);
+ if (circuit->u.bc.t_send_lan_hello[1])
+ thread_cancel (circuit->u.bc.t_send_lan_hello[1]);
+ } else if (circuit->circ_type == CIRCUIT_T_P2P) {
+ if (circuit->u.p2p.t_send_p2p_hello)
+ thread_cancel (circuit->u.p2p.t_send_p2p_hello);
+ }
+ /* close the socket */
+ close (circuit->fd);
+
+ return;
+}
+
+void
+circuit_update_nlpids (struct isis_circuit *circuit)
+{
+ circuit->nlpids.count = 0;
+
+ if (circuit->ip_router) {
+ circuit->nlpids.nlpids[0] = NLPID_IP;
+ circuit->nlpids.count++;
+ }
+#ifdef HAVE_IPV6
+ if (circuit->ipv6_router) {
+ circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6;
+ circuit->nlpids.count++;
+ }
+#endif /* HAVE_IPV6 */
+ return;
+}
+
+int
+isis_interface_config_write (struct vty *vty)
+{
+
+ int write = 0;
+ listnode node;
+ listnode node2;
+ listnode node3;
+ struct interface *ifp;
+ struct isis_area *area;
+ struct isis_circuit *c;
+ struct prefix_ipv4 *ip;
+ int i;
+#ifdef HAVE_IPV6
+ struct prefix_ipv6 *ipv6;
+#endif /*HAVE_IPV6 */
+
+ char buf[BUFSIZ];
+
+
+ LIST_LOOP (iflist, ifp, node)
+ {
+ /* IF name */
+ vty_out (vty, "interface %s%s", ifp->name,VTY_NEWLINE);
+ write++;
+ /* IF desc */
+ if (ifp->desc) {
+ vty_out (vty, " description %s%s", ifp->desc,VTY_NEWLINE);
+ write++;
+ }
+ /* ISIS Circuit */
+ LIST_LOOP (isis->area_list, area, node2)
+ {
+ c = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ if (c) {
+ if (c->ip_router) {
+ vty_out (vty, " ip router isis %s%s",area->area_tag,VTY_NEWLINE);
+ write++;
+ }
+#ifdef HAVE_IPV6
+ if (c->ipv6_router) {
+ vty_out (vty, " ipv6 router isis %s%s",area->area_tag,VTY_NEWLINE);
+ write++;
+ }
+#endif /* HAVE_IPV6 */
+ /* ipv4 addresses - FIXME: those should be related to interface*/
+ if (c->ip_addrs) {LIST_LOOP (c->ip_addrs,ip, node3)
+ {
+ vty_out (vty, " ip%s address %s/%d%s",
+ ip->family == AF_INET ? "" : "v6",
+ inet_ntop (ip->family, &ip->prefix, buf, BUFSIZ), ip->prefixlen,
+ VTY_NEWLINE);
+ write++;
+ }}
+
+ /* ipv6 addresses - FIXME: those should be related to interface*/
+#ifdef HAVE_IPV6
+ if (c->ipv6_link) {LIST_LOOP (c->ipv6_link, ipv6, node3)
+ {
+ vty_out (vty, " ip%s address %s/%d%s",
+ ipv6->family == AF_INET ? "" : "v6",
+ inet_ntop (ipv6->family, &ipv6->prefix, buf, BUFSIZ),
+ ipv6->prefixlen,VTY_NEWLINE);
+ write++;
+ }}
+ if (c->ipv6_non_link) {LIST_LOOP (c->ipv6_non_link, ipv6, node3)
+ {
+ vty_out (vty, " ip%s address %s/%d%s",
+ ipv6->family == AF_INET ? "" : "v6",
+ inet_ntop (ipv6->family, &ipv6->prefix, buf, BUFSIZ),
+ ipv6->prefixlen, VTY_NEWLINE);
+ write++;
+ }}
+#endif /* HAVE_IPV6 */
+
+ /* ISIS - circuit type */
+ if (c->circuit_is_type == IS_LEVEL_1) {
+ vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
+ write ++;
+ } else {if (c->circuit_is_type == IS_LEVEL_2) {
+ vty_out (vty, " isis circuit-type level-2-only%s", VTY_NEWLINE);
+ write ++;
+ }}
+
+ /* ISIS - CSNP interval - FIXME: compare to cisco*/
+ if (c->csnp_interval[0] == c->csnp_interval[1]) {
+ if (c->csnp_interval[0] != CSNP_INTERVAL) {
+ vty_out (vty, " isis csnp-interval %d%s", c->csnp_interval[0],
+ VTY_NEWLINE);
+ write ++;
+ }
+ } else {
+ for (i=0;i<2;i++) {
+ if (c->csnp_interval[1] != CSNP_INTERVAL) {
+ vty_out (vty, " isis csnp-interval %d level-%d%s",
+ c->csnp_interval[1],i+1, VTY_NEWLINE);
+ write ++;
+ }
+ }
+ }
+
+ /* ISIS - Hello padding - Defaults to true so only display if false */
+ if (c->circ_type == CIRCUIT_T_BROADCAST && !c->u.bc.pad_hellos) {
+ vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
+ write ++;
+ }
+
+ /* ISIS - Hello interval - FIXME: compare to cisco */
+ if (c->hello_interval[0] == c->hello_interval[1]) {
+ if (c->hello_interval[0] != HELLO_INTERVAL) {
+ vty_out (vty, " isis hello-interval %d%s", c->hello_interval[0],
+ VTY_NEWLINE);
+ write ++;
+ }
+ } else {
+ for (i=0;i<2;i++) {
+ if (c->hello_interval[i] != HELLO_INTERVAL) {
+ if (c->hello_interval[i] == HELLO_MINIMAL) {
+ vty_out (vty, " isis hello-interval minimal level-%d%s", i+1,
+ VTY_NEWLINE);
+ } else {
+ vty_out (vty, " isis hello-interval %d level-%d%s",
+ c->hello_interval[i],i+1, VTY_NEWLINE);
+ }
+ write ++;
+ }
+ }
+ }
+
+ /* ISIS - Hello Multiplier */
+ if (c->hello_multiplier[0] == c->hello_multiplier[1]) {
+ if (c->hello_multiplier[0] != HELLO_MULTIPLIER ) {
+ vty_out (vty, " isis hello-multiplier %d%s",
+ c->hello_multiplier[0], VTY_NEWLINE);
+ write ++;
+ }
+ } else {
+ for (i=0;i<2;i++) {
+ if (c->hello_multiplier[i] != HELLO_MULTIPLIER) {
+ vty_out (vty, " isis hello-multiplier %d level-%d%s",
+ c->hello_multiplier[i],i+1, VTY_NEWLINE);
+ write ++;
+ }
+ }
+ }
+ /* ISIS - Priority */
+ if (c->circ_type == CIRCUIT_T_BROADCAST) {
+ if (c->u.bc.priority[0] == c->u.bc.priority[1]) {
+ if (c->u.bc.priority[0] != DEFAULT_PRIORITY) {
+ vty_out (vty, " isis priority %d%s", c->u.bc.priority[0],
+ VTY_NEWLINE);
+ write ++;
+ }
+ } else {
+ for (i=0;i<2;i++) {
+ if (c->u.bc.priority[i] != DEFAULT_PRIORITY) {
+ vty_out (vty, " isis priority %d level-%d%s",
+ c->u.bc.priority[i],i+1, VTY_NEWLINE);
+ write ++;
+ }
+ }
+ }
+ }
+ /* ISIS - Metric */
+ if (c->metrics[0].metric_default == c->metrics[1].metric_default) {
+ if (c->metrics[0].metric_default != DEFAULT_CIRCUIT_METRICS) {
+ vty_out (vty, " isis metric %d%s", c->metrics[0].metric_default,
+ VTY_NEWLINE);
+ write ++;
+ }
+ } else {
+ for (i=0;i<2;i++) {
+ if (c->metrics[i].metric_default != DEFAULT_CIRCUIT_METRICS) {
+ vty_out (vty, " isis metric %d level-%d%s",
+ c->metrics[i].metric_default,i+1, VTY_NEWLINE);
+ write ++;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ return write;
+}
+
+
+DEFUN (ip_router_isis,
+ ip_router_isis_cmd,
+ "ip router isis WORD",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS Routing for IP\n"
+ "Routing process tag\n"
+ )
+{
+ struct isis_circuit *c;
+ struct interface *ifp;
+ struct isis_area *area;
+
+ ifp = (struct interface *)vty->index;
+ assert (ifp);
+
+ area = isis_area_lookup (argv[0]);
+
+ /* Prevent more than one circuit per interface */
+ if (area)
+ c = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ else c = NULL;
+ if (c && (ifp->info != NULL)) {
+#ifdef HAVE_IPV6
+ if (c->ipv6_router == 0) {
+#endif /* HAVE_IPV6 */
+ vty_out (vty, "ISIS circuit is already defined%s", VTY_NEWLINE);
+ return CMD_WARNING;
+#ifdef HAVE_IPV6
+ }
+#endif /* HAVE_IPV6 */
+ }
+
+ /* this is here for ciscopability */
+ if (!area) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!c) {
+ c = circuit_lookup_by_ifp (ifp, isis->init_circ_list);
+ c = isis_csm_state_change (ISIS_ENABLE, c, area);
+ c->interface = ifp; /* this is automatic */
+ ifp->info = c; /* hardly related to the FSM */
+ }
+
+ if(!c)
+ return CMD_WARNING;
+
+ c->ip_router = 1;
+ area->ip_circuits++;
+ circuit_update_nlpids (c);
+
+ vty->node = INTERFACE_NODE;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_router_isis,
+ no_ip_router_isis_cmd,
+ "no ip router isis WORD",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS Routing for IP\n"
+ "Routing process tag\n"
+ )
+{
+ struct isis_circuit *circuit = NULL;
+ struct interface *ifp;
+ struct isis_area *area;
+ struct listnode *node;
+
+ ifp = (struct interface *)vty->index;
+ assert (ifp);
+
+ area = isis_area_lookup (argv[0]);
+ if (!area) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ LIST_LOOP (area->circuit_list, circuit, node)
+ if (circuit->interface == ifp)
+ break;
+ if (!circuit) {
+ vty_out (vty, "Can't find ISIS interface %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ circuit->ip_router = 0;
+ area->ip_circuits--;
+#ifdef HAVE_IPV6
+ if (circuit->ipv6_router == 0)
+#endif
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (isis_circuit_type,
+ isis_circuit_type_cmd,
+ "isis circuit-type (level-1|level-1-2|level-2-only)",
+ "IS-IS commands\n"
+ "Configure circuit type for interface\n"
+ "Level-1 only adjacencies are formed\n"
+ "Level-1-2 adjacencies are formed\n"
+ "Level-2 only adjacencies are formed\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int circuit_t;
+ int is_type;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ /* UGLY - will remove l8r */
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+
+ assert (circuit);
+
+ circuit_t = string2circuit_t (argv[0]);
+
+ if (!circuit_t) {
+ vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ is_type = circuit->area->is_type;
+ if (is_type == IS_LEVEL_1_AND_2 || is_type == circuit_t)
+ isis_event_circuit_type_change (circuit, circuit_t);
+ else {
+ vty_out (vty, "invalid circuit level for area %s.%s",
+ circuit->area->area_tag, VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_circuit_type,
+ no_isis_circuit_type_cmd,
+ "no isis circuit-type (level-1|level-1-2|level-2-only)",
+ NO_STR
+ "IS-IS commands\n"
+ "Configure circuit type for interface\n"
+ "Level-1 only adjacencies are formed\n"
+ "Level-1-2 adjacencies are formed\n"
+ "Level-2 only adjacencies are formed\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+
+ assert(circuit);
+
+ /*
+ * Set the circuits level to its default value which is that of the area
+ */
+ isis_event_circuit_type_change (circuit, circuit->area->is_type);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (isis_passwd,
+ isis_passwd_cmd,
+ "isis password WORD",
+ "IS-IS commands\n"
+ "Configure the authentication password for interface\n"
+ "Password\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int len;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+
+ len = strlen (argv[0]);
+ if (len > 254) {
+ vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ circuit->passwd.len = len;
+ circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
+ strncpy (circuit->passwd.passwd, argv[0], 255);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_passwd,
+ no_isis_passwd_cmd,
+ "no isis password",
+ NO_STR
+ "IS-IS commands\n"
+ "Configure the authentication password for interface\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+
+ memset (&circuit->passwd, 0, sizeof (struct isis_passwd));
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (isis_priority,
+ isis_priority_cmd,
+ "isis priority <0-127>",
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Priority value\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int prio;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ prio = atoi (argv[0]);
+
+ circuit->u.bc.priority[0] = prio;
+ circuit->u.bc.priority[1] = prio;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_priority,
+ no_isis_priority_cmd,
+ "no isis priority",
+ NO_STR
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->u.bc.priority[0] = DEFAULT_PRIORITY;
+ circuit->u.bc.priority[1] = DEFAULT_PRIORITY;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_priority,
+ no_isis_priority_arg_cmd,
+ "no isis priority <0-127>",
+ NO_STR
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Priority value\n"
+ )
+
+DEFUN (isis_priority_l1,
+ isis_priority_l1_cmd,
+ "isis priority <0-127> level-1",
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Priority value\n"
+ "Specify priority for level-1 routing\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int prio;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ prio = atoi (argv[0]);
+
+ circuit->u.bc.priority[0] = prio;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_priority_l1,
+ no_isis_priority_l1_cmd,
+ "no isis priority level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Specify priority for level-1 routing\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->u.bc.priority[0] = DEFAULT_PRIORITY;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_priority_l1,
+ no_isis_priority_l1_arg_cmd,
+ "no isis priority <0-127> level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Priority value\n"
+ "Specify priority for level-1 routing\n"
+ )
+
+DEFUN (isis_priority_l2,
+ isis_priority_l2_cmd,
+ "isis priority <0-127> level-2",
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Priority value\n"
+ "Specify priority for level-2 routing\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int prio;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ prio = atoi (argv[0]);
+
+ circuit->u.bc.priority[1] = prio;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_priority_l2,
+ no_isis_priority_l2_cmd,
+ "no isis priority level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Specify priority for level-2 routing\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->u.bc.priority[1] = DEFAULT_PRIORITY;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_priority_l2,
+ no_isis_priority_l2_arg_cmd,
+ "no isis priority <0-127> level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set priority for Designated Router election\n"
+ "Priority value\n"
+ "Specify priority for level-2 routing\n"
+ )
+
+/* Metric command */
+
+DEFUN (isis_metric,
+ isis_metric_cmd,
+ "isis metric <0-63>",
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Default metric value\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int met;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ met = atoi (argv[0]);
+
+ circuit->metrics[0].metric_default = met;
+ circuit->metrics[1].metric_default = met;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_metric,
+ no_isis_metric_cmd,
+ "no isis metric",
+ NO_STR
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRICS;
+ circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRICS;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_metric,
+ no_isis_metric_arg_cmd,
+ "no isis metric <0-127>",
+ NO_STR
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Default metric value\n"
+ )
+/* end of metrics */
+
+
+DEFUN (isis_hello_interval,
+ isis_hello_interval_cmd,
+ "isis hello-interval (<1-65535>|minimal)",
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Hello interval value\n"
+ "Holdtime 1 seconds, interval depends on multiplier\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int interval;
+ char c;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+ c = *argv[0];
+ if (isdigit((int)c)) {
+ interval = atoi (argv[0]);
+ } else
+ interval = HELLO_MINIMAL; /* FIXME: should be calculated */
+
+ circuit->hello_interval[0] = (u_int16_t)interval;
+ circuit->hello_interval[1] = (u_int16_t)interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello_interval,
+ no_isis_hello_interval_cmd,
+ "no isis hello-interval",
+ NO_STR
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+
+ circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */
+ circuit->hello_interval[1] = HELLO_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_hello_interval,
+ no_isis_hello_interval_arg_cmd,
+ "no isis hello-interval (<1-65535>|minimal)",
+ NO_STR
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Hello interval value\n"
+ "Holdtime 1 second, interval depends on multiplier\n"
+ )
+
+DEFUN (isis_hello_interval_l1,
+ isis_hello_interval_l1_cmd,
+ "isis hello-interval (<1-65535>|minimal) level-1",
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Hello interval value\n"
+ "Holdtime 1 second, interval depends on multiplier\n"
+ "Specify hello-interval for level-1 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ long interval;
+ char c;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ c = *argv[0];
+ if (isdigit((int)c)) {
+ interval = atoi (argv[0]);
+ } else
+ interval = HELLO_MINIMAL;
+
+ circuit->hello_interval[0] = (u_int16_t)interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello_interval_l1,
+ no_isis_hello_interval_l1_cmd,
+ "no isis hello-interval level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Specify hello-interval for level-1 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+
+ circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_hello_interval_l1,
+ no_isis_hello_interval_l1_arg_cmd,
+ "no isis hello-interval (<1-65535>|minimal) level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Hello interval value\n"
+ "Holdtime 1 second, interval depends on multiplier\n"
+ "Specify hello-interval for level-1 IIHs\n"
+ )
+
+DEFUN (isis_hello_interval_l2,
+ isis_hello_interval_l2_cmd,
+ "isis hello-interval (<1-65535>|minimal) level-2",
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Hello interval value\n"
+ "Holdtime 1 second, interval depends on multiplier\n"
+ "Specify hello-interval for level-2 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ long interval;
+ char c;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ c = *argv[0];
+ if (isdigit((int)c)) {
+ interval = atoi (argv[0]);
+ } else
+ interval = HELLO_MINIMAL;
+
+ circuit->hello_interval[1] = (u_int16_t)interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello_interval_l2,
+ no_isis_hello_interval_l2_cmd,
+ "no isis hello-interval level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Specify hello-interval for level-2 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+
+ circuit->hello_interval[1] = HELLO_INTERVAL; /* Default is 1 sec. */
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_hello_interval_l2,
+ no_isis_hello_interval_l2_arg_cmd,
+ "no isis hello-interval (<1-65535>|minimal) level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set Hello interval\n"
+ "Hello interval value\n"
+ "Holdtime 1 second, interval depends on multiplier\n"
+ "Specify hello-interval for level-2 IIHs\n"
+ )
+
+
+DEFUN (isis_hello_multiplier,
+ isis_hello_multiplier_cmd,
+ "isis hello-multiplier <3-1000>",
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Hello multiplier value\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int mult;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ mult = atoi (argv[0]);
+
+ circuit->hello_multiplier[0] = (u_int16_t)mult;
+ circuit->hello_multiplier[1] = (u_int16_t)mult;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello_multiplier,
+ no_isis_hello_multiplier_cmd,
+ "no isis hello-multiplier",
+ NO_STR
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->hello_multiplier[0] = HELLO_MULTIPLIER;
+ circuit->hello_multiplier[1] = HELLO_MULTIPLIER;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_hello_multiplier,
+ no_isis_hello_multiplier_arg_cmd,
+ "no isis hello-multiplier <3-1000>",
+ NO_STR
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Hello multiplier value\n"
+ )
+
+DEFUN (isis_hello_multiplier_l1,
+ isis_hello_multiplier_l1_cmd,
+ "isis hello-multiplier <3-1000> level-1",
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Hello multiplier value\n"
+ "Specify hello multiplier for level-1 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int mult;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ mult = atoi (argv[0]);
+
+ circuit->hello_multiplier[0] = (u_int16_t)mult;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello_multiplier_l1,
+ no_isis_hello_multiplier_l1_cmd,
+ "no isis hello-multiplier level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Specify hello multiplier for level-1 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->hello_multiplier[0] = HELLO_MULTIPLIER;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_hello_multiplier_l1,
+ no_isis_hello_multiplier_l1_arg_cmd,
+ "no isis hello-multiplier <3-1000> level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Hello multiplier value\n"
+ "Specify hello multiplier for level-1 IIHs\n"
+ )
+
+DEFUN (isis_hello_multiplier_l2,
+ isis_hello_multiplier_l2_cmd,
+ "isis hello-multiplier <3-1000> level-2",
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Hello multiplier value\n"
+ "Specify hello multiplier for level-2 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ int mult;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ mult = atoi (argv[0]);
+
+ circuit->hello_multiplier[1] = (u_int16_t)mult;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello_multiplier_l2,
+ no_isis_hello_multiplier_l2_cmd,
+ "no isis hello-multiplier level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Specify hello multiplier for level-2 IIHs\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->hello_multiplier[1] = HELLO_MULTIPLIER;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_hello_multiplier_l2,
+ no_isis_hello_multiplier_l2_arg_cmd,
+ "no isis hello-multiplier <3-1000> level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set multiplier for Hello holding time\n"
+ "Hello multiplier value\n"
+ "Specify hello multiplier for level-2 IIHs\n"
+ )
+
+DEFUN (isis_hello,
+ isis_hello_cmd,
+ "isis hello padding",
+ "IS-IS commands\n"
+ "Add padding to IS-IS hello packets\n"
+ "Pad hello packets\n"
+ "<cr>\n")
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->u.bc.pad_hellos = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_address,
+ ip_address_cmd,
+ "ip address A.B.C.D/A",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8\n")
+
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct prefix_ipv4 *ipv4, *ip;
+ struct listnode *node;
+ int ret, found = 1;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+
+ assert (circuit);
+#ifdef HAVE_IPV6
+ zlog_info ("ip_address_cmd circuit %d", circuit->interface->ifindex);
+#endif /* HAVE_IPV6 */
+
+ ipv4 = prefix_ipv4_new ();
+
+ ret = str2prefix_ipv4 (argv[0], ipv4);
+ if (ret <= 0) {
+ zlog_warn ("ip_address_cmd(): malformed address");
+ vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!circuit->ip_addrs)
+ circuit->ip_addrs = list_new ();
+ else {
+ for (node = listhead (circuit->ip_addrs); node; nextnode (node)) {
+ ip = getdata (node);
+ if (prefix_same ((struct prefix *)ip, (struct prefix *)ipv4))
+ found = 1;
+ }
+ if (found) {
+ prefix_ipv4_free (ipv4);
+ return CMD_SUCCESS;
+ }
+ }
+
+
+ listnode_add (circuit->ip_addrs, ipv4);
+#ifdef EXTREME_DEBUG
+ zlog_info ("added IP address %s to circuit %d", argv[0],
+ circuit->interface->ifindex);
+#endif /* EXTREME_DEBUG */
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_address,
+ no_ip_address_cmd,
+ "no ip address A.B.C.D/A",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IP address (e.g. 10.0.0.1/8\n")
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct prefix_ipv4 ipv4, *ip = NULL;
+ struct listnode *node;
+ int ret;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ /* UGLY - will remove l8r */
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ if (!circuit->ip_addrs || circuit->ip_addrs->count == 0) {
+ vty_out (vty, "Invalid address %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ ret = str2prefix_ipv4 (argv[0], &ipv4);
+ if (ret <= 0) {
+ vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ for (node = listhead (circuit->ip_addrs); node; nextnode (node)) {
+ ip = getdata (node);
+ if (prefix_same ((struct prefix *)ip, (struct prefix *)&ipv4))
+ break;
+ }
+
+ if (ip) {
+ listnode_delete (circuit->ip_addrs, ip);
+ } else {
+ vty_out (vty, "Invalid address %s", VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_hello,
+ no_isis_hello_cmd,
+ "no isis hello padding",
+ NO_STR
+ "IS-IS commands\n"
+ "Add padding to IS-IS hello packets\n"
+ "Pad hello packets\n"
+ "<cr>\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->u.bc.pad_hellos = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (csnp_interval,
+ csnp_interval_cmd,
+ "isis csnp-interval <0-65535>",
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "CSNP interval value\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ unsigned long interval;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ interval = atol (argv[0]);
+
+ circuit->csnp_interval[0] = (u_int16_t)interval;
+ circuit->csnp_interval[1] = (u_int16_t)interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_csnp_interval,
+ no_csnp_interval_cmd,
+ "no isis csnp-interval",
+ NO_STR
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ )
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->csnp_interval[0] = CSNP_INTERVAL;
+ circuit->csnp_interval[1] = CSNP_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_csnp_interval,
+ no_csnp_interval_arg_cmd,
+ "no isis csnp-interval <0-65535>",
+ NO_STR
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "CSNP interval value\n")
+
+
+DEFUN (csnp_interval_l1,
+ csnp_interval_l1_cmd,
+ "isis csnp-interval <0-65535> level-1",
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "CSNP interval value\n"
+ "Specify interval for level-1 CSNPs\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ unsigned long interval;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ interval = atol (argv[0]);
+
+ circuit->csnp_interval[0] = (u_int16_t)interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_csnp_interval_l1,
+ no_csnp_interval_l1_cmd,
+ "no isis csnp-interval level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "Specify interval for level-1 CSNPs\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->csnp_interval[0] = CSNP_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_csnp_interval_l1,
+ no_csnp_interval_l1_arg_cmd,
+ "no isis csnp-interval <0-65535> level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "CSNP interval value\n"
+ "Specify interval for level-1 CSNPs\n")
+
+
+DEFUN (csnp_interval_l2,
+ csnp_interval_l2_cmd,
+ "isis csnp-interval <0-65535> level-2",
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "CSNP interval value\n"
+ "Specify interval for level-2 CSNPs\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ unsigned long interval;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ interval = atol (argv[0]);
+
+ circuit->csnp_interval[1] = (u_int16_t)interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_csnp_interval_l2,
+ no_csnp_interval_l2_cmd,
+ "no isis csnp-interval level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "Specify interval for level-2 CSNPs\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ circuit->csnp_interval[1] = CSNP_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_csnp_interval_l2,
+ no_csnp_interval_l2_arg_cmd,
+ "no isis csnp-interval <0-65535> level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set CSNP interval in seconds\n"
+ "CSNP interval value\n"
+ "Specify interval for level-2 CSNPs\n")
+
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_router_isis,
+ ipv6_router_isis_cmd,
+ "ipv6 router isis WORD",
+ "IPv6 interface subcommands\n"
+ "IPv6 Router interface commands\n"
+ "IS-IS Routing for IPv6\n"
+ "Routing process tag\n")
+{
+ struct isis_circuit *c;
+ struct interface *ifp;
+ struct isis_area *area;
+
+ ifp = (struct interface *)vty->index;
+ assert (ifp);
+
+ area = isis_area_lookup (argv[0]);
+
+ /* Prevent more than one circuit per interface */
+ if (area)
+ c = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ else c = NULL;
+
+ if (c && (ifp->info != NULL)) {
+ if (c->ipv6_router == 1) {
+ vty_out (vty, "ISIS circuit is already defined for IPv6%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ /* this is here for ciscopability */
+ if (!area) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!c) {
+ c = circuit_lookup_by_ifp (ifp, isis->init_circ_list);
+ c = isis_csm_state_change (ISIS_ENABLE, c, area);
+ c->interface = ifp;
+ ifp->info = c;
+ }
+
+ if(!c)
+ return CMD_WARNING;
+
+ c->ipv6_router = 1;
+ area->ipv6_circuits++;
+ circuit_update_nlpids (c);
+
+ vty->node = INTERFACE_NODE;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_router_isis,
+ no_ipv6_router_isis_cmd,
+ "no ipv6 router isis WORD",
+ NO_STR
+ "IPv6 interface subcommands\n"
+ "IPv6 Router interface commands\n"
+ "IS-IS Routing for IPv6\n"
+ "Routing process tag\n")
+{
+ struct isis_circuit *c;
+ struct interface *ifp;
+ struct isis_area *area;
+
+ ifp = (struct interface *)vty->index;
+ /* UGLY - will remove l8r
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ } */
+ assert (ifp);
+
+ area = isis_area_lookup (argv[0]);
+ if (!area) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ c = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ if (!c)
+ return CMD_WARNING;
+
+ c->ipv6_router = 0;
+ area->ipv6_circuits--;
+ if (c->ip_router == 0)
+ isis_csm_state_change (ISIS_DISABLE, c, area);
+
+ return CMD_SUCCESS;
+}
+
+#if 0 /* Guess we don't really need these */
+
+DEFUN (ipv6_address,
+ ipv6_address_cmd,
+ "ipv6 address X:X::X:X/M",
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IPv6 address (e.g. 3ffe:506::1/48)\n")
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct prefix_ipv6 *ipv6, *ip6;
+ struct listnode *node;
+ int ret, found = 1;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ /* UGLY - will remove l8r */
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+#ifdef EXTREME_DEBUG
+ zlog_info ("ipv6_address_cmd circuit %d", circuit->idx);
+#endif /* EXTREME_DEBUG */
+
+ if (circuit == NULL) {
+ zlog_warn ("ipv6_address_cmd(): no circuit");
+ return CMD_WARNING;
+ }
+
+
+ ipv6 = prefix_ipv6_new ();
+
+ ret = str2prefix_ipv6 (argv[0], ipv6);
+ if (ret <= 0) {
+ vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!circuit->ipv6_addrs)
+ circuit->ipv6_addrs = list_new ();
+ else {
+ for (node = listhead (circuit->ipv6_addrs); node; nextnode (node)) {
+ ip6 = getdata (node);
+ if (prefix_same ((struct prefix *)ip6, (struct prefix *)ipv6))
+ found = 1;
+ }
+ if (found) {
+ prefix_ipv6_free (ipv6);
+ return CMD_SUCCESS;
+ }
+ }
+
+
+ listnode_add (circuit->ipv6_addrs, ipv6);
+#ifdef EXTREME_DEBUG
+ zlog_info ("added IPv6 address %s to circuit %d", argv[0], circuit->idx);
+#endif /* EXTREME_DEBUG */
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_address,
+ no_ipv6_address_cmd,
+ "no ipv6 address X:X::X:X/M",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Set the IP address of an interface\n"
+ "IPv6 address (e.g. 3ffe:506::1/48)\n")
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct prefix_ipv6 ipv6, *ip6 = NULL;
+ struct listnode *node;
+ int ret;
+
+ ifp = vty->index;
+ circuit = ifp->info;
+ /* UGLY - will remove l8r */
+ if (circuit == NULL) {
+ return CMD_WARNING;
+ }
+ assert (circuit);
+
+ if (!circuit->ipv6_addrs || circuit->ipv6_addrs->count == 0) {
+ vty_out (vty, "Invalid address %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ ret = str2prefix_ipv6 (argv[0], &ipv6);
+ if (ret <= 0) {
+ vty_out (vty, "%% Malformed address %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ for (node = listhead (circuit->ipv6_addrs); node; nextnode (node)) {
+ ip6 = getdata (node);
+ if (prefix_same ((struct prefix *)ip6, (struct prefix *)&ipv6))
+ break;
+ }
+
+ if (ip6) {
+ listnode_delete (circuit->ipv6_addrs, ip6);
+ } else {
+ vty_out (vty, "Invalid address %s", VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+#endif /* 0 */
+#endif /* HAVE_IPV6 */
+
+
+struct cmd_node interface_node =
+{
+ INTERFACE_NODE,
+ "%s(config-if)# ",
+ 1,
+};
+
+
+int
+isis_if_new_hook (struct interface *ifp)
+{
+/* FIXME: Discuss if the circuit should be created here
+ ifp->info = XMALLOC (MTYPE_ISIS_IF_INFO, sizeof (struct isis_if_info)); */
+ ifp->info = NULL;
+ return 0;
+}
+
+int
+isis_if_delete_hook (struct interface *ifp)
+{
+/* FIXME: Discuss if the circuit should be created here
+ XFREE (MTYPE_ISIS_IF_INFO, ifp->info);*/
+ ifp->info = NULL;
+ return 0;
+}
+
+
+void
+isis_circuit_init ()
+{
+
+ /* Initialize Zebra interface data structure */
+ if_init ();
+ if_add_hook (IF_NEW_HOOK, isis_if_new_hook);
+ if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook);
+
+ /* Install interface node */
+ install_node (&interface_node, isis_interface_config_write);
+ install_element (CONFIG_NODE, &interface_cmd);
+
+ install_default (INTERFACE_NODE);
+ install_element (INTERFACE_NODE, &interface_desc_cmd);
+ install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+
+ install_element (INTERFACE_NODE, &ip_router_isis_cmd);
+ install_element (INTERFACE_NODE, &no_ip_router_isis_cmd);
+
+ install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
+ install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd);
+
+ install_element (INTERFACE_NODE, &isis_passwd_cmd);
+ install_element (INTERFACE_NODE, &no_isis_passwd_cmd);
+
+ install_element (INTERFACE_NODE, &isis_priority_cmd);
+ install_element (INTERFACE_NODE, &no_isis_priority_cmd);
+ install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_priority_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_priority_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd);
+
+ install_element (INTERFACE_NODE, &isis_metric_cmd);
+ install_element (INTERFACE_NODE, &no_isis_metric_cmd);
+ install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd);
+
+ install_element (INTERFACE_NODE, &isis_hello_interval_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd);
+
+ install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd);
+
+ install_element (INTERFACE_NODE, &isis_hello_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_cmd);
+
+ install_element (INTERFACE_NODE, &ip_address_cmd);
+ install_element (INTERFACE_NODE, &no_ip_address_cmd);
+
+ install_element (INTERFACE_NODE, &csnp_interval_cmd);
+ install_element (INTERFACE_NODE, &no_csnp_interval_cmd);
+ install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd);
+ install_element (INTERFACE_NODE, &csnp_interval_l1_cmd);
+ install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd);
+ install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd);
+ install_element (INTERFACE_NODE, &csnp_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd);
+
+#ifdef HAVE_IPV6
+ install_element (INTERFACE_NODE, &ipv6_router_isis_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd);
+#if 0
+ install_element (INTERFACE_NODE, &ipv6_address_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_address_cmd);
+#endif
+#endif
+
+}
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
new file mode 100644
index 00000000..7163c5b9
--- /dev/null
+++ b/isisd/isis_circuit.h
@@ -0,0 +1,158 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_circuit.h
+ *
+ * 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.
+ */
+
+#ifndef ISIS_CIRCUIT_H
+#define ISIS_CIRCUIT_H
+
+#define CIRCUIT_MAX 255
+
+struct password {
+ struct password *next;
+ int len;
+ u_char *pass;
+};
+
+struct metric {
+ u_char metric_default;
+ u_char metric_error;
+ u_char metric_expense;
+ u_char metric_delay;
+};
+
+struct isis_bcast_info {
+ u_char snpa [ETH_ALEN]; /* SNPA of this circuit */
+ char run_dr_elect[2]; /* Should we run dr election ? */
+ struct thread *t_run_dr[2]; /* DR election thread */
+ struct thread *t_send_lan_hello[2]; /* send LAN IIHs in this thread */
+ struct list *adjdb[2]; /* adjacency dbs */
+ struct list *lan_neighs[2]; /* list of lx neigh snpa */
+ char is_dr[2]; /* Are we level x DR ? */
+ u_char l1_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-1 DR */
+ u_char l2_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-2 DR */
+ struct thread *t_refresh_pseudo_lsp[2]; /* refresh pseudo-node LSPs */
+ int pad_hellos; /* add padding to Hello PDUs ? */
+ u_char priority[2]; /* l1/2 IS Priority */
+};
+
+struct isis_p2p_info {
+ struct isis_adjacency *neighbor;
+ struct thread *t_send_p2p_hello; /* send P2P IIHs in this thread */
+};
+
+struct isis_circuit {
+ int state;
+ u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */
+ struct isis_area *area; /* back pointer to the area */
+ struct interface *interface; /* interface info from z */
+ int fd; /* IS-IS l1/2 socket */
+ struct nlpids nlpids;
+ /*
+ * Threads
+ */
+ struct thread *t_read;
+ struct thread *t_send_csnp[2];
+ struct thread *t_send_psnp[2];
+ struct list *lsp_queue; /* LSPs to be txed (both levels) */
+ /* there is no real point in two streams, just for programming kicker */
+ int (* rx) (struct isis_circuit *circuit, u_char *ssnpa);
+ struct stream *rcv_stream; /* Stream for receiving */
+ int (* tx) (struct isis_circuit *circuit, int level);
+ struct stream *snd_stream; /* Stream for sending */
+ int idx; /* idx in S[RM|SN] flags */
+#define CIRCUIT_T_BROADCAST 0
+#define CIRCUIT_T_P2P 1
+#define CIRCUIT_T_STATIC_IN 2
+#define CIRCUIT_T_STATIC_OUT 3
+#define CIRCUIT_T_DA 4
+ int circ_type; /* type of the physical interface */
+ union {
+ struct isis_bcast_info bc;
+ struct isis_p2p_info p2p;
+ } u;
+ char ext_domain; /* externalDomain (boolean) */
+ /*
+ * Configurables
+ */
+ struct isis_passwd passwd; /* Circuit rx/tx password */
+ long lsp_interval;
+ int manual_l2_only; /* manualL2OnlyMode (boolean) */
+ int circuit_is_type; /* circuit is type == level of circuit
+ * diffrenciated from circuit type (media) */
+ u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */
+ u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */
+ u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */
+ u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */
+ struct metric metrics[2]; /* l1XxxMetric */
+ struct password *c_rx_passwds; /* circuitReceivePasswords */
+ struct password *c_tc_passwd; /* circuitTransmitPassword */
+ int ip_router; /* Route IP ? */
+ struct list *ip_addrs; /* our IP addresses */
+#ifdef HAVE_IPV6
+ int ipv6_router; /* Route IPv6 ? */
+ struct list *ipv6_link; /* our link local IPv6 addresses */
+ struct list *ipv6_non_link; /* our non-link local IPv6 addresses */
+#endif /* HAVE_IPV6 */
+ /*
+ * RFC 2973 IS-IS Mesh Groups
+ */
+#define MESH_INACTIVE 0
+#define MESH_BLOCKED 1
+#define MESH_SET 2
+ int mesh_enabled; /* meshGroupEnabled */
+ u_int16_t mesh_group; /* meshGroup */
+ u_int16_t upadjcount[2];
+ /*
+ * Counters as in 10589--11.2.5.9
+ */
+ u_int32_t adj_state_changes; /* changesInAdjacencyState */
+ u_int32_t init_failures; /* intialisationFailures */
+ u_int32_t ctrl_pdus_rxed; /* controlPDUsReceived */
+ u_int32_t ctrl_pdus_txed; /* controlPDUsSent */
+ u_int32_t desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges*/
+ u_int32_t rej_adjacencies; /* rejectedAdjacencies */
+};
+
+
+void isis_circuit_init (void);
+struct isis_circuit *isis_circuit_new (void);
+struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp,
+ struct list *list);
+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);
+void isis_circuit_deconfigure (struct isis_circuit *circuit,
+ struct isis_area *area);
+
+int isis_circuit_destroy (struct isis_circuit *circuit);
+void isis_circuit_if_add (struct isis_circuit *circuit,
+ struct interface *ifp);
+void isis_circuit_if_del (struct isis_circuit *circuit);
+void circuit_update_nlpids (struct isis_circuit *circuit);
+void isis_circuit_update_params (struct isis_circuit *circuit,
+ struct interface *ifp);
+void isis_circuit_add_addr (struct isis_circuit *circuit,
+ struct connected *conn);
+void isis_circuit_del_addr (struct isis_circuit *circuit,
+ struct connected *conn);
+#endif /* _ZEBRA_ISIS_CIRCUIT_H */
diff --git a/isisd/isis_common.h b/isisd/isis_common.h
new file mode 100644
index 00000000..951e6371
--- /dev/null
+++ b/isisd/isis_common.h
@@ -0,0 +1,65 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_common.h
+ * some common data structures
+ *
+ * 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.
+ */
+
+/*
+ * Area Address
+ */
+struct area_addr {
+ u_char addr_len;
+ u_char area_addr[20];
+};
+
+struct isis_passwd {
+ u_char len;
+#define ISIS_PASSWD_TYPE_UNUSED 0
+#define ISIS_PASSWD_TYPE_CLEARTXT 1
+#define ISIS_PASSWD_TYPE_PRIVATE 255
+ u_char type;
+ u_char passwd[255];
+};
+
+/*
+ * (Dynamic) Hostname
+ * one struct for cache list
+ * one struct for LSP TLV
+ */
+struct hostname {
+ u_char namelen;
+ u_char name[255];
+};
+
+/*
+ * Supported Protocol IDs
+ */
+struct nlpids {
+ u_char count;
+ u_char nlpids[4]; /* FIXME: enough ? */
+};
+
+/*
+ * Flags structure for SSN and SRM flags
+ */
+struct flags {
+ int maxindex;
+ struct list *free_idcs;
+};
diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h
new file mode 100644
index 00000000..c5b59aa3
--- /dev/null
+++ b/isisd/isis_constants.h
@@ -0,0 +1,151 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_constants.h
+ *
+ * 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.
+ */
+
+#ifndef ISIS_CONSTANTS_H
+#define ISIS_CONSTANTS_H
+
+/*
+ * Architectural constant values from p. 35 of ISO/IEC 10589
+ */
+
+#define MAX_LINK_METRIC 63
+#define MAX_PATH_METRIC 1023
+#define ISO_SAP 0xFE
+#define INTRADOMAIN_ROUTEING_SELECTOR 0
+#define SEQUENCE_MODULUS 4294967296
+#define RECEIVE_LSP_BUFFER_SIZE 1492
+
+/*
+ * implementation specific jitter values
+ */
+
+#define IIH_JITTER 25 /* % */
+#define MAX_AGE_JITTER 5 /* % */
+#define MAX_LSP_GEN_JITTER 5 /* % */
+#define CSNP_JITTER 10 /* % */
+#define PSNP_JITTER 10 /* % */
+
+#define RANDOM_SPREAD 100000.0
+
+/*
+ * Default values
+ * ISO - 10589
+ * Section 7.3.21 - Parameters
+ */
+#define MAX_AGE 1200
+#define ZERO_AGE_LIFETIME 60
+#define MAX_LSP_GEN_INTERVAL 900
+#define MIN_LSP_GEN_INTERVAL 30
+#define MIN_LSP_TRANS_INTERVAL 5
+#define ISIS_MIN_LSP_LIFETIME 380
+#define CSNP_INTERVAL 10
+#define PSNP_INTERVAL 2
+#define ISIS_MAX_PATH_SPLITS 3
+
+#define ISIS_LEVELS 2
+#define ISIS_LEVEL1 1
+#define ISIS_LEVEL2 2
+
+#define HELLO_INTERVAL 1
+#define HELLO_MINIMAL HELLO_INTERVAL
+#define HELLO_MULTIPLIER 3
+#define DEFAULT_PRIORITY 64
+/* different vendors implement different values 5-10 on average */
+#define LSP_GEN_INTERVAL_DEFAULT 10
+#define LSP_INTERVAL 33 /* msecs */
+#define DEFAULT_CIRCUIT_METRICS 10
+#define METRICS_UNSUPPORTED 0x80
+#define PERIODIC_SPF_INTERVAL 60 /* at the top of my head */
+#define MINIMUM_SPF_INTERVAL 5 /* .. same here */
+
+/*
+ * NLPID values
+ */
+#define NLPID_IP 204
+#define NLPID_IPV6 142
+
+/*
+ * Return values for functions
+ */
+#define ISIS_OK 0
+#define ISIS_WARNING 1
+#define ISIS_ERROR 2
+#define ISIS_CRITICAL 3
+
+/*
+ * IS-IS Circuit Types
+ */
+
+#define IS_LEVEL_1 1
+#define IS_LEVEL_2 2
+#define IS_LEVEL_1_AND_2 3
+
+#define SNPA_ADDRSTRLEN 18
+#define ISIS_SYS_ID_LEN 6
+#define SYSID_STRLEN 24
+
+/*
+ * LSP bit masks
+ */
+#define LSPBIT_P 0x80
+#define LSPBIT_ATT 0x78
+#define LSPBIT_OL 0x04
+#define LSPBIT_IST 0x03
+
+/*
+ * LSP bit masking macros
+ * taken from tcpdumps
+ * print-isoclns.c
+ */
+
+#define ISIS_MASK_LSP_OL_BIT(x) ((x)&0x4)
+#define ISIS_MASK_LSP_IS_L1_BIT(x) ((x)&0x1)
+#define ISIS_MASK_LSP_IS_L2_BIT(x) ((x)&0x2)
+#define ISIS_MASK_LSP_PARTITION_BIT(x) ((x)&0x80)
+#define ISIS_MASK_LSP_ATT_BITS(x) ((x)&0x78)
+#define ISIS_MASK_LSP_ATT_ERROR_BIT(x) ((x)&0x40)
+#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x) ((x)&0x20)
+#define ISIS_MASK_LSP_ATT_DELAY_BIT(x) ((x)&0x10)
+#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x) ((x)&0x8)
+
+#define LLC_LEN 3
+
+/* we need to be aware of the fact we are using ISO sized
+ * packets, using isomtu = mtu - LLC_LEN
+ */
+#define ISO_MTU(C) \
+ (C->circ_type==CIRCUIT_T_BROADCAST) ? \
+ (C->interface->mtu - LLC_LEN) : (C->interface->mtu)
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+#endif /* ISIS_CONSTANTS_H */
+
+
+
+
+
+
+
+
diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c
new file mode 100644
index 00000000..2282bbc8
--- /dev/null
+++ b/isisd/isis_csm.c
@@ -0,0 +1,186 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_csm.c
+ * IS-IS circuit state machine
+ * 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>
+
+#include "log.h"
+#include "memory.h"
+#include "if.h"
+#include "linklist.h"
+#include "command.h"
+#include "thread.h"
+#include "hash.h"
+#include "prefix.h"
+#include "stream.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_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_events.h"
+
+extern struct isis *isis;
+
+static char *csm_statestr[] =
+{
+ "C_STATE_NA",
+ "C_STATE_INIT",
+ "C_STATE_CONF",
+ "C_STATE_UP"
+};
+
+#define STATE2STR(S) csm_statestr[S]
+
+static char *csm_eventstr[] =
+{
+ "NO_STATE",
+ "ISIS_ENABLE",
+ "IF_UP_FROM_Z",
+ "ISIS_DISABLE",
+ "IF_DOWN_FROM_Z",
+};
+
+#define EVENT2STR(E) csm_eventstr[E]
+
+
+struct isis_circuit*
+isis_csm_state_change (int event, struct isis_circuit *circuit,
+ void *arg)
+{
+ int old_state;
+
+ old_state = circuit ? circuit->state : C_STATE_NA;
+
+ zlog_info ("CSM_EVENT: %s", EVENT2STR(event));
+
+ switch (old_state) {
+ case C_STATE_NA:
+ if (circuit)
+ zlog_warn ("Non-null circuit while state C_STATE_NA");
+ switch (event) {
+ case ISIS_ENABLE:
+ circuit = isis_circuit_new ();
+ isis_circuit_configure (circuit, (struct isis_area *)arg);
+ circuit->state = C_STATE_CONF;
+ break;
+ case IF_UP_FROM_Z:
+ circuit = isis_circuit_new ();
+ isis_circuit_if_add (circuit, (struct interface *)arg);
+ listnode_add (isis->init_circ_list, circuit);
+ circuit->state = C_STATE_INIT;
+ break;
+ case ISIS_DISABLE:
+ zlog_warn ("circuit already disabled");
+ case IF_DOWN_FROM_Z:
+ zlog_warn ("circuit already disconnected");
+ break;
+ }
+ break;
+ case C_STATE_INIT:
+ switch (event) {
+ case ISIS_ENABLE:
+ isis_circuit_configure (circuit, (struct isis_area *)arg);
+ isis_circuit_up (circuit);
+ circuit->state = C_STATE_UP;
+ isis_event_circuit_state_change (circuit, 1);
+ listnode_delete (isis->init_circ_list, circuit);
+ break;
+ case IF_UP_FROM_Z:
+ zlog_warn ("circuit already connected");
+ break;
+ case ISIS_DISABLE:
+ zlog_warn ("circuit already disabled");
+ break;
+ case IF_DOWN_FROM_Z:
+ isis_circuit_if_del (circuit);
+ listnode_delete (isis->init_circ_list, circuit);
+ isis_circuit_del (circuit);
+ break;
+ }
+ break;
+ case C_STATE_CONF:
+ switch (event) {
+ case ISIS_ENABLE:
+ zlog_warn ("circuit already enabled");
+ break;
+ case IF_UP_FROM_Z:
+ isis_circuit_if_add (circuit, (struct interface *)arg);
+ isis_circuit_up (circuit);
+ circuit->state = C_STATE_UP;
+ isis_event_circuit_state_change (circuit, 1);
+ break;
+ case ISIS_DISABLE:
+ isis_circuit_deconfigure (circuit, (struct isis_area *)arg);
+ isis_circuit_del (circuit);
+ break;
+ case IF_DOWN_FROM_Z:
+ zlog_warn ("circuit already disconnected");
+ break;
+ }
+ break;
+ case C_STATE_UP:
+ switch (event) {
+ case ISIS_ENABLE:
+ zlog_warn ("circuit already configured");
+ break;
+ case IF_UP_FROM_Z:
+ zlog_warn ("circuit already connected");
+ break;
+ case ISIS_DISABLE:
+ 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_if_del (circuit);
+ circuit->state = C_STATE_CONF;
+ isis_event_circuit_state_change (circuit, 0);
+ break;
+ }
+ break;
+
+ default:
+ zlog_warn ("Invalid circuit state %d", old_state);
+ }
+
+ zlog_info ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state),
+ circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA));
+
+ return circuit;
+}
+
+
+
diff --git a/isisd/isis_csm.h b/isisd/isis_csm.h
new file mode 100644
index 00000000..23cc2150
--- /dev/null
+++ b/isisd/isis_csm.h
@@ -0,0 +1,47 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_csm.h
+ * IS-IS circuit state machine
+ *
+ * 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.
+ */
+#ifndef _ZEBRA_ISIS_CSM_H
+#define _ZEBRA_ISIS_CSM_H
+
+/*
+ * Circuit states
+ */
+#define C_STATE_NA 0
+#define C_STATE_INIT 1 /* Connected to interface */
+#define C_STATE_CONF 2 /* Configured for ISIS */
+#define C_STATE_UP 3 /* CONN | CONF */
+
+/*
+ * Circuit events
+ */
+#define ISIS_ENABLE 1
+#define IF_UP_FROM_Z 2
+#define ISIS_DISABLE 3
+#define IF_DOWN_FROM_Z 4
+
+struct isis_circuit *isis_csm_state_change (int event,
+ struct isis_circuit *circuit,
+ void *arg);
+
+#endif /* _ZEBRA_ISIS_CSM_H */
diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c
new file mode 100644
index 00000000..5b7d23e6
--- /dev/null
+++ b/isisd/isis_dr.c
@@ -0,0 +1,373 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_dr.c
+ * IS-IS designated router related routines
+ *
+ * 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>
+
+#include "log.h"
+#include "hash.h"
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "stream.h"
+#include "if.h"
+
+#include "isisd/dict.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_events.h"
+
+extern struct isis *isis;
+extern struct thread_master *master;
+
+char *
+isis_disflag2string (int disflag) {
+
+ switch (disflag) {
+ case ISIS_IS_NOT_DIS:
+ return "is not DIS";
+ case ISIS_IS_DIS:
+ return "is DIS";
+ case ISIS_WAS_DIS:
+ return "was DIS";
+ default:
+ return "unknown DIS state";
+ }
+ return NULL; /* not reached */
+}
+
+
+
+int
+isis_run_dr_l1 (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ if (circuit->u.bc.run_dr_elect[0])
+ zlog_warn ("isis_run_dr(): run_dr_elect already set for l1");
+
+ circuit->u.bc.run_dr_elect[0] = 1;
+
+ return ISIS_OK;
+}
+
+int
+isis_run_dr_l2 (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ if (circuit->u.bc.run_dr_elect[1])
+ zlog_warn ("isis_run_dr(): run_dr_elect already set for l2");
+
+
+ circuit->u.bc.run_dr_elect[1] = 1;
+
+ return ISIS_OK;
+}
+
+int
+isis_check_dr_change (struct isis_adjacency *adj, int level)
+{
+ int i;
+
+ if ( adj->dis_record[level-1].dis !=
+ adj->dis_record[(1*ISIS_LEVELS) + level - 1].dis)
+ /* was there a DIS state transition ? */
+ {
+ adj->dischanges[level-1]++;
+ /* ok rotate the history list through */
+ for (i = DIS_RECORDS - 1; i > 0; i--)
+ {
+ adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
+ adj->dis_record[((i-1) * ISIS_LEVELS) + level - 1].dis;
+ adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change =
+ adj->dis_record[((i-1) * ISIS_LEVELS) + level - 1].last_dis_change;
+ }
+ }
+ return ISIS_OK;
+}
+
+int
+isis_dr_elect (struct isis_circuit *circuit, int level)
+{
+ struct list *adjdb;
+ struct listnode *node;
+ struct isis_adjacency *adj, *adj_dr = NULL;
+ struct list *list = list_new ();
+ u_char own_prio;
+ int biggest_prio = -1;
+ int cmp_res, retval = ISIS_OK;
+
+ own_prio = circuit->u.bc.priority[level - 1];
+ adjdb = circuit->u.bc.adjdb[level - 1];
+
+ if (!adjdb) {
+ zlog_warn ("isis_dr_elect() adjdb == NULL");
+ retval = ISIS_WARNING;
+ list_delete (list);
+ goto out;
+ }
+ isis_adj_build_up_list (adjdb, list);
+
+ /*
+ * Loop the adjacencies and find the one with the biggest priority
+ */
+ for (node = listhead (list); node; nextnode (node)) {
+ adj = getdata (node);
+ /* clear flag for show output */
+ adj->dis_record[level-1].dis = ISIS_IS_NOT_DIS;
+ adj->dis_record[level-1].last_dis_change = time (NULL);
+
+ if (adj->prio[level-1] > biggest_prio) {
+ biggest_prio = adj->prio[level-1];
+ adj_dr = adj;
+ } else if (adj->prio[level-1] == biggest_prio) {
+ /*
+ * Comparison of MACs breaks a tie
+ */
+ if (adj_dr) {
+ cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN);
+ if (cmp_res < 0) {
+ adj_dr = adj;
+ }
+ if (cmp_res == 0)
+ zlog_warn ("isis_dr_elect(): multiple adjacencies with same SNPA");
+ } else {
+ adj_dr = adj;
+ }
+ }
+ }
+
+ if (!adj_dr) {
+ /*
+ * Could not find the DR - means we are alone and thus the DR
+ */
+ if ( !circuit->u.bc.is_dr[level - 1]) {
+ list_delete (list);
+ list = NULL;
+ return isis_dr_commence (circuit, level);
+ }
+ goto out;
+ }
+
+ /*
+ * Now we have the DR adjacency, compare it to self
+ */
+ if (adj_dr->prio[level-1] < own_prio || (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 -> commence
+ */
+ list_delete (list);
+ return isis_dr_commence (circuit, level);
+ }
+ } else {
+
+ /* ok we have found the DIS - lets mark the adjacency */
+ /* set flag for show output */
+ adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
+ adj_dr->dis_record[level - 1].last_dis_change = time(NULL);
+
+ /* now loop through a second time to check if there has been a DIS change
+ * if yes rotate the history log
+ */
+
+ for (node = listhead (list); node; nextnode (node)) {
+ adj = getdata (node);
+ isis_check_dr_change(adj, level);
+ }
+
+ /*
+ * We are not DR - if we were -> resign
+ */
+
+ if (circuit->u.bc.is_dr[level - 1]) {
+ list_delete (list);
+ return isis_dr_resign (circuit, level);
+ }
+ }
+ out:
+ if (list)
+ list_delete (list);
+ return retval;
+}
+
+int
+isis_dr_resign (struct isis_circuit *circuit, int level)
+{
+ u_char id[ISIS_SYS_ID_LEN + 2];
+
+ zlog_info ("isis_dr_resign l%d", level);
+
+ circuit->u.bc.is_dr[level - 1] = 0;
+ circuit->u.bc.run_dr_elect[level - 1] = 0;
+ if (circuit->u.bc.t_run_dr[level - 1]) {
+ thread_cancel (circuit->u.bc.t_run_dr[level - 1]);
+ circuit->u.bc.t_run_dr[level - 1] = NULL;
+ }
+ if (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]) {
+ thread_cancel (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+ circuit->u.bc.t_refresh_pseudo_lsp[level - 1] = NULL;
+ }
+
+ memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID(id) = circuit->circuit_id;
+ LSP_FRAGMENT(id) = 0;
+ lsp_purge_dr (id, circuit, level);
+
+ if (level == 1) {
+ memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
+
+ if (circuit->t_send_csnp[0])
+ thread_cancel (circuit->t_send_csnp[0]);
+
+ circuit->u.bc.t_run_dr[0] =
+ thread_add_timer (master, isis_run_dr_l1, circuit,
+ 2 * circuit->hello_interval[1]);
+
+ circuit->t_send_psnp[0] =
+ thread_add_timer (master,
+ send_l1_psnp,
+ circuit,
+ isis_jitter (circuit->psnp_interval[level - 1],
+ PSNP_JITTER));
+ } else {
+ memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
+
+ if (circuit->t_send_csnp[0])
+ thread_cancel (circuit->t_send_csnp[0]);
+
+ circuit->u.bc.t_run_dr[1] =
+ thread_add_timer (master, isis_run_dr_l2, circuit,
+ 2 * circuit->hello_interval[1]);
+ circuit->t_send_psnp[1] =
+ thread_add_timer (master,
+ send_l2_psnp,
+ circuit,
+ isis_jitter (circuit->psnp_interval[level - 1],
+ PSNP_JITTER));
+ }
+
+ thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+
+ return ISIS_OK;
+}
+
+int
+isis_dr_commence (struct isis_circuit *circuit, int level)
+{
+ u_char old_dr[ISIS_SYS_ID_LEN + 2];
+
+ zlog_info ("isis_dr_commence l%d", level);
+
+ /* Lets keep a pause in DR election */
+ circuit->u.bc.run_dr_elect[level - 1] = 0;
+ if (level == 1)
+ circuit->u.bc.t_run_dr[0] =
+ thread_add_timer (master, isis_run_dr_l1, circuit,
+ 2 * circuit->hello_multiplier[0] *
+ circuit->hello_interval[0]);
+ else
+ circuit->u.bc.t_run_dr[1] =
+ thread_add_timer (master, isis_run_dr_l2, circuit,
+ 2 * circuit->hello_multiplier[1] *
+ circuit->hello_interval[1]);
+ circuit->u.bc.is_dr[level - 1] = 1;
+
+ if (level == 1) {
+ memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
+ LSP_FRAGMENT (old_dr) = 0;
+ if (LSP_PSEUDO_ID(old_dr)) {
+ /* there was a dr elected, purge its LSPs from the db */
+ lsp_purge_dr (old_dr, circuit, level);
+ }
+ memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
+ *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
+
+ assert (circuit->circuit_id); /* must be non-zero */
+ /* if (circuit->t_send_l1_psnp)
+ thread_cancel (circuit->t_send_l1_psnp); */
+ lsp_l1_pseudo_generate (circuit);
+
+ circuit->u.bc.t_run_dr[0] =
+ thread_add_timer (master, isis_run_dr_l1, circuit,
+ 2 * circuit->hello_interval[0]);
+
+ circuit->t_send_csnp[0] = thread_add_timer (master,
+ send_l1_csnp,
+ circuit,
+ isis_jitter
+ (circuit->csnp_interval[level-1],
+ CSNP_JITTER));
+ } else {
+ memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
+ LSP_FRAGMENT (old_dr) = 0;
+ if (LSP_PSEUDO_ID(old_dr)) {
+ /* there was a dr elected, purge its LSPs from the db */
+ lsp_purge_dr (old_dr, circuit, level);
+ }
+ memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
+ *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
+
+ assert (circuit->circuit_id); /* must be non-zero */
+ /* if (circuit->t_send_l1_psnp)
+ thread_cancel (circuit->t_send_l1_psnp); */
+ lsp_l2_pseudo_generate (circuit);
+
+ circuit->u.bc.t_run_dr[1] =
+ thread_add_timer (master, isis_run_dr_l2, circuit,
+ 2 * circuit->hello_interval[1]);
+
+ circuit->t_send_csnp[1] =
+ thread_add_timer (master,
+ send_l2_csnp,
+ circuit,
+ isis_jitter (circuit->csnp_interval[level-1],
+ CSNP_JITTER));
+
+ }
+
+ thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+
+ return ISIS_OK;
+}
+
diff --git a/isisd/isis_dr.h b/isisd/isis_dr.h
new file mode 100644
index 00000000..73d9cd38
--- /dev/null
+++ b/isisd/isis_dr.h
@@ -0,0 +1,42 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_dr.h
+ * IS-IS designated router related routines
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_DR_H
+#define _ZEBRA_ISIS_DR_H
+
+int isis_run_dr_l1 (struct thread *thread);
+int isis_run_dr_l2 (struct thread *thread);
+int isis_dr_elect (struct isis_circuit *circuit, int level);
+int isis_dr_resign (struct isis_circuit *circuit, int level);
+int isis_dr_commence (struct isis_circuit *circuit, int level);
+char *isis_disflag2string (int disflag);
+
+enum isis_dis_state {
+ ISIS_IS_NOT_DIS,
+ ISIS_IS_DIS,
+ ISIS_WAS_DIS,
+ ISIS_UNKNOWN_DIS
+};
+
+#endif /* _ZEBRA_ISIS_DR_H */
+
diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c
new file mode 100644
index 00000000..9e151d0a
--- /dev/null
+++ b/isisd/isis_dynhn.c
@@ -0,0 +1,124 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_dynhn.c
+ * Dynamic hostname cache
+ * 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 <time.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "vty.h"
+#include "linklist.h"
+#include "memory.h"
+#include "log.h"
+#include "stream.h"
+#include "command.h"
+#include "if.h"
+
+#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_dynhn.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+
+extern struct isis *isis;
+extern struct host host;
+
+struct list *dyn_cache = NULL;
+
+void
+dyn_cache_init (void)
+{
+ dyn_cache = list_new ();
+
+ return;
+}
+
+struct isis_dynhn *dynhn_find_by_id (u_char * id)
+{
+ struct listnode *node = NULL;
+ struct isis_dynhn *dyn = NULL;
+
+ for (node = listhead (dyn_cache); node; nextnode (node)) {
+ dyn = getdata (node);
+ if (memcmp (dyn->id, id, ISIS_SYS_ID_LEN) == 0)
+ return dyn;
+ }
+
+ return NULL;
+}
+
+void
+isis_dynhn_insert (u_char *id, struct hostname *hostname, int level)
+{
+ struct isis_dynhn *dyn;
+
+ dyn = dynhn_find_by_id (id);
+ if (dyn) {
+ memcpy (&dyn->name, hostname, hostname->namelen + 1);
+ memcpy (dyn->id, id, ISIS_SYS_ID_LEN);
+ dyn->refresh = time (NULL);
+ return;
+ }
+ dyn = XMALLOC (MTYPE_ISIS_DYNHN, sizeof (struct isis_dynhn));
+ if (!dyn) {
+ zlog_warn ("isis_dynhn_insert(): out of memory!");
+ return;
+ }
+ memset (dyn,0,sizeof(struct isis_dynhn));
+ /* we also copy the length */
+ memcpy (&dyn->name, hostname, hostname->namelen + 1);
+ memcpy (dyn->id, id, ISIS_SYS_ID_LEN);
+ dyn->refresh = time (NULL);
+ dyn->level = level;
+
+ listnode_add (dyn_cache, dyn);
+
+ return;
+}
+
+/*
+ * Level System ID Dynamic Hostname (notag)
+ * 2 0000.0000.0001 foo-gw
+ * 2 0000.0000.0002 bar-gw
+ * * 0000.0000.0004 this-gw
+ */
+void dynhn_print_all (struct vty *vty)
+{
+ struct listnode *node;
+ struct isis_dynhn *dyn;
+
+ vty_out (vty, "Level System ID Dynamic Hostname%s", VTY_NEWLINE);
+ for (node = listhead (dyn_cache); node; nextnode (node)) {
+ dyn = getdata (node);
+ vty_out (vty, "%-7d", dyn->level);
+ vty_out (vty, "%-15s%-15s%s", sysid_print (dyn->id), dyn->name.name,
+ VTY_NEWLINE);
+ }
+
+ vty_out (vty, " * %s %s%s", sysid_print (isis->sysid), host.name,
+ VTY_NEWLINE);
+ return;
+}
+
diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h
new file mode 100644
index 00000000..2a7f3ec9
--- /dev/null
+++ b/isisd/isis_dynhn.h
@@ -0,0 +1,42 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_dynhn.h
+ * Dynamic hostname cache
+ *
+ * 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.
+ */
+#ifndef _ZEBRA_ISIS_DYNHN_H
+#define _ZEBRA_ISIS_DYNHN_H
+
+struct isis_dynhn {
+ u_char id[ISIS_SYS_ID_LEN];
+ struct hostname name;
+ time_t refresh;
+ int level;
+};
+
+void dyn_cache_init (void);
+void isis_dynhn_insert (u_char *id, struct hostname *hostname, int level);
+struct isis_dynhn *dynhn_find_by_id (u_char * id);
+void dynhn_print_all (struct vty *vty);
+
+#endif /* _ZEBRA_ISIS_DYNHN_H */
+
+
+
+
diff --git a/isisd/isis_events.c b/isisd/isis_events.c
new file mode 100644
index 00000000..aada395d
--- /dev/null
+++ b/isisd/isis_events.c
@@ -0,0 +1,336 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_events.h
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "log.h"
+#include "memory.h"
+#include "if.h"
+#include "linklist.h"
+#include "command.h"
+#include "thread.h"
+#include "hash.h"
+#include "prefix.h"
+#include "stream.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_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_events.h"
+#include "isisd/isis_spf.h"
+
+extern struct thread_master *master;
+extern struct isis *isis;
+
+/* debug isis-spf spf-events
+ 4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4
+ 4w4d: ISIS-Spf (tlt): L2, 0000.0000.0042.01-00 TLV contents changed, code 0x2
+ 4w4d: ISIS-Spf (tlt): L2, new LSP 0 DEAD.BEEF.0043.00-00
+ 4w5d: ISIS-Spf (tlt): L1 SPF needed, periodic SPF, from 0x6091C844
+ 4w5d: ISIS-Spf (tlt): L2 SPF needed, periodic SPF, from 0x6091C844
+*/
+
+void
+isis_event_circuit_state_change (struct isis_circuit *circuit, int up)
+{
+ struct isis_area *area;
+
+ area = circuit->area;
+ assert (area);
+ area->circuit_state_changes++;
+
+ if (isis->debugs & DEBUG_EVENTS)
+ zlog_info ("ISIS-Evt (%s) circuit %s", circuit->area->area_tag,
+ up ? "up" : "down");
+
+ /*
+ * Regenerate LSPs this affects
+ */
+ lsp_regenerate_schedule (area);
+
+ return;
+}
+
+void
+isis_event_system_type_change (struct isis_area *area, int newtype)
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ if (isis->debugs & DEBUG_EVENTS)
+ zlog_info ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag,
+ circuit_t2string (area->is_type), circuit_t2string (newtype));
+
+ if (area->is_type == newtype)
+ return; /* No change */
+
+ switch (area->is_type) {
+ case IS_LEVEL_1:
+ if (area->lspdb[1] == NULL)
+ area->lspdb[1] = lsp_db_init ();
+ lsp_l2_generate (area);
+ break;
+ case IS_LEVEL_1_AND_2:
+ if (newtype == IS_LEVEL_1) {
+ lsp_db_destroy (area->lspdb[1]);
+ }
+ else {
+ lsp_db_destroy (area->lspdb[0]);
+ }
+ break;
+ case IS_LEVEL_2:
+ if (area->lspdb[0] == NULL)
+ area->lspdb[0] = lsp_db_init ();
+ lsp_l1_generate (area);
+ break;
+ default:
+ break;
+ }
+
+ area->is_type = newtype;
+ for (node = listhead (area->circuit_list); node; nextnode (node)) {
+ circuit = getdata (node);
+ isis_event_circuit_type_change (circuit, newtype);
+ }
+
+ spftree_area_init (area);
+ lsp_regenerate_schedule (area);
+
+ return;
+}
+
+
+
+void
+isis_event_area_addr_change (struct isis_area *area)
+{
+
+}
+
+void
+circuit_commence_level (struct isis_circuit *circuit, int level)
+{
+ uint32_t interval;
+
+ if (level == 1) {
+ circuit->t_send_psnp[0] = thread_add_timer (master, send_l1_psnp,
+ circuit,
+ isis_jitter
+ (circuit->psnp_interval[0],
+ PSNP_JITTER));
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ interval = circuit->hello_multiplier[0] * (circuit->hello_interval[0]);
+ circuit->u.bc.t_run_dr[0] = thread_add_timer (master, isis_run_dr_l1,
+ circuit, interval);
+
+ circuit->u.bc.t_send_lan_hello[0] =
+ thread_add_timer (master,
+ send_lan_l1_hello,
+ circuit,
+ isis_jitter
+ (circuit->hello_interval[0], IIH_JITTER));
+ circuit->u.bc.lan_neighs[0] = list_new ();
+ }
+ } else {
+ circuit->t_send_psnp[1] = thread_add_timer (master, send_l2_psnp,
+ circuit,
+ isis_jitter
+ (circuit->psnp_interval[1],
+ PSNP_JITTER));
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ interval = circuit->hello_multiplier[1] * (circuit->hello_interval[1]);
+ circuit->u.bc.t_run_dr[1] = thread_add_timer (master, isis_run_dr_l2,
+ circuit, interval);
+
+ circuit->u.bc.t_send_lan_hello[1] =
+ thread_add_timer (master,
+ send_lan_l2_hello,
+ circuit,
+ isis_jitter
+ (circuit->hello_interval[1], IIH_JITTER));
+ circuit->u.bc.lan_neighs[1] = list_new ();
+ }
+ }
+
+ return;
+}
+
+void
+circuit_resign_level (struct isis_circuit *circuit, int level)
+{
+ int idx = level - 1;
+
+ if (circuit->t_send_csnp[idx])
+ thread_cancel (circuit->t_send_csnp[idx]);
+ circuit->t_send_csnp[idx] = NULL;
+
+ if (circuit->t_send_psnp[idx])
+ thread_cancel (circuit->t_send_psnp[idx]);
+ circuit->t_send_psnp[level - 1] = NULL;
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ if (circuit->u.bc.t_send_lan_hello[idx])
+ thread_cancel (circuit->u.bc.t_send_lan_hello[idx]);
+ circuit->u.bc.t_send_lan_hello[idx] = NULL;
+ if (circuit->u.bc.t_run_dr[idx])
+ thread_cancel (circuit->u.bc.t_run_dr[idx]);
+ circuit->u.bc.t_run_dr[idx] = NULL;
+ circuit->u.bc.run_dr_elect[idx] = 0;
+ }
+
+ return;
+}
+
+void
+isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)
+{
+
+ if (isis->debugs & DEBUG_EVENTS)
+ zlog_info ("ISIS-Evt (%s) circuit type change %s -> %s",
+ circuit->area->area_tag,
+ circuit_t2string (circuit->circuit_is_type),
+ circuit_t2string (newtype));
+
+ if (circuit->circuit_is_type == newtype)
+ return; /* No change */
+
+ if (!(newtype & circuit->area->is_type)) {
+ zlog_err ("ISIS-Evt (%s) circuit type change - invalid level %s because"
+ " area is %s", circuit->area->area_tag,
+ circuit_t2string (newtype),
+ circuit_t2string (circuit->area->is_type));
+ return;
+ }
+
+ switch (circuit->circuit_is_type) {
+ case IS_LEVEL_1:
+ if (newtype == IS_LEVEL_2)
+ circuit_resign_level (circuit, 1);
+ circuit_commence_level (circuit, 2);
+ break;
+ case IS_LEVEL_1_AND_2:
+ if (newtype == IS_LEVEL_1)
+ circuit_resign_level (circuit, 2);
+ else
+ circuit_resign_level (circuit, 1);
+ break;
+ case IS_LEVEL_2:
+ if (newtype == IS_LEVEL_1)
+ circuit_resign_level (circuit, 2);
+ circuit_commence_level (circuit, 1);
+ break;
+ default:
+ break;
+ }
+
+ circuit->circuit_is_type = newtype;
+ lsp_regenerate_schedule (circuit->area);
+
+ return;
+}
+
+ /* 04/18/2002 by Gwak. */
+ /**************************************************************************
+ *
+ * EVENTS for LSP generation
+ *
+ * 1) an Adajacency or Circuit Up/Down event
+ * 2) a chnage in Circuit metric
+ * 3) a change in Reachable Address metric
+ * 4) a change in manualAreaAddresses
+ * 5) a change in systemID
+ * 6) a change in DIS status
+ * 7) a chnage in the waiting status
+ *
+ * ***********************************************************************
+ *
+ * current support event
+ *
+ * 1) Adjacency Up/Down event
+ * 6) a change in DIS status
+ *
+ * ***********************************************************************/
+
+void
+isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate)
+{
+ /* adjacency state change event.
+ * - the only proto-type was supported */
+
+ /* invalid arguments */
+ if ( !adj || !adj->circuit || !adj->circuit->area ) return;
+
+ zlog_info ("ISIS-Evt (%s) Adjacency State change",
+ adj->circuit->area->area_tag );
+
+ /* LSP generation again */
+ lsp_regenerate_schedule (adj->circuit->area);
+
+ return;
+}
+
+/* events supporting code */
+
+int
+isis_event_dis_status_change (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+
+ circuit = THREAD_ARG (thread);
+
+ /* invalid arguments */
+ if (!circuit || !circuit->area) return 0;
+
+ zlog_info ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag);
+
+ /* LSP generation again */
+ lsp_regenerate_schedule (circuit->area);
+
+ return 0;
+}
+
+
+void
+isis_event_auth_failure (char *area_tag, char *error_string, char *sysid)
+{
+ zlog_info ("ISIS-Evt (%s) Authentication failure %s from %s",
+ area_tag, error_string, sysid_print (sysid));
+
+ return;
+}
+
diff --git a/isisd/isis_events.h b/isisd/isis_events.h
new file mode 100644
index 00000000..75dd92e8
--- /dev/null
+++ b/isisd/isis_events.h
@@ -0,0 +1,54 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_events.h
+ *
+ * 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.
+ */
+#ifndef _ZEBRA_ISIS_EVENTS_H
+#define _ZEBRA_ISIS_EVENTS_H
+
+/*
+ * Events related to area
+ */
+void isis_event_system_type_change (struct isis_area *area, int newtype);
+void isis_event_area_addr_change (struct isis_area *area);
+
+/*
+ * Events related to circuit
+ */
+void isis_event_circuit_state_change (struct isis_circuit *circuit, int state);
+void isis_event_circuit_type_change (struct isis_circuit *circuit,
+ int newtype);
+/*
+ * Events related to adjacencies
+ */
+void isis_event_adjacency_state_change(struct isis_adjacency *adj,
+ int newstate);
+
+int isis_event_dis_status_change (struct thread *thread);
+
+/*
+ * Error events
+ */
+#define AUTH_ERROR_TYPE_LSP 3
+#define AUTH_ERROR_TYPE_SNP 2
+#define AUTH_ERROR_TYPE_HELLO 1
+void isis_event_auth_failure (char *area_tag, char *error_string, char *sysid);
+
+#endif /* _ZEBRA_ISIS_EVENTS_H */
+
diff --git a/isisd/isis_flags.c b/isisd/isis_flags.c
new file mode 100644
index 00000000..716bee05
--- /dev/null
+++ b/isisd/isis_flags.c
@@ -0,0 +1,71 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_flags.c
+ * Routines for manipulation of SSN and SRM flags
+ *
+ * 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 "log.h"
+#include "linklist.h"
+
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+
+int
+flags_get_index (struct flags *flags)
+{
+ struct listnode *node;
+ int index;
+
+ if (flags->free_idcs == NULL || flags->free_idcs->count == 0) {
+ flags->maxindex++;
+ index = flags->maxindex;
+ } else {
+ node = listhead (flags->free_idcs);
+ index = (int) getdata (node);
+ listnode_delete (flags->free_idcs, (void *)index);
+ }
+
+ return index;
+}
+
+void
+flags_free_index (struct flags *flags, int index)
+{
+ if (flags->free_idcs == NULL) {
+ flags->free_idcs = list_new ();
+ }
+
+ listnode_add (flags->free_idcs, (void *)index);
+
+ return;
+}
+
+int
+flags_any_set (u_int32_t *flags)
+{
+
+ u_int32_t zero[ISIS_MAX_CIRCUITS];
+ memset (zero, 0x00, ISIS_MAX_CIRCUITS*4);
+
+ return bcmp(flags, zero, ISIS_MAX_CIRCUITS*4);
+}
diff --git a/isisd/isis_flags.h b/isisd/isis_flags.h
new file mode 100644
index 00000000..66b94848
--- /dev/null
+++ b/isisd/isis_flags.h
@@ -0,0 +1,58 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_flags.h
+ * Routines for manipulation of SSN and SRM flags
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_FLAGS_H
+#define _ZEBRA_ISIS_FLAGS_H
+
+/* 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*/
+
+struct flags *new_flags (int size);
+int flags_get_index (struct flags *flags);
+void flags_free_index (struct flags *flags, int index);
+
+int flags_any_set (u_int32_t *flags);
+
+#define ISIS_SET_FLAG(F,C) \
+ F[C->idx>>5] |= (1<<(C->idx & 0x1F));
+
+#define ISIS_CLEAR_FLAG(F,C) \
+ F[C->idx>>5] &= ~(1<<(C->idx & 0x1F));
+
+#define ISIS_CHECK_FLAG(F, C) F[(C)->idx>>5] & (1<<(C->idx & 0x1F))
+
+/* sets all u_32int_t flags to 1 */
+#define ISIS_FLAGS_SET_ALL(FLAGS) \
+ memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4);
+
+#define ISIS_FLAGS_CLEAR_ALL(FLAGS) \
+ memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4);
+
+#endif /* _ZEBRA_ISIS_FLAGS_H */
+
+
+
+
+
+
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
new file mode 100644
index 00000000..6bfb0fd4
--- /dev/null
+++ b/isisd/isis_lsp.c
@@ -0,0 +1,2419 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_lsp.c
+ * LSP processing
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "linklist.h"
+#include "thread.h"
+#include "vty.h"
+#include "stream.h"
+#include "memory.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "hash.h"
+#include "if.h"
+
+#include "isisd/dict.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#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"
+
+#ifdef TOPOLOGY_GENERATE
+#include "spgrid.h"
+#endif
+
+#define LSP_MEMORY_PREASSIGN
+
+extern struct isis *isis;
+extern struct thread_master *master;
+extern struct host host;
+
+int
+lsp_id_cmp (u_char *id1, u_char *id2)
+{
+ return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2);
+}
+
+dict_t *
+lsp_db_init (void)
+{
+ dict_t *dict;
+
+ dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t)lsp_id_cmp);
+
+ return dict;
+}
+
+struct isis_lsp *
+lsp_search (u_char *id, dict_t *lspdb)
+{
+ dnode_t *node;
+
+#ifdef EXTREME_DEBUG
+ dnode_t *dn;
+
+ zlog_warn("searching db");
+ for (dn = dict_first(lspdb); dn; dn = dict_next(lspdb, dn)) {
+ zlog_warn("%s\t%pX", rawlspid_print((char *) dnode_getkey(dn)),
+ dnode_get(dn));
+ }
+#endif /* EXTREME DEBUG */
+
+ node = dict_lookup (lspdb, id);
+
+ if (node)
+ return (struct isis_lsp *)dnode_get (node);
+
+ return NULL;
+}
+
+void
+lsp_clear_data (struct isis_lsp *lsp)
+{
+ if (!lsp)
+ return;
+
+ if (lsp->own_lsp) {
+ if (lsp->tlv_data.nlpids)
+ XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
+ if (lsp->tlv_data.hostname)
+ XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
+ }
+ if (lsp->tlv_data.is_neighs)
+ list_delete (lsp->tlv_data.is_neighs);
+ if (lsp->tlv_data.area_addrs)
+ list_delete (lsp->tlv_data.area_addrs);
+ if (lsp->tlv_data.es_neighs)
+ list_delete (lsp->tlv_data.es_neighs);
+ if (lsp->tlv_data.ipv4_addrs)
+ list_delete (lsp->tlv_data.ipv4_addrs);
+ if (lsp->tlv_data.ipv4_int_reachs)
+ list_delete (lsp->tlv_data.ipv4_int_reachs);
+ if (lsp->tlv_data.ipv4_ext_reachs)
+ list_delete (lsp->tlv_data.ipv4_ext_reachs);
+#ifdef HAVE_IPV6
+ if (lsp->tlv_data.ipv6_addrs)
+ list_delete (lsp->tlv_data.ipv6_addrs);
+ if (lsp->tlv_data.ipv6_reachs)
+ list_delete (lsp->tlv_data.ipv6_reachs);
+#endif /* HAVE_IPV6 */
+
+ memset (&lsp->tlv_data, 0, sizeof (struct tlvs));
+
+ return;
+}
+
+void
+lsp_destroy (struct isis_lsp *lsp)
+{
+ if (!lsp)
+ return;
+
+ lsp_clear_data (lsp);
+
+ if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) {
+ list_delete (lsp->lspu.frags);
+ }
+
+ if (lsp->pdu)
+ stream_free (lsp->pdu);
+ XFREE (MTYPE_ISIS_LSP, lsp);
+}
+
+void
+lsp_db_destroy (dict_t *lspdb)
+{
+ dnode_t *dnode, *next;
+ struct isis_lsp *lsp;
+
+ dnode = dict_first (lspdb);
+ while (dnode) {
+ next = dict_next (lspdb, dnode);
+ lsp = dnode_get (dnode);
+ lsp_destroy (lsp);
+ dict_delete_free (lspdb, dnode);
+ dnode = next;
+ }
+
+ dict_free (lspdb);
+
+ return;
+}
+
+/*
+ * Remove all the frags belonging to the given lsp
+ */
+void
+lsp_remove_frags (struct list *frags, dict_t *lspdb)
+{
+ dnode_t *dnode;
+ struct listnode *lnode;
+ struct isis_lsp *lsp;
+
+ for (lnode = listhead (frags); lnode; nextnode (lnode)) {
+ lsp = getdata (lnode);
+ dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
+ lsp_destroy (lsp);
+ dnode_destroy (dict_delete(lspdb, dnode));
+ }
+
+ list_delete_all_node (frags);
+
+ return;
+}
+
+void
+lsp_search_and_destroy (u_char *id, dict_t *lspdb)
+{
+ dnode_t *node;
+ struct isis_lsp *lsp;
+
+ node = dict_lookup (lspdb, id);
+ if (node) {
+ node = dict_delete (lspdb, node);
+ lsp = dnode_get (node);
+ /*
+ * If this is a zero lsp, remove all the frags now
+ */
+ if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0) {
+ if (lsp->lspu.frags)
+ lsp_remove_frags (lsp->lspu.frags, lspdb);
+ } else {
+ /*
+ * else just remove this frag, from the zero lsps' frag list
+ */
+ if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
+ listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
+ }
+ lsp_destroy (lsp);
+ dnode_destroy (node);
+ }
+}
+
+/*
+ * Compares a LSP to given values
+ * Params are given in net order
+ */
+int
+lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
+ u_int16_t checksum, u_int16_t rem_lifetime)
+{
+ /* no point in double ntohl on seqnum */
+ if (lsp->lsp_header->seq_num == seq_num &&
+ lsp->lsp_header->checksum == checksum &&
+ /*comparing with 0, no need to do ntohl */
+ ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
+ (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) {
+ if (isis->debugs & DEBUG_SNP_PACKETS) {
+ zlog_info ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
+ " lifetime %us",
+ areatag,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl(lsp->lsp_header->seq_num),
+ ntohs(lsp->lsp_header->checksum),
+ ntohs(lsp->lsp_header->rem_lifetime) );
+ zlog_info ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
+ " cksum 0x%04x, lifetime %us",
+ areatag,
+ ntohl(seq_num),
+ ntohs(checksum),
+ ntohs(rem_lifetime));
+ }
+ return LSP_EQUAL;
+ }
+
+ if (ntohl(seq_num) >= ntohl(lsp->lsp_header->seq_num)) {
+ if (isis->debugs & DEBUG_SNP_PACKETS) {
+ zlog_info ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
+ " lifetime %us",
+ areatag,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl(seq_num),
+ ntohs(checksum),
+ ntohs(rem_lifetime ));
+ zlog_info ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
+ "cksum 0x%04x, lifetime %us",
+ areatag,
+ ntohl(lsp->lsp_header->seq_num),
+ ntohs(lsp->lsp_header->checksum),
+ ntohs(lsp->lsp_header->rem_lifetime) );
+ }
+ return LSP_NEWER;
+ }
+ if (isis->debugs & DEBUG_SNP_PACKETS) {
+ zlog_info ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
+ areatag,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl(seq_num),
+ ntohs(checksum),
+ ntohs(rem_lifetime ));
+ zlog_info ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
+ " cksum 0x%04x, lifetime %us",
+ areatag,
+ ntohl(lsp->lsp_header->seq_num),
+ ntohs(lsp->lsp_header->checksum),
+ ntohs(lsp->lsp_header->rem_lifetime) );
+ }
+
+ return LSP_OLDER;
+}
+
+void
+lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
+{
+ u_int32_t newseq;
+
+ if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
+ newseq = ntohl (lsp->lsp_header->seq_num) + 1;
+ else
+ newseq = seq_num ++;
+
+ lsp->lsp_header->seq_num = htonl (newseq);
+ iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+ ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+
+ return;
+}
+
+/*
+ * Genetates checksum for LSP and its frags
+ */
+void
+lsp_seqnum_update (struct isis_lsp *lsp0)
+{
+ struct isis_lsp *lsp;
+ struct listnode *node;
+
+ lsp_inc_seqnum (lsp0, 0);
+
+ if (!lsp0->lspu.frags)
+ return;
+
+ for (node = listhead (lsp0->lspu.frags); node; nextnode (node)) {
+ lsp = getdata (node);
+ lsp_inc_seqnum(lsp, 0);
+ }
+
+ return;
+}
+
+int
+isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
+ int pdulen, struct isis_passwd *passwd)
+{
+ uint32_t expected = 0, found;
+ struct tlvs tlvs;
+ int retval = 0;
+
+ expected |= TLVFLAG_AUTH_INFO;
+ retval = parse_tlvs (area->area_tag, stream->data +
+ ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
+ pdulen - ISIS_FIXED_HDR_LEN
+ - ISIS_LSP_HDR_LEN,
+ &expected, &found, &tlvs);
+ if (retval || !(found & TLVFLAG_AUTH_INFO))
+ return 1; /* Auth fail (parsing failed or no auth-tlv)*/
+
+ return authentication_check (passwd, &tlvs.auth_info);
+}
+
+void
+lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
+ struct isis_area *area)
+{
+ uint32_t expected = 0,found;
+ int retval;
+
+ /* copying only the relevant part of our stream */
+ lsp->pdu = stream_new (stream->endp);
+ lsp->pdu->putp = stream->putp;
+ lsp->pdu->getp = stream->getp;
+ lsp->pdu->endp = stream->endp;
+ memcpy (lsp->pdu->data, stream->data, stream->endp);
+
+ /* setting pointers to the correct place */
+ lsp->isis_header = (struct isis_fixed_hdr *)(STREAM_DATA(lsp->pdu));
+ lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu) +
+ ISIS_FIXED_HDR_LEN);
+ lsp->age_out = ZERO_AGE_LIFETIME;
+ lsp->installed = time(NULL);
+ /*
+ * Get LSP data i.e. TLVs
+ */
+ expected |= TLVFLAG_AUTH_INFO;
+ expected |= TLVFLAG_AREA_ADDRS;
+ expected |= TLVFLAG_IS_NEIGHS;
+ if ((lsp->lsp_header->lsp_bits & 3) == 3) /* a level 2 LSP */
+ expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS;
+ expected |= TLVFLAG_NLPID;
+ if (area->dynhostname)
+ expected |= TLVFLAG_DYN_HOSTNAME;
+ if (area->newmetric) {
+ expected |= TLVFLAG_TE_IS_NEIGHS;
+ expected |= TLVFLAG_TE_IPV4_REACHABILITY;
+ expected |= TLVFLAG_TE_ROUTER_ID;
+ }
+ expected |= TLVFLAG_IPV4_ADDR;
+ expected |= TLVFLAG_IPV4_INT_REACHABILITY;
+ expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
+#ifdef HAVE_IPV6
+ expected |= TLVFLAG_IPV6_ADDR;
+ expected |= TLVFLAG_IPV6_REACHABILITY;
+#endif /* HAVE_IPV6 */
+
+ retval = parse_tlvs (area->area_tag, lsp->pdu->data +
+ ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
+ ntohs(lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
+ - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data);
+
+ if (found & TLVFLAG_DYN_HOSTNAME) {
+ if (area->dynhostname)
+ isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
+ (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
+ IS_LEVEL_1_AND_2 ? IS_LEVEL_2 :
+ (lsp->lsp_header->lsp_bits & LSPBIT_IST));
+ }
+
+}
+
+void
+lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
+ struct stream *stream, struct isis_area *area)
+{
+
+ /* free the old lsp data*/
+ XFREE (MTYPE_STREAM_DATA, lsp->pdu);
+ lsp_clear_data (lsp);
+
+ /* rebuild the lsp data */
+ lsp_update_data (lsp, stream, area);
+
+ /* set the new values for lsp header */
+ memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
+
+}
+
+
+/* creation of LSP directly from what we received */
+struct isis_lsp *
+lsp_new_from_stream_ptr (struct stream *stream,
+ u_int16_t pdu_len, struct isis_lsp *lsp0,
+ struct isis_area *area)
+{
+ struct isis_lsp *lsp;
+
+ lsp = XMALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
+ memset (lsp, 0, sizeof (struct isis_lsp));
+
+ lsp_update_data (lsp, stream, area);
+
+ if (lsp0 == NULL) {
+ /*
+ * zero lsp -> create the list for fragments
+ */
+ lsp->lspu.frags = list_new ();
+ } else {
+ /*
+ * a fragment -> set the backpointer and add this to zero lsps frag list
+ */
+ lsp->lspu.zero_lsp = lsp0;
+ listnode_add (lsp0->lspu.frags, lsp);
+ }
+
+ return lsp;
+}
+
+struct isis_lsp *
+lsp_new (u_char *lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
+ u_int8_t lsp_bits, u_int16_t checksum, int level)
+{
+ struct isis_lsp *lsp;
+
+ lsp = XMALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
+ if (!lsp) {
+ /* FIXME: set lspdbol bit */
+ zlog_warn ("lsp_new(): out of memory");
+ return NULL;
+ }
+ memset (lsp, 0, sizeof (struct isis_lsp));
+#ifdef LSP_MEMORY_PREASSIGN
+ lsp->pdu = stream_new (1514); /*Should be minimal mtu? yup...*/
+#else
+ /* We need to do realloc on TLVs additions*/
+ lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+#endif /* LSP_MEMORY_PREASSIGN */
+ if (LSP_FRAGMENT (lsp_id) == 0)
+ lsp->lspu.frags = list_new ();
+ lsp->isis_header = (struct isis_fixed_hdr*)(STREAM_DATA(lsp->pdu));
+ lsp->lsp_header = (struct isis_link_state_hdr*)
+ (STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN);
+
+ /* at first we fill the FIXED HEADER */
+ (level == 1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE):
+ fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
+
+ /* now for the LSP HEADER */
+ /* Minimal LSP PDU size */
+ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
+ lsp->lsp_header->checksum = checksum; /* Provided in network order */
+ lsp->lsp_header->seq_num = htonl (seq_num);
+ lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
+ lsp->lsp_header->lsp_bits = lsp_bits;
+ lsp->level = level;
+ lsp->age_out = ZERO_AGE_LIFETIME;
+
+ stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+
+ /* #ifdef EXTREME_DEBUG */
+ /* logging */
+ zlog_info ("New LSP with ID %s-%02x-%02x seqnum %08x", sysid_print (lsp_id),
+ LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
+ LSP_FRAGMENT (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->seq_num));
+ /* #endif EXTREME DEBUG */
+
+ return lsp;
+}
+
+void
+lsp_insert (struct isis_lsp *lsp, dict_t *lspdb)
+{
+ dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
+}
+
+/*
+ * Build a list of LSPs with non-zero ht bounded by start and stop ids
+ */
+void
+lsp_build_list_nonzero_ht (u_char *start_id, u_char *stop_id,
+ struct list *list, dict_t *lspdb)
+{
+ dnode_t *first, *last, *curr;
+
+ first = dict_lower_bound (lspdb, start_id);
+ if (!first)
+ return;
+
+ last = dict_upper_bound (lspdb, stop_id);
+
+ curr = first;
+
+ if (((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime)
+ listnode_add (list, first->dict_data);
+
+ while (curr) {
+ curr = dict_next (lspdb, curr);
+ if (curr &&
+ ((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime)
+ listnode_add (list, curr->dict_data);
+ if (curr == last)
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Build a list of all LSPs bounded by start and stop ids
+ */
+void
+lsp_build_list (u_char *start_id, u_char *stop_id,
+ struct list *list, dict_t *lspdb)
+{
+ dnode_t *first, *last, *curr;
+
+ first = dict_lower_bound (lspdb, start_id);
+ if (!first)
+ return;
+
+ last = dict_upper_bound (lspdb, stop_id);
+
+ curr = first;
+
+ listnode_add (list, first->dict_data);
+
+ while (curr) {
+ curr = dict_next (lspdb, curr);
+ if (curr)
+ listnode_add (list, curr->dict_data);
+ if (curr == last)
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Build a list of LSPs with SSN flag set for the given circuit
+ */
+void
+lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
+ dict_t *lspdb)
+{
+ dnode_t *dnode, *next;
+ struct isis_lsp *lsp;
+
+ dnode = dict_first (lspdb);
+ while (dnode != NULL) {
+ next = dict_next (lspdb, dnode);
+ lsp = dnode_get (dnode);
+ if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
+ listnode_add (list, lsp);
+ dnode = next;
+ }
+
+ return;
+}
+
+void
+lsp_set_time (struct isis_lsp *lsp)
+{
+ assert (lsp);
+
+ if (lsp->lsp_header->rem_lifetime == 0) {
+ if (lsp->age_out != 0) lsp->age_out--;
+ return;
+ }
+
+ /* If we are turning 0 */
+ /* ISO 10589 - 7.3.16.4 first paragraph */
+
+ if (ntohs (lsp->lsp_header->rem_lifetime) == 1) {
+ /* 7.3.16.4 a) set SRM flags on all */
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ /* 7.3.16.4 b) retain only the header FIXME */
+ /* 7.3.16.4 c) record the time to purge FIXME (other way to do it)*/
+ }
+
+ lsp->lsp_header->rem_lifetime =
+ htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
+}
+
+void
+lspid_print (u_char *lsp_id, u_char *trg, char dynhost, char frag)
+{
+ struct isis_dynhn *dyn = NULL;
+ u_char id [SYSID_STRLEN];
+
+ if (dynhost)
+ dyn = dynhn_find_by_id (lsp_id);
+ else
+ dyn = NULL;
+
+ if (dyn)
+ sprintf (id, "%.14s", dyn->name.name);
+ else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost)
+ sprintf (id, "%.14s", host.name);
+ else {
+ memcpy(id, sysid_print (lsp_id), 15);
+ }
+ if (frag)
+ sprintf (trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID(lsp_id),
+ LSP_FRAGMENT(lsp_id));
+ else
+ sprintf (trg, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id));
+}
+
+/* Convert the lsp attribute bits to attribute string */
+char *
+lsp_bits2string (u_char *lsp_bits) {
+
+ char *pos = lsp_bits_string;
+
+ if(!*lsp_bits)
+ return " none";
+
+ /* we only focus on the default metric */
+ pos += sprintf (pos, "%d/",
+ ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits) ?
+ 1 : 0);
+
+ pos += sprintf (pos, "%d/",
+ ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits) ?
+ 1 : 0);
+
+ pos += sprintf (pos, "%d",
+ ISIS_MASK_LSP_OL_BIT(*lsp_bits) ?
+ 1 : 0);
+
+ *(pos) = '\0';
+
+ return lsp_bits_string;
+
+}
+
+/* this function prints the lsp on show isis database */
+void
+lsp_print (dnode_t *node, struct vty *vty, char dynhost)
+{
+ struct isis_lsp *lsp = dnode_get(node);
+ u_char LSPid[255];
+
+ lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
+ vty_out (vty, "%-21s%c ", LSPid,lsp->own_lsp?'*':' ');
+ vty_out (vty, "0x%08x ", ntohl(lsp->lsp_header->seq_num));
+ vty_out (vty, "0x%04x ", ntohs(lsp->lsp_header->checksum));
+
+ if (ntohs(lsp->lsp_header->rem_lifetime) == 0)
+ vty_out (vty, " (%2u)",lsp->age_out);
+ else
+ vty_out (vty, "%5u", ntohs(lsp->lsp_header->rem_lifetime));
+
+ vty_out (vty, " %s%s",
+ lsp_bits2string(&lsp->lsp_header->lsp_bits),
+ VTY_NEWLINE);
+}
+
+void
+lsp_print_detail (dnode_t *node, struct vty *vty, char dynhost)
+{
+ struct isis_lsp *lsp = dnode_get (node);
+ struct area_addr *area_addr;
+ char nlpidstr[2];
+ int i;
+ struct listnode *lnode;
+ struct is_neigh *is_neigh;
+ struct te_is_neigh *te_is_neigh;
+ struct ipv4_reachability *ipv4_reach;
+ struct in_addr *ipv4_addr;
+ struct te_ipv4_reachability *te_ipv4_reach;
+#ifdef HAVE_IPV6
+ struct ipv6_reachability *ipv6_reach;
+ struct in6_addr in6;
+#endif
+ u_char LSPid[255];
+ u_char hostname[255];
+ u_char buff[BUFSIZ];
+ u_int32_t now,helper;
+ u_char ipv4_reach_prefix[20];
+ u_char ipv4_reach_mask[20];
+ u_char ipv4_address[20];
+
+ lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
+ lsp_print(node, vty, dynhost);
+
+ /* for all area address */
+ if (lsp->tlv_data.area_addrs) {
+ LIST_LOOP (lsp->tlv_data.area_addrs, area_addr, lnode) {
+ vty_out (vty, " Area Address: %s%s",
+ isonet_print (area_addr->area_addr, area_addr->addr_len),
+ VTY_NEWLINE);
+ }
+ }
+
+ /* for the nlpid tlv */
+ if (lsp->tlv_data.nlpids) {
+ for (i = 0; i < lsp->tlv_data.nlpids->count; i++) {
+ switch (lsp->tlv_data.nlpids->nlpids[i]) {
+ case NLPID_IP:
+ case NLPID_IPV6:
+ vty_out (vty, " NLPID: 0x%X%s",
+ lsp->tlv_data.nlpids->nlpids[i],
+ VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, " NLPID: %s%s",
+ "unknown",
+ VTY_NEWLINE);
+ break;
+ }
+ }
+ }
+
+ /* for the hostname tlv */
+ if (lsp->tlv_data.hostname) {
+ bzero (hostname, sizeof (hostname));
+ memcpy (hostname, lsp->tlv_data.hostname->name,
+ lsp->tlv_data.hostname->namelen);
+ vty_out (vty, " Hostname: %s%s", hostname, VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.ipv4_addrs) {
+ LIST_LOOP(lsp->tlv_data.ipv4_addrs, ipv4_addr, lnode) {
+ memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_addr));
+ vty_out (vty, " IP: %s%s",
+ ipv4_address,
+ VTY_NEWLINE);
+ }
+ }
+
+ /* for the internal reachable tlv */
+ if (lsp->tlv_data.ipv4_int_reachs)
+ LIST_LOOP(lsp->tlv_data.ipv4_int_reachs, ipv4_reach, lnode) {
+ memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix), sizeof (ipv4_reach_prefix));
+ memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask));
+ vty_out (vty, " Matric: %d IP %s %s%s",
+ ipv4_reach->metrics.metric_default,
+ ipv4_reach_prefix,
+ ipv4_reach_mask,
+ VTY_NEWLINE);
+ }
+
+ /* for the IS neighbor tlv */
+ if (lsp->tlv_data.is_neighs) {
+ LIST_LOOP(lsp->tlv_data.is_neighs,is_neigh,lnode) {
+ lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
+ vty_out (vty, " Metric: %d IS %s%s",
+ is_neigh->metrics.metric_default,
+ LSPid,
+ VTY_NEWLINE);
+ }
+ }
+
+/* FIXME: Other tlvs such as te or external tlv will be added later */
+#if 0
+ vty_out (vty, "%s %s %c%s",
+ VTY_NEWLINE,
+ LSPid,
+ lsp->own_lsp ? '*' : ' ',
+ VTY_NEWLINE);
+
+ vty_out (vty, " Sequence: 0x%08x Checksum: 0x%04x Lifetime: ",
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum));
+
+ if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
+ vty_out (vty, " (%2u) ", lsp->age_out);
+ else
+ vty_out (vty, "%5u ", ntohs (lsp->lsp_header->rem_lifetime));
+
+ vty_out (vty, "%s Attributes:%s",
+ VTY_NEWLINE,
+ lsp_bits2string (&lsp->lsp_header->lsp_bits));
+
+ /* if this is a self originated LSP then print
+ * the generation time plus when we sent it last
+ * if it is a non self-originated LSP then print the
+ * time when the LSP has been installed
+ */
+
+ if (lsp->own_lsp) {
+
+ now = time (NULL);
+ helper = now - lsp->last_generated;
+ if (!lsp->last_generated)
+ helper = 0;
+
+ vty_out (vty, ", Generated: %s ago",
+ time2string (helper));
+
+ now = time (NULL);
+ helper = now - lsp->last_sent;
+ if (!lsp->last_sent)
+ helper = 0;
+
+ vty_out (vty, ", Last sent: %s ago",
+ time2string (helper));
+ } else {
+ now = time (NULL);
+ helper = now - lsp->installed;
+ if (!lsp->installed)
+ helper = 0;
+
+ vty_out (vty, ", Installed: %s ago",
+ time2string (helper));
+
+ }
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ if (lsp->tlv_data.nlpids) {
+ vty_out (vty, " Speaks: %s%s", nlpid2string (lsp->tlv_data.nlpids),
+ VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.router_id) {
+ vty_out (vty, " Router ID: %s%s",
+ inet_ntoa (lsp->tlv_data.router_id->id), VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.is_neighs)
+ LIST_LOOP(lsp->tlv_data.is_neighs,is_neigh,lnode) {
+ lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
+ vty_out (vty, " IS %s, Metric: %d%s",
+ LSPid,
+ is_neigh->metrics.metric_default,
+ VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.te_is_neighs)
+ LIST_LOOP(lsp->tlv_data.te_is_neighs,te_is_neigh,lnode) {
+ /* FIXME: metric display is wrong */
+ lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
+ vty_out (vty, " extd-IS %s, Metric: %d%s",
+ LSPid,
+ te_is_neigh->te_metric[0],
+ VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.ipv4_int_reachs)
+ LIST_LOOP(lsp->tlv_data.ipv4_int_reachs, ipv4_reach, lnode) {
+ vty_out (vty, " int-IP %s/%d, Metric: %d%s",
+ inet_ntoa (ipv4_reach->prefix),
+ ip_masklen (ipv4_reach->mask),
+ ipv4_reach->metrics.metric_default,
+ VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.ipv4_ext_reachs)
+ LIST_LOOP(lsp->tlv_data.ipv4_ext_reachs,ipv4_reach,lnode) {
+ vty_out (vty, " ext-IP %s/%d, Metric: %d%s",
+ inet_ntoa(ipv4_reach->prefix),
+ ip_masklen(ipv4_reach->mask),
+ ipv4_reach->metrics.metric_default,
+ VTY_NEWLINE);
+ }
+
+ if (lsp->tlv_data.te_ipv4_reachs)
+ LIST_LOOP(lsp->tlv_data.te_ipv4_reachs,te_ipv4_reach,lnode) {
+ vty_out (vty, " extd-IP %s/%d, Metric: %d%s",
+ inet_ntoa ( newprefix2inaddr (&te_ipv4_reach->prefix_start,
+ te_ipv4_reach->control)),
+ te_ipv4_reach->control & 0x3F,
+ ntohl (te_ipv4_reach->te_metric),
+ VTY_NEWLINE);
+ }
+
+#ifdef HAVE_IPV6
+ if (lsp->tlv_data.ipv6_reachs)
+ LIST_LOOP(lsp->tlv_data.ipv6_reachs, ipv6_reach, lnode) {
+ memcpy (in6.s6_addr, ipv6_reach->prefix, 16);
+ inet_ntop (AF_INET6, &in6, buff, BUFSIZ);
+ if ((ipv6_reach->control_info &&
+ CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
+ vty_out (vty, " int-IPv6 %s/%d, Metric: %d%s",
+ buff,
+ ipv6_reach->prefix_len,
+ ntohl (ipv6_reach->metric),
+ VTY_NEWLINE);
+ else
+ vty_out (vty, " ext-IPv6 %s/%d, Metric: %d%s",
+ buff,
+ ipv6_reach->prefix_len,
+ ntohl (ipv6_reach->metric),
+ VTY_NEWLINE);
+
+ }
+#endif
+ if (lsp->tlv_data.hostname) {
+ memset (hostname, 0, sizeof (hostname));
+ memcpy (hostname, lsp->tlv_data.hostname->name,
+ lsp->tlv_data.hostname->namelen);
+ vty_out (vty, " Hostname: %s%s", hostname, VTY_NEWLINE);
+ }
+#endif
+ return;
+}
+
+/* print all the lsps info in the local lspdb */
+int
+lsp_print_all (struct vty *vty, dict_t *lspdb, char detail, char dynhost)
+{
+
+ dnode_t *node = dict_first(lspdb), *next;
+ int lsp_count = 0;
+
+ /* print the title, for both modes */
+ vty_out (vty, "LSP ID LSP Seq Num LSP Checksum "
+ "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE);
+
+ if (detail == ISIS_UI_LEVEL_BRIEF) {
+ while (node != NULL) {
+ /* dict_contains (lspdb, node); */ /* I think it is unnecessary, so I comment it out */
+ next = dict_next (lspdb, node);
+ lsp_print (node, vty, dynhost);
+ node = next;
+ lsp_count++;
+ }
+ } else if (detail == ISIS_UI_LEVEL_DETAIL) {
+ while (node != NULL) {
+ next = dict_next (lspdb, node);
+ lsp_print_detail (node, vty, dynhost);
+ node = next;
+ lsp_count++;
+ }
+ }
+
+ return lsp_count;
+}
+
+/* this function reallocate memory to an lsp pdu, with an additional
+ * size of memory, it scans the lsp and moves all pointers the
+ * way they should */
+u_char *
+lsppdu_realloc (struct isis_lsp *lsp, int memorytype, int size)
+{
+ u_char *retval;
+
+ retval = STREAM_DATA(lsp->pdu) + ntohs(lsp->lsp_header->pdu_len);
+#ifdef LSP_MEMORY_PREASSIGN
+ lsp->lsp_header->pdu_len = htons(ntohs(lsp->lsp_header->pdu_len) + size);
+ return retval;
+#else /* otherwise we have to move all pointers */
+ u_char *newpdu;
+ newpdu = stream_new (ntohs (lsp->lsp_header->pdu_len) + size);
+ memcpy (STREAM_DATA (newpdu), STREAM_DATA(lsp->pdu),
+ ntohs (lsp->lsp_header->pdu_len));
+ XFREE (memorytype, lsp->pdu);
+ lsp->pdu = newpdu;
+ lsp->isis_header = (struct isis_fixed_hdr*)STREAM_DATA(lsp->pdu);
+ lsp->lsp_header = (struct isis_link_state_hdr*)
+ (STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN);
+ htons (ntohs (lsp->lsp_header->pdu_len) += size);
+ return STREAM_DATA(lsp->pdu) + (lsp->lsp_header->pdu_len - size);
+#endif /* LSP_MEMORY_PREASSIGN */
+}
+
+
+#if 0 /* Saving the old one just in case :) */
+/*
+ * Builds the lsp->tlv_data
+ * and writes the tlvs into lsp->pdu
+ */
+void
+lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+{
+ struct is_neigh *is_neigh;
+ struct listnode *node, *ipnode;
+ int level = lsp->level;
+ struct isis_circuit *circuit;
+ struct prefix_ipv4 *ipv4;
+ struct ipv4_reachability *ipreach;
+ struct isis_adjacency *nei;
+#ifdef HAVE_IPV6
+ struct prefix_ipv6 *ipv6;
+ struct ipv6_reachability *ip6reach;
+#endif /* HAVE_IPV6 */
+
+ /*
+ * First add the tlvs related to area
+ */
+
+ /* Area addresses */
+ if (lsp->tlv_data.area_addrs == NULL)
+ lsp->tlv_data.area_addrs = list_new ();
+ list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
+ /* Protocols Supported */
+ if (area->ip_circuits > 0
+#ifdef HAVE_IPV6
+ || area->ipv6_circuits > 0
+#endif /* HAVE_IPV6 */
+ )
+ {
+ lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
+ lsp->tlv_data.nlpids->count = 0;
+ if (area->ip_circuits > 0) {
+ lsp->tlv_data.nlpids->count++;
+ lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
+ }
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits > 0) {
+ lsp->tlv_data.nlpids->count++;
+ lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
+ NLPID_IPV6;
+ }
+#endif /* HAVE_IPV6 */
+ }
+ /* Dynamic Hostname */
+ if (area->dynhostname) {
+ lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
+ sizeof (struct hostname));
+ memcpy (&lsp->tlv_data.hostname->name, host.name, strlen(host.name));
+ lsp->tlv_data.hostname->namelen = strlen (host.name);
+ }
+#ifdef TOPOLOGY_GENERATE
+ /*
+ * If we have a topology in this area, we need to connect this lsp to
+ * the first topology lsp
+ */
+ if ((area->topology) && (level == 1)) {
+ if (lsp->tlv_data.is_neighs == NULL)
+ lsp->tlv_data.is_neighs = list_new ();
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
+ /* connected to the first */
+ is_neigh->neigh_id[ISIS_SYS_ID_LEN-1] = (0x01);
+ /* this is actually the same system, why mess the SPT */
+ is_neigh->metrics.metric_default = 0;
+ is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
+ is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
+ is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+
+ }
+#endif
+
+ /*
+ * Then add tlvs related to circuits
+ */
+ for (node = listhead (area->circuit_list); node; nextnode (node)) {
+ circuit = getdata (node);
+ if (circuit->state != C_STATE_UP)
+ continue;
+
+ /*
+ * Add IPv4 internal reachability of this circuit
+ */
+ if (circuit->ip_router && circuit->ip_addrs &&
+ circuit->ip_addrs->count > 0) {
+ if (lsp->tlv_data.ipv4_int_reachs == NULL) {
+ lsp->tlv_data.ipv4_int_reachs = list_new ();
+ lsp->tlv_data.ipv4_int_reachs->del = free_tlv;
+ }
+ for (ipnode = listhead (circuit->ip_addrs); ipnode; nextnode (ipnode)) {
+ ipv4 = getdata (ipnode);
+ ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
+ ipreach->metrics = circuit->metrics[level - 1];
+ ipreach->prefix = ipv4->prefix;
+ masklen2ip (ipv4->prefixlen, &ipreach->mask);
+ listnode_add (lsp->tlv_data.ipv4_int_reachs, ipreach);
+ }
+ }
+#ifdef HAVE_IPV6
+ /*
+ * Add IPv6 reachability of this circuit
+ */
+ if (circuit->ipv6_router && circuit->ipv6_non_link &&
+ circuit->ipv6_non_link->count > 0) {
+ if (lsp->tlv_data.ipv6_reachs == NULL) {
+ lsp->tlv_data.ipv6_reachs = list_new ();
+ lsp->tlv_data.ipv6_reachs->del = free_tlv;
+ }
+ for (ipnode = listhead (circuit->ipv6_non_link); ipnode;
+ nextnode (ipnode)) {
+ ipv6 = getdata (ipnode);
+ ip6reach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
+ memset (ip6reach, 0, sizeof (struct ipv6_reachability));
+ ip6reach->metric = htonl(circuit->metrics[level - 1].metric_default);
+ ip6reach->control_info = 0;
+ ip6reach->prefix_len = ipv6->prefixlen;
+ memcpy (&ip6reach->prefix, ipv6->prefix.s6_addr,
+ (ipv6->prefixlen + 7) / 8);
+ listnode_add (lsp->tlv_data.ipv6_reachs, ip6reach);
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ if (level & circuit->circuit_is_type) {
+ if (lsp->tlv_data.is_neighs == NULL) {
+ lsp->tlv_data.is_neighs = list_new ();
+ lsp->tlv_data.is_neighs->del = free_tlv;
+ }
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ if (level == 1)
+ memcpy (&is_neigh->neigh_id,
+ circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
+ else
+ memcpy (&is_neigh->neigh_id,
+ circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
+ is_neigh->metrics = circuit->metrics[level - 1];
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ nei = circuit->u.p2p.neighbor;
+ if (nei && (level & nei->circuit_t)) {
+ if (lsp->tlv_data.is_neighs == NULL) {
+ lsp->tlv_data.is_neighs = list_new ();
+ lsp->tlv_data.is_neighs->del = free_tlv;
+ }
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ memcpy (&is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
+ is_neigh->metrics = circuit->metrics[level - 1];
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+ }
+ break;
+ case CIRCUIT_T_STATIC_IN:
+ zlog_warn ("lsp_area_create: unsupported circuit type");
+ break;
+ case CIRCUIT_T_STATIC_OUT:
+ zlog_warn ("lsp_area_create: unsupported circuit type");
+ break;
+ case CIRCUIT_T_DA:
+ zlog_warn ("lsp_area_create: unsupported circuit type");
+ break;
+ default:
+ zlog_warn ("lsp_area_create: unknown circuit type");
+ }
+ }
+
+ stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+
+ if (lsp->tlv_data.nlpids)
+ tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
+ if (lsp->tlv_data.hostname)
+ tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
+ if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0 )
+ tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
+ if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
+ tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
+ if (lsp->tlv_data.ipv4_int_reachs &&
+ listcount (lsp->tlv_data.ipv4_int_reachs) > 0)
+ tlv_add_ipv4_reachs (lsp->tlv_data.ipv4_int_reachs, lsp->pdu);
+#ifdef HAVE_IPV6
+ if (lsp->tlv_data.ipv6_reachs &&
+ listcount (lsp->tlv_data.ipv6_reachs) > 0)
+ tlv_add_ipv6_reachs (lsp->tlv_data.ipv6_reachs, lsp->pdu);
+#endif /* HAVE_IPV6 */
+
+ lsp->lsp_header->pdu_len = htons (stream_get_putp (lsp->pdu));
+
+ return;
+}
+#endif
+
+#define FRAG_THOLD(S,T) \
+((STREAM_SIZE(S)*T)/100)
+
+/* stream*, area->lsp_frag_threshold, increment */
+#define FRAG_NEEDED(S,T,I) \
+ (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
+
+void
+lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
+ int tlvsize, int frag_thold,
+ int tlv_build_func(struct list *, struct stream *))
+{
+ int count, i;
+
+ /* can we fit all ? */
+ if (!FRAG_NEEDED(lsp->pdu, frag_thold,
+ listcount(*from) * tlvsize + 2)) {
+ tlv_build_func (*from, lsp->pdu);
+ *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;
+ for (i = 0; i < count; i++) {
+ listnode_add (*to, getdata(listhead(*from)));
+ listnode_delete(*from, getdata(listhead(*from)));
+ }
+ tlv_build_func (*to, lsp->pdu);
+ }
+ lsp->lsp_header->pdu_len = htons (stream_get_putp (lsp->pdu));
+ return;
+}
+
+struct isis_lsp *
+lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
+ int level )
+{
+ struct isis_lsp *lsp;
+ u_char frag_id[ISIS_SYS_ID_LEN + 2];
+
+ memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
+ LSP_FRAGMENT (frag_id) = frag_num;
+ lsp = lsp_search (frag_id, area->lspdb[level - 1]);
+ if (lsp) {
+ /*
+ * Clear the TLVs, but inherit the authinfo
+ */
+ lsp_clear_data (lsp);
+ if (lsp0->tlv_data.auth_info.type) {
+ memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
+ sizeof (struct isis_passwd));
+ tlv_add_authinfo (lsp->tlv_data.auth_info.type,
+ lsp->tlv_data.auth_info.len,
+ lsp->tlv_data.auth_info.passwd, lsp->pdu);
+ }
+ return lsp;
+ }
+ lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type,
+ 0, level);
+ lsp->own_lsp = 1;
+ lsp_insert (lsp, area->lspdb[level-1]);
+ listnode_add (lsp0->lspu.frags, lsp);
+ lsp->lspu.zero_lsp = lsp0;
+ /*
+ * Copy the authinfo from zero LSP
+ */
+ if (lsp0->tlv_data.auth_info.type) {
+ memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
+ sizeof (struct isis_passwd));
+ tlv_add_authinfo (lsp->tlv_data.auth_info.type,
+ lsp->tlv_data.auth_info.len,
+ lsp->tlv_data.auth_info.passwd, lsp->pdu);
+ }
+ return lsp;
+}
+
+/*
+ * Builds the LSP data part. This func creates a new frag whenever
+ * area->lsp_frag_threshold is exceeded.
+ */
+#if 1
+void
+lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+{
+ struct is_neigh *is_neigh;
+ struct listnode *node, *ipnode;
+ int level = lsp->level;
+ struct isis_circuit *circuit;
+ struct prefix_ipv4 *ipv4;
+ struct ipv4_reachability *ipreach;
+ struct isis_adjacency *nei;
+#ifdef HAVE_IPV6
+ struct prefix_ipv6 *ipv6;
+ struct ipv6_reachability *ip6reach;
+#endif /* HAVE_IPV6 */
+ struct tlvs tlv_data;
+ struct isis_lsp *lsp0 = lsp;
+ struct isis_passwd *passwd;
+
+ /*
+ * First add the tlvs related to area
+ */
+
+ /* Area addresses */
+ if (lsp->tlv_data.area_addrs == NULL)
+ lsp->tlv_data.area_addrs = list_new ();
+ list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
+ /* Protocols Supported */
+ if (area->ip_circuits > 0
+#ifdef HAVE_IPV6
+ || area->ipv6_circuits > 0
+#endif /* HAVE_IPV6 */
+ )
+ {
+ lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
+ lsp->tlv_data.nlpids->count = 0;
+ if (area->ip_circuits > 0) {
+ lsp->tlv_data.nlpids->count++;
+ lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
+ }
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits > 0) {
+ lsp->tlv_data.nlpids->count++;
+ lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
+ NLPID_IPV6;
+ }
+#endif /* HAVE_IPV6 */
+ }
+ /* Dynamic Hostname */
+ if (area->dynhostname) {
+ lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
+ sizeof (struct hostname));
+ memcpy (lsp->tlv_data.hostname->name, host.name, strlen (host.name));
+ lsp->tlv_data.hostname->namelen = strlen (host.name);
+ }
+
+ /*
+ * Building the zero lsp
+ */
+ stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ /*
+ * Add the authentication info if its present
+ */
+ (level == 1) ? (passwd = &area->area_passwd) :
+ (passwd = &area->domain_passwd);
+ if (passwd->type) {
+ memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
+ tlv_add_authinfo (passwd->type, passwd->len,
+ passwd->passwd, lsp->pdu);
+ }
+ if (lsp->tlv_data.nlpids)
+ tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
+ if (lsp->tlv_data.hostname)
+ tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
+ if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0 )
+ tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
+
+ memset (&tlv_data, 0, sizeof (struct tlvs));
+ /*
+ * Then build lists of tlvs related to circuits
+ */
+ for (node = listhead (area->circuit_list); node; nextnode (node)) {
+ circuit = getdata (node);
+ if (circuit->state != C_STATE_UP)
+ continue;
+
+ /*
+ * Add IPv4 internal reachability of this circuit
+ */
+ if (circuit->ip_router && circuit->ip_addrs &&
+ circuit->ip_addrs->count > 0) {
+ if (tlv_data.ipv4_int_reachs == NULL) {
+ tlv_data.ipv4_int_reachs = list_new ();
+ }
+ for (ipnode = listhead (circuit->ip_addrs); ipnode; nextnode (ipnode)) {
+ ipv4 = getdata (ipnode);
+ ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
+ ipreach->metrics = circuit->metrics[level - 1];
+ ipreach->prefix = ipv4->prefix;
+ masklen2ip (ipv4->prefixlen, &ipreach->mask);
+ listnode_add (tlv_data.ipv4_int_reachs, ipreach);
+ }
+
+ }
+#ifdef HAVE_IPV6
+ /*
+ * Add IPv6 reachability of this circuit
+ */
+ if (circuit->ipv6_router && circuit->ipv6_non_link &&
+ circuit->ipv6_non_link->count > 0) {
+
+ if (tlv_data.ipv6_reachs == NULL) {
+ tlv_data.ipv6_reachs = list_new ();
+ }
+ for (ipnode = listhead (circuit->ipv6_non_link); ipnode;
+ nextnode (ipnode)) {
+ ipv6 = getdata (ipnode);
+ ip6reach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
+ memset (ip6reach, 0, sizeof (struct ipv6_reachability));
+ ip6reach->metric = htonl(circuit->metrics[level - 1].metric_default);
+ ip6reach->control_info = 0;
+ ip6reach->prefix_len = ipv6->prefixlen;
+ memcpy (ip6reach->prefix, ipv6->prefix.s6_addr,
+ (ipv6->prefixlen + 7) / 8);
+ listnode_add (tlv_data.ipv6_reachs, ip6reach);
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ if (level & circuit->circuit_is_type) {
+ if (tlv_data.is_neighs == NULL) {
+ tlv_data.is_neighs = list_new ();
+ }
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ if (level == 1)
+ memcpy (is_neigh->neigh_id,
+ circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
+ else
+ memcpy (is_neigh->neigh_id,
+ circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
+ is_neigh->metrics = circuit->metrics[level - 1];
+ listnode_add (tlv_data.is_neighs, is_neigh);
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ nei = circuit->u.p2p.neighbor;
+ if (nei && (level & nei->circuit_t)) {
+ if (tlv_data.is_neighs == NULL) {
+ tlv_data.is_neighs = list_new ();
+ tlv_data.is_neighs->del = free_tlv;
+ }
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
+ is_neigh->metrics = circuit->metrics[level - 1];
+ listnode_add (tlv_data.is_neighs, is_neigh);
+ }
+ break;
+ case CIRCUIT_T_STATIC_IN:
+ zlog_warn ("lsp_area_create: unsupported circuit type");
+ break;
+ case CIRCUIT_T_STATIC_OUT:
+ zlog_warn ("lsp_area_create: unsupported circuit type");
+ break;
+ case CIRCUIT_T_DA:
+ zlog_warn ("lsp_area_create: unsupported circuit type");
+ break;
+ default:
+ zlog_warn ("lsp_area_create: unknown circuit type");
+ }
+ }
+
+ while (tlv_data.ipv4_int_reachs && listcount(tlv_data.ipv4_int_reachs)) {
+ if (lsp->tlv_data.ipv4_int_reachs == NULL)
+ lsp->tlv_data.ipv4_int_reachs = list_new ();
+ lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
+ &lsp->tlv_data.ipv4_int_reachs,
+ IPV4_REACH_LEN, area->lsp_frag_threshold,
+ tlv_add_ipv4_reachs);
+ if (tlv_data.ipv4_int_reachs && listcount(tlv_data.ipv4_int_reachs))
+ lsp = lsp_next_frag (LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+
+#ifdef HAVE_IPV6
+ while (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) {
+ if (lsp->tlv_data.ipv6_reachs == NULL)
+ lsp->tlv_data.ipv6_reachs = list_new ();
+ lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
+ &lsp->tlv_data.ipv6_reachs,
+ IPV6_REACH_LEN, area->lsp_frag_threshold,
+ tlv_add_ipv6_reachs);
+ if (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs))
+ lsp = lsp_next_frag (LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+#endif /* HAVE_IPV6 */
+
+ while (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) {
+ if (lsp->tlv_data.is_neighs == NULL)
+ lsp->tlv_data.is_neighs = list_new ();
+ lsp_tlv_fit (lsp, &tlv_data.is_neighs,
+ &lsp->tlv_data.is_neighs,
+ IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
+ tlv_add_is_neighs);
+ if (tlv_data.is_neighs && listcount(tlv_data.is_neighs))
+ lsp = lsp_next_frag (LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1,
+ lsp0, area, level);
+ }
+
+
+ return;
+}
+#endif
+
+void
+build_lsp_data (struct isis_lsp *lsp, struct isis_area *area)
+{
+ struct list *circuit_list = area->circuit_list;
+ struct isis_circuit *circuit;
+ u_char *tlv_ptr;
+ struct is_neigh *is_neigh;
+
+
+ /* add our nlpids */
+ /* the 2 is for the TL plus 1 for the nlpid*/
+ tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 3);
+ *tlv_ptr = PROTOCOLS_SUPPORTED; /* Type */
+ *(tlv_ptr+1) = 1; /* one protocol */
+#ifdef HAVE_IPV6 /*dunno if its right*/
+ *(tlv_ptr+2) = NLPID_IPV6;
+#else
+ *(tlv_ptr+2) = NLPID_IP;
+#endif /* HAVE_IPV6 */
+
+ /* we should add our areas here
+ * FIXME: we need to figure out which should be added? Adj? All? First? */
+
+ /* first, lets add ourselves to the IS neighbours info */
+ /* the 2 is for the TL plus 1 for the virtual field*/
+ tlv_ptr = lsppdu_realloc(lsp,MTYPE_ISIS_TLV, 3);
+ *tlv_ptr = IS_NEIGHBOURS; /* Type */
+ *(tlv_ptr+2) = 0; /* virtual is zero */
+ lsp->tlv_data.is_neighs = list_new (); /* new list of is_neighbours */
+ /* assign space for the is_neigh at the pdu end */
+ is_neigh = (struct is_neigh*) lsppdu_realloc(lsp,MTYPE_ISIS_TLV,
+ sizeof(struct is_neigh));
+ /* add this node to our list */
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+ /* FIXME: Do we need our designated address here? */
+ memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN + 1);
+ /* FIXME: Where should we really get our own LSPs metrics from? */
+ circuit = (struct isis_circuit*)listhead(circuit_list);
+ /* is_neigh->metrics = circuit->metrics[lsp->level -1];*/
+ /* Length */
+ *(tlv_ptr+1)=(lsp->tlv_data.is_neighs->count * sizeof(struct is_neigh) +1);
+
+ /* FIXME: scan for adjencecies and add them */
+
+ /* FIXME: add reachability info */
+
+ /* adding dynamic hostname if needed*/
+ if (area->dynhostname) {
+ tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 2); /* the 2 is for the TL */
+ *tlv_ptr = DYNAMIC_HOSTNAME; /* Type */
+ *(tlv_ptr+1) = strlen (host.name); /* Length */
+ lsp->tlv_data.hostname = (struct hostname *)
+ (lsppdu_realloc(lsp,
+ MTYPE_ISIS_TLV,
+ /* the -1 is to fit the length in the struct */
+ strlen (host.name)) - 1);
+ memcpy (lsp->tlv_data.hostname->name, host.name, strlen(host.name));
+ }
+
+}
+
+/*
+ * 7.3.7 Generation on non-pseudonode LSPs
+ */
+int
+lsp_generate_non_pseudo (struct isis_area *area, int level) {
+
+ struct isis_lsp *oldlsp, *newlsp;
+ u_int32_t seq_num = 0;
+ u_char lspid[ISIS_SYS_ID_LEN + 2];
+
+ memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
+ memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
+
+ /* only builds the lsp if the area shares the level */
+ if ((area->is_type & level) == level) {
+ oldlsp = lsp_search (lspid, area->lspdb[level-1]);
+ if (oldlsp) {
+ seq_num = ntohl (oldlsp->lsp_header->seq_num);
+ lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
+ area->lspdb[level-1]);
+ /* FIXME: we should actually initiate a purge */
+ }
+ newlsp = lsp_new (lspid, area->max_lsp_lifetime[level-1], seq_num,
+ area->is_type, 0, level);
+ newlsp->own_lsp = 1;
+
+ lsp_insert (newlsp, area->lspdb[level-1]);
+ /* build_lsp_data (newlsp, area); */
+ lsp_build_nonpseudo (newlsp, area);
+ /* time to calculate our checksum */
+ lsp_seqnum_update (newlsp);
+ }
+
+
+ /* DEBUG_ADJ_PACKETS */
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ /* FIXME: is this place right? fix missing info */
+ zlog_info ("ISIS-Upd (%s): Building L%d LSP",
+ area->area_tag, level);
+ }
+
+ return ISIS_OK;
+}
+
+/*
+ * 7.3.9 Generation of level 1 LSPs (non-pseudonode)
+ */
+int
+lsp_l1_generate (struct isis_area *area)
+{
+
+ area->t_lsp_refresh[0] = thread_add_timer (master, lsp_refresh_l1, area,
+ MAX_LSP_GEN_INTERVAL);
+
+ return lsp_generate_non_pseudo (area, 1);
+}
+
+
+/*
+ * 7.3.9 Generation of level 2 LSPs (non-pseudonode)
+ */
+int
+lsp_l2_generate (struct isis_area *area)
+{
+
+ area->t_lsp_refresh[1] = thread_add_timer (master, lsp_refresh_l2, area,
+ MAX_LSP_GEN_INTERVAL);
+
+ return lsp_generate_non_pseudo (area, 2);
+}
+
+int
+lsp_non_pseudo_regenerate (struct isis_area *area, int level)
+{
+ dict_t *lspdb = area->lspdb[level - 1];
+ struct isis_lsp *lsp, *frag;
+ struct listnode *node;
+ u_char lspid[ISIS_SYS_ID_LEN + 2];
+
+ memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
+ memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
+
+ lsp = lsp_search (lspid, lspdb);
+
+ if (!lsp) {
+ zlog_err ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!",
+ area->area_tag,
+ level);
+
+ return ISIS_ERROR;
+ }
+
+ lsp_clear_data (lsp);
+ lsp_build_nonpseudo (lsp, area);
+ lsp->lsp_header->rem_lifetime = htons (isis_jitter
+ (area->max_lsp_lifetime[level-1],
+ MAX_AGE_JITTER));
+ lsp_seqnum_update (lsp);
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS) {
+ zlog_info ("ISIS-Upd (%s): refreshing our L%d LSP %s, "
+ "seq 0x%08x, cksum 0x%04x lifetime %us",
+ area->area_tag,
+ level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl(lsp->lsp_header->seq_num),
+ ntohs(lsp->lsp_header->checksum),
+ ntohs(lsp->lsp_header->rem_lifetime));
+ }
+
+ lsp->last_generated = time (NULL);
+ area->lsp_regenerate_pending[level - 1] = 0;
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ for (node = listhead (lsp->lspu.frags); node; nextnode(node)) {
+ frag = getdata (node);
+ frag->lsp_header->rem_lifetime = htons (isis_jitter
+ (area->max_lsp_lifetime[level-1],
+ MAX_AGE_JITTER));
+ ISIS_FLAGS_SET_ALL (frag->SRMflags);
+ }
+
+ if (area->ip_circuits)
+ isis_spf_schedule (area, level);
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits)
+ isis_spf_schedule6 (area, level);
+#endif
+ return ISIS_OK;
+}
+
+
+/*
+ * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding
+ * time and set SRM
+ */
+int
+lsp_refresh_l1 (struct thread *thread)
+{
+ struct isis_area *area;
+ unsigned long ref_time;
+
+ area = THREAD_ARG (thread);
+ assert (area);
+
+ area->t_lsp_refresh[0] = NULL;
+ if (area->is_type & IS_LEVEL_1)
+ lsp_non_pseudo_regenerate (area, 1);
+
+ ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
+ MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
+
+ area->t_lsp_refresh[0] = thread_add_timer (master, lsp_refresh_l1, area,
+ isis_jitter (ref_time,
+ MAX_AGE_JITTER));
+ return ISIS_OK;
+}
+
+int
+lsp_refresh_l2 (struct thread *thread)
+{
+ struct isis_area *area;
+ unsigned long ref_time;
+
+ area = THREAD_ARG (thread);
+ assert (area);
+
+ area->t_lsp_refresh[1] = NULL;
+ if (area->is_type & IS_LEVEL_2)
+ lsp_non_pseudo_regenerate (area, 2);
+
+ ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
+ MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1];
+
+
+ area->t_lsp_refresh[1] = thread_add_timer (master, lsp_refresh_l2, area,
+ isis_jitter (ref_time,
+ MAX_AGE_JITTER));
+ return ISIS_OK;
+}
+
+
+/*
+ * Something has changed -> regenerate LSP
+ */
+
+int
+lsp_l1_regenerate (struct thread *thread)
+{
+ struct isis_area *area;
+
+ area = THREAD_ARG (thread);
+ area->lsp_regenerate_pending[0] = 0;
+
+ return lsp_non_pseudo_regenerate (area, 1);
+}
+
+int
+lsp_l2_regenerate (struct thread *thread)
+{
+ struct isis_area *area;
+
+ area = THREAD_ARG (thread);
+ area->lsp_regenerate_pending[1] = 0;
+
+ return lsp_non_pseudo_regenerate (area, 2);
+}
+
+int
+lsp_regenerate_schedule (struct isis_area *area)
+{
+ struct isis_lsp *lsp;
+ u_char id[ISIS_SYS_ID_LEN + 2];
+ time_t now, diff;
+ memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
+ now = time (NULL);
+ /*
+ * First level 1
+ */
+ if (area->is_type & IS_LEVEL_1) {
+ lsp = lsp_search (id, area->lspdb[0]);
+ if (!lsp || area->lsp_regenerate_pending[0])
+ goto L2;
+ /*
+ * Throttle avoidance
+ */
+ diff = now - lsp->last_generated;
+ if (diff < MIN_LSP_GEN_INTERVAL) {
+ area->lsp_regenerate_pending[0] = 1;
+ thread_add_timer (master, lsp_l1_regenerate, area,
+ MIN_LSP_GEN_INTERVAL - diff);
+ return ISIS_OK;
+ } else
+ lsp_non_pseudo_regenerate (area, 1);
+ }
+ /*
+ * then 2
+ */
+ L2:
+ if (area->is_type & IS_LEVEL_2) {
+ lsp = lsp_search (id, area->lspdb[1]);
+ if (!lsp || area->lsp_regenerate_pending[1])
+ return ISIS_OK;
+ /*
+ * Throttle avoidance
+ */
+ diff = now - lsp->last_generated;
+ if (diff < MIN_LSP_GEN_INTERVAL) {
+ area->lsp_regenerate_pending[1] = 1;
+ thread_add_timer (master, lsp_l2_regenerate, area,
+ MIN_LSP_GEN_INTERVAL - diff);
+ return ISIS_OK;
+ } else
+ lsp_non_pseudo_regenerate (area, 2);
+ }
+
+ return ISIS_OK;
+}
+
+/*
+ * Funcs for pseudonode LSPs
+ */
+
+/*
+ * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
+ */
+void
+lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
+ int level)
+{
+ struct isis_adjacency *adj;
+ struct is_neigh *is_neigh;
+ struct es_neigh *es_neigh;
+ struct list *adj_list;
+ struct listnode *node;
+ struct isis_passwd *passwd;
+
+ assert (circuit);
+ assert (circuit->circ_type == CIRCUIT_T_BROADCAST);
+
+ if (!circuit->u.bc.is_dr[level - 1])
+ return; /* we are not DIS on this circuit */
+
+ lsp->level = level;
+ if (level == 1)
+ lsp->lsp_header->lsp_bits |= IS_LEVEL_1;
+ else
+ lsp->lsp_header->lsp_bits |= IS_LEVEL_2;
+
+ /*
+ * add self to IS neighbours
+ */
+ if (lsp->tlv_data.is_neighs == NULL) {
+ lsp->tlv_data.is_neighs = list_new ();
+ lsp->tlv_data.is_neighs->del = free_tlv;
+ }
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+
+ adj_list = list_new();
+ isis_adj_build_up_list (circuit->u.bc.adjdb[level-1], adj_list);
+
+ for (node = listhead (adj_list); node; nextnode (node)){
+ adj = getdata (node);
+ if (adj->circuit_t & level) {
+ if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
+ (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
+ adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
+ (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
+ /* an IS neighbour -> add it */
+ is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
+ memset (is_neigh, 0, sizeof (struct is_neigh));
+ memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+ } else if (level == 1 && adj->sys_type == ISIS_SYSTYPE_ES) {
+ /* an ES neigbour add it, if we are building level 1 LSP */
+ /* FIXME: the tlv-format is hard to use here */
+ if (lsp->tlv_data.es_neighs == NULL) {
+ lsp->tlv_data.es_neighs = list_new ();
+ lsp->tlv_data.es_neighs->del = free_tlv;
+ }
+ es_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
+ memset (es_neigh, 0, sizeof (struct es_neigh));
+ memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
+ listnode_add (lsp->tlv_data.es_neighs, is_neigh);
+ }
+ }
+ }
+
+ stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ /*
+ * Add the authentication info if it's present
+ */
+ (level == 1) ? (passwd = &circuit->area->area_passwd) :
+ (passwd = &circuit->area->domain_passwd);
+ if (passwd->type) {
+ memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
+ tlv_add_authinfo (passwd->type, passwd->len,
+ passwd->passwd, lsp->pdu);
+ }
+
+ if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
+ tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
+
+ if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
+ tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
+
+ lsp->lsp_header->pdu_len = htons (stream_get_putp (lsp->pdu));
+ iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+ ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+
+ list_delete (adj_list);
+
+ return;
+}
+
+int
+lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)
+{
+ dict_t *lspdb = circuit->area->lspdb[level - 1];
+ struct isis_lsp *lsp;
+ u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+
+ memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
+ LSP_FRAGMENT(lsp_id) = 0;
+
+ lsp = lsp_search (lsp_id, lspdb);
+
+ if (!lsp) {
+ zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level,
+ rawlspid_print(lsp_id));
+ return ISIS_ERROR;
+ }
+ lsp_clear_data (lsp);
+
+ lsp_build_pseudo (lsp, circuit, level);
+
+ lsp->lsp_header->rem_lifetime =
+ htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1],
+ MAX_AGE_JITTER));
+
+ lsp_inc_seqnum (lsp, 0);
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS) {
+ zlog_info ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s",
+ circuit->area->area_tag, level,
+ rawlspid_print (lsp->lsp_header->lsp_id));
+ }
+
+ lsp->last_generated = time (NULL);
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+
+ return ISIS_OK;
+}
+
+
+int
+lsp_l1_refresh_pseudo (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ int retval;
+ unsigned long ref_time;
+
+ circuit = THREAD_ARG(thread);
+
+ if (!circuit->u.bc.is_dr[0])
+ return ISIS_ERROR; /* FIXME: purge and such */
+
+ retval = lsp_pseudo_regenerate (circuit, 1);
+
+ ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
+ MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
+
+ circuit->u.bc.t_refresh_pseudo_lsp[0] =
+ thread_add_timer (master, lsp_l1_refresh_pseudo, circuit,
+ isis_jitter (ref_time,
+ MAX_AGE_JITTER));
+ return retval;
+}
+
+int
+lsp_l1_pseudo_generate (struct isis_circuit *circuit)
+{
+ struct isis_lsp *lsp;
+ u_char id[ISIS_SYS_ID_LEN + 2];
+ unsigned long ref_time;
+
+ memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_FRAGMENT(id) = 0;
+ LSP_PSEUDO_ID(id) = circuit->circuit_id;
+
+ /*
+ * If for some reason have a pseudo LSP in the db already -> regenerate
+ */
+ if (lsp_search (id, circuit->area->lspdb[0]))
+ return lsp_pseudo_regenerate (circuit, 1);
+ lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0],
+ 1, circuit->area->is_type, 0, 1);
+
+ lsp_build_pseudo (lsp, circuit, 1);
+
+ lsp->own_lsp = 1;
+ lsp_insert (lsp, circuit->area->lspdb[0]);
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+
+ ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
+ MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
+
+
+ circuit->u.bc.t_refresh_pseudo_lsp[0] =
+ thread_add_timer (master, lsp_l1_refresh_pseudo, circuit,
+ isis_jitter (ref_time,
+ MAX_AGE_JITTER));
+
+ return lsp_regenerate_schedule (circuit->area);
+}
+
+int
+lsp_l2_refresh_pseudo (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ int retval;
+ unsigned long ref_time;
+ circuit = THREAD_ARG(thread);
+
+ if (!circuit->u.bc.is_dr[1])
+ return ISIS_ERROR; /* FIXME: purge and such */
+
+ retval = lsp_pseudo_regenerate (circuit, 2);
+
+ ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
+ MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
+
+
+ circuit->u.bc.t_refresh_pseudo_lsp[1] =
+ thread_add_timer (master, lsp_l2_refresh_pseudo, circuit,
+ isis_jitter (ref_time,
+ MAX_AGE_JITTER));
+ return retval;
+}
+
+
+int
+lsp_l2_pseudo_generate (struct isis_circuit *circuit)
+{
+ struct isis_lsp *lsp;
+ u_char id[ISIS_SYS_ID_LEN + 2];
+ unsigned long ref_time;
+
+ memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_FRAGMENT(id) = 0;
+ LSP_PSEUDO_ID(id) = circuit->circuit_id;
+
+ if (lsp_search (id, circuit->area->lspdb[1]))
+ return lsp_pseudo_regenerate (circuit, 2);
+
+ lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1],
+ 1, circuit->area->is_type, 0, 2);
+
+ lsp_build_pseudo (lsp, circuit, 2);
+
+ ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
+ MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
+
+
+ lsp->own_lsp = 1;
+ lsp_insert (lsp, circuit->area->lspdb[1]);
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+
+ circuit->u.bc.t_refresh_pseudo_lsp[1] =
+ thread_add_timer (master, lsp_l2_refresh_pseudo, circuit,
+ isis_jitter (ref_time,
+ MAX_AGE_JITTER));
+
+ return lsp_regenerate_schedule (circuit->area);
+}
+
+
+
+/*
+ * Walk through LSPs for an area
+ * - set remaining lifetime
+ * - set LSPs with SRMflag set for sending
+ */
+int
+lsp_tick (struct thread *thread)
+{
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct isis_lsp *lsp;
+ struct list *lsp_list;
+ struct listnode *lspnode, *cnode;
+ dnode_t *dnode, *dnode_next;
+ int level;
+
+ lsp_list = list_new ();
+
+ area = THREAD_ARG (thread);
+ assert (area);
+ area->t_tick = thread_add_timer (master, lsp_tick, area, 1);
+
+ /*
+ * Build a list of LSPs with (any) SRMflag set
+ * and removed the ones that have aged out
+ */
+ for (level = 0; level < ISIS_LEVELS; level++) {
+ if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) {
+ dnode = dict_first (area->lspdb[level]);
+ while (dnode != NULL) {
+ dnode_next = dict_next (area->lspdb[level], dnode);
+ lsp = dnode_get (dnode);
+ lsp_set_time (lsp);
+ if (lsp->age_out == 0) {
+
+ zlog_info ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
+ area->area_tag,
+ lsp->level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl(lsp->lsp_header->seq_num));
+
+ lsp_destroy (lsp);
+ dict_delete (area->lspdb[level], dnode);
+ } else if (flags_any_set (lsp->SRMflags))
+ listnode_add (lsp_list, lsp);
+ dnode = dnode_next;
+ }
+
+ /*
+ * Send LSPs on circuits indicated by the SRMflags
+ */
+ if (listcount (lsp_list) > 0) {
+ for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode)) {
+ circuit = getdata (cnode);
+ for (lspnode = listhead (lsp_list); lspnode; nextnode (lspnode)) {
+ lsp = getdata (lspnode);
+ if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) {
+ /* FIXME: if same or elder lsp is already in lsp queue */
+ listnode_add (circuit->lsp_queue, lsp);
+ thread_add_event (master, send_lsp, circuit, 0);
+ }
+ }
+ }
+ }
+ list_delete_all_node (lsp_list);
+ }
+ }
+
+ list_delete (lsp_list);
+
+ return ISIS_OK;
+}
+
+
+void
+lsp_purge_dr (u_char *id, struct isis_circuit *circuit, int level)
+{
+ struct isis_lsp *lsp;
+
+ lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
+
+ if (lsp && lsp->purged == 0) {
+ lsp->lsp_header->rem_lifetime = htons (0);
+ 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,
+ ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+ ISIS_FLAGS_SET_ALL(lsp->SRMflags);
+ }
+
+
+ return;
+}
+
+/*
+ * Purge own LSP that is received and we don't have.
+ * -> Do as in 7.3.16.4
+ */
+void
+lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
+ struct isis_area *area)
+{
+ struct isis_lsp *lsp;
+
+ /*
+ * We need to create the LSP to be purged
+ */
+ zlog_info ("LSP PURGE NON EXIST");
+ lsp = XMALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
+ memset (lsp, 0, sizeof (struct isis_lsp));
+ /*FIXME: BUG BUG BUG! the lsp doesn't exist here!*/
+ /*did smt here, maybe good probably not*/
+ lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;
+ lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ lsp->isis_header = (struct isis_fixed_hdr*)STREAM_DATA(lsp->pdu);
+ fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE
+ : L2_LINK_STATE);
+ lsp->lsp_header = (struct isis_link_state_hdr*)(STREAM_DATA(lsp->pdu) +
+ ISIS_FIXED_HDR_LEN);
+ memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
+
+ /*
+ * Retain only LSP header
+ */
+ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ /*
+ * Set the remaining lifetime to 0
+ */
+ lsp->lsp_header->rem_lifetime = 0;
+ /*
+ * Put the lsp into LSPdb
+ */
+ lsp_insert (lsp, area->lspdb[lsp->level-1]);
+
+ /*
+ * Send in to whole area
+ */
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+
+ return;
+}
+
+#ifdef TOPOLOGY_GENERATE
+int
+top_lsp_refresh (struct thread *thread)
+{
+ struct isis_lsp *lsp;
+
+ lsp = THREAD_ARG (thread);
+ assert (lsp);
+
+ lsp->t_lsp_top_ref = NULL;
+
+ lsp->lsp_header->rem_lifetime = htons (isis_jitter(MAX_AGE,MAX_AGE_JITTER));
+ lsp->lsp_header->seq_num = htonl(ntohl(lsp->lsp_header->seq_num) +1);
+
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ if (isis->debugs & DEBUG_UPDATE_PACKETS) {
+ zlog_info ("ISIS-Upd (): refreshing Topology L1 %s",
+ rawlspid_print (lsp->lsp_header->lsp_id));
+ }
+
+ /* time to calculate our checksum */
+ iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+ ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+
+ lsp->t_lsp_top_ref = thread_add_timer (master, top_lsp_refresh, lsp,
+ isis_jitter (MAX_LSP_GEN_INTERVAL,
+ MAX_LSP_GEN_JITTER));
+
+ return ISIS_OK;
+}
+
+void
+generate_topology_lsps (struct isis_area *area)
+{
+ struct listnode *node;
+ int i, max = 0;
+ struct arc *arc;
+ u_char lspid[ISIS_SYS_ID_LEN + 2];
+ struct isis_lsp *lsp;
+
+ /* first we find the maximal node */
+ LIST_LOOP (area->topology, arc, node) {
+ if (arc->from_node > max) max = arc->from_node;
+ if (arc->to_node > max) max = arc->to_node;
+ }
+
+
+ for (i = 1; i < (max+1); i++) {
+ memcpy (lspid,area->topology_baseis,ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (lspid) = 0x00;
+ LSP_FRAGMENT (lspid) = 0x00;
+ lspid[ISIS_SYS_ID_LEN-1] = (i & 0xFF);
+ lspid[ISIS_SYS_ID_LEN-2] = ((i >> 8) & 0xFF);
+
+ lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0],
+ MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1);
+ lsp->from_topology = 1;
+ /* creating data based on topology */
+ build_topology_lsp_data (lsp,area,i);
+ /* time to calculate our checksum */
+ iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+ ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+ lsp->t_lsp_top_ref = thread_add_timer (master, top_lsp_refresh, lsp,
+ isis_jitter(MAX_LSP_GEN_INTERVAL,
+ MAX_LSP_GEN_JITTER));
+
+ ISIS_FLAGS_SET_ALL(lsp->SRMflags);
+ lsp_insert (lsp,area->lspdb[0]);
+
+ }
+}
+
+void
+remove_topology_lsps (struct isis_area *area)
+{
+ struct isis_lsp *lsp;
+ dnode_t *dnode, *dnode_next;
+
+ dnode = dict_first (area->lspdb[0]);
+ while (dnode != NULL) {
+ dnode_next = dict_next (area->lspdb[0], dnode);
+ lsp = dnode_get (dnode);
+ if (lsp->from_topology) {
+ thread_cancel(lsp->t_lsp_top_ref);
+ lsp_destroy (lsp);
+ dict_delete (area->lspdb[0], dnode);
+ }
+ dnode = dnode_next;
+ }
+}
+
+void
+build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
+ int lsp_top_num)
+{
+ struct listnode *node;
+ struct arc *arc;
+ u_char *tlv_ptr;
+ struct is_neigh *is_neigh;
+ int to_lsp = 0;
+ char buff[200];
+
+ /* add our nlpids */
+ /* the 2 is for the TL plus 1 for the nlpid*/
+ tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 3);
+ *tlv_ptr = PROTOCOLS_SUPPORTED; /* Type */
+ *(tlv_ptr+1) = 1; /* one protocol */
+ *(tlv_ptr+2) = NLPID_IP;
+ lsp->tlv_data.nlpids = (struct nlpids*)(tlv_ptr+1);
+
+ /* first, lets add the tops */
+ /* the 2 is for the TL plus 1 for the virtual field*/
+ tlv_ptr = lsppdu_realloc (lsp ,MTYPE_ISIS_TLV, 3);
+ *tlv_ptr = IS_NEIGHBOURS; /* Type */
+ *(tlv_ptr+1) = 1; /* this is the virtual char len*/
+ *(tlv_ptr+2) = 0; /* virtual is zero */
+ lsp->tlv_data.is_neighs = list_new (); /* new list of is_neighbours */
+
+ /* add reachability for this IS for simulated 1 */
+ if (lsp_top_num == 1) {
+ /* assign space for the is_neigh at the pdu end */
+ is_neigh = (struct is_neigh*) lsppdu_realloc(lsp, MTYPE_ISIS_TLV,
+ sizeof(struct is_neigh));
+ /* add this node to our list */
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+ memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
+ is_neigh->metrics.metric_default = 0x00; /* no special reason */
+ is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
+ is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
+ is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
+ /* don't forget the length */
+ *(tlv_ptr+1) += IS_NEIGHBOURS_LEN; /* the -1 is the virtual */
+ /* no need to check for fragging here, it is a lonely is_reach */
+ }
+
+ /* addding is reachabilities */
+ LIST_LOOP (area->topology, arc, node) {
+ if ((arc->from_node == lsp_top_num) ||
+ (arc->to_node == lsp_top_num)) {
+ if (arc->to_node == lsp_top_num) to_lsp = arc->from_node;
+ if (arc->from_node == lsp_top_num) to_lsp = arc->to_node;
+
+ /* if the length here is about to cross the FF limit, we reTLV */
+ if (*(tlv_ptr+1) >= (0xFF - IS_NEIGHBOURS_LEN)) {
+ /* retlv */
+ /* the 2 is for the TL plus 1 for the virtual field*/
+ tlv_ptr = lsppdu_realloc(lsp,MTYPE_ISIS_TLV, 3);
+ *tlv_ptr = IS_NEIGHBOURS; /* Type */
+ *(tlv_ptr+1) = 1; /* this is the virtual char len*/
+ *(tlv_ptr+2) = 0; /* virtual is zero */
+ }
+ /* doing this here assures us that we won't add an "empty" tlv */
+ /* assign space for the is_neigh at the pdu end */
+ is_neigh = (struct is_neigh*) lsppdu_realloc (lsp, MTYPE_ISIS_TLV,
+ sizeof(struct is_neigh));
+ /* add this node to our list */
+ listnode_add (lsp->tlv_data.is_neighs, is_neigh);
+ memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
+ is_neigh->neigh_id[ISIS_SYS_ID_LEN-1] = (to_lsp & 0xFF);
+ is_neigh->neigh_id[ISIS_SYS_ID_LEN-2] = ((to_lsp >> 8) & 0xFF);
+ is_neigh->metrics.metric_default = arc->distance;
+ is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
+ is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
+ is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
+ /* don't forget the length */
+ *(tlv_ptr+1) += IS_NEIGHBOURS_LEN; /* the -1 is the virtual */
+ }
+ }
+
+ /* adding dynamic hostname if needed*/
+ if (area->dynhostname) {
+ memset (buff,0x00,200);
+ sprintf (buff,"feedme%d",lsp_top_num);
+ tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 2); /* the 2 is for the TL */
+ *tlv_ptr = DYNAMIC_HOSTNAME; /* Type */
+ *(tlv_ptr+1) = strlen (buff); /* Length */
+ /* the -1 is to fit the length in the struct */
+ lsp->tlv_data.hostname = (struct hostname *)
+ (lsppdu_realloc (lsp, MTYPE_ISIS_TLV, strlen(buff)) - 1);
+ memcpy (lsp->tlv_data.hostname->name, buff, strlen(buff));
+ }
+
+ /* thanks to hannes, another bug bites the dust */
+ lsp->pdu->putp = ntohs(lsp->lsp_header->pdu_len);
+ lsp->pdu->endp = ntohs(lsp->lsp_header->pdu_len);
+}
+#endif /* TOPOLOGY_GENERATE */
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
new file mode 100644
index 00000000..71a75089
--- /dev/null
+++ b/isisd/isis_lsp.h
@@ -0,0 +1,132 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_lsp.h
+ * LSP processing
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_LSP_H
+#define _ZEBRA_ISIS_LSP_H
+
+/* 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 flags.h as well*/
+
+/* Structure for isis_lsp, this structure will only support the fixed
+ * System ID (Currently 6) (atleast for now). In order to support more
+ * We will have to split the header into two parts, and for readability
+ * sake it should better be avoided */
+struct isis_lsp
+{
+ struct isis_fixed_hdr *isis_header; /* normally equals pdu */
+ struct isis_link_state_hdr *lsp_header; /* pdu + isis_header_len */
+ struct stream *pdu; /* full pdu lsp */
+ union {
+ struct list *frags;
+ struct isis_lsp *zero_lsp;
+ } lspu;
+ u_int32_t SRMflags[ISIS_MAX_CIRCUITS];
+ u_int32_t SSNflags[ISIS_MAX_CIRCUITS];
+ u_int32_t rexmit_queue[ISIS_MAX_CIRCUITS];
+ int level; /* L1 or L2? */
+ int purged; /* have purged this one */
+ int scheduled; /* scheduled for sending */
+ time_t installed;
+ time_t last_generated;
+ time_t last_sent;
+ int own_lsp;
+#ifdef TOPOLOGY_GENERATE
+ int from_topology;
+ struct thread *t_lsp_top_ref;
+#endif
+ /* used for 60 second counting when rem_lifetime is zero */
+ int age_out;
+ struct isis_adjacency *adj;
+ struct tlvs tlv_data; /* Simplifies TLV access */
+};
+
+dict_t *lsp_db_init (void);
+void lsp_db_destroy (dict_t *lspdb);
+int lsp_tick (struct thread *thread);
+
+int lsp_l1_generate (struct isis_area *area);
+int lsp_l2_generate (struct isis_area *area);
+int lsp_refresh_l1 (struct thread *thread);
+int lsp_refresh_l2 (struct thread *thread);
+int lsp_regenerate_schedule (struct isis_area *area);
+
+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);
+int lsp_l2_refresh_pseudo (struct thread *thread);
+int isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
+ int pdulen, struct isis_passwd *passwd);
+struct isis_lsp *lsp_new (u_char *lsp_id, u_int16_t rem_lifetime,
+ u_int32_t seq_num, u_int8_t lsp_bits,
+ u_int16_t checksum, int level);
+struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream,
+ u_int16_t pdu_len,
+ struct isis_lsp *lsp0,
+ struct isis_area *area);
+void lsp_insert (struct isis_lsp *lsp, dict_t *lspdb);
+struct isis_lsp *lsp_search (u_char *id, dict_t *lspdb);
+
+void lsp_build_list (u_char *start_id, u_char *stop_id,
+ struct list *list, dict_t *lspdb);
+void lsp_build_list_nonzero_ht (u_char *start_id, u_char *stop_id,
+ struct list *list, dict_t *lspdb);
+void lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
+ dict_t *lspdb);
+
+void lsp_search_and_destroy (u_char *id, dict_t *lspdb);
+void lsp_purge_dr (u_char *id, struct isis_circuit *circuit, int level);
+void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
+ struct isis_area *area);
+
+#define LSP_EQUAL 1
+#define LSP_NEWER 2
+#define LSP_OLDER 3
+
+#define LSP_PSEUDO_ID(I) ((u_char)(I)[ISIS_SYS_ID_LEN])
+#define LSP_FRAGMENT(I) ((u_char)(I)[ISIS_SYS_ID_LEN + 1])
+#define OWNLSPID(I) \
+ memcpy ((I), isis->sysid, ISIS_SYS_ID_LEN);\
+ (I)[ISIS_SYS_ID_LEN] = 0;\
+ (I)[ISIS_SYS_ID_LEN + 1] = 0
+int lsp_id_cmp (u_char *id1, u_char *id2);
+int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
+ u_int16_t checksum, u_int16_t rem_lifetime);
+void lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
+ struct stream *stream, struct isis_area *area);
+void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num);
+int lsp_print_all (struct vty *vty, dict_t *lspdb, char detail, char dynhost);
+char *lsp_bits2string (u_char *);
+
+/* staticly assigned vars for printing purposes */
+char lsp_bits_string[200]; /* FIXME: enough ? */
+
+#ifdef TOPOLOGY_GENERATE
+void generate_topology_lsps (struct isis_area *area);
+void remove_topology_lsps (struct isis_area *area);
+void build_topology_lsp_data (struct isis_lsp *lsp,
+ struct isis_area *area, int lsp_top_num);
+#endif /* TOPOLOGY_GENERATE */
+
+#endif /* ISIS_LSP */
+
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
new file mode 100644
index 00000000..baf5f38d
--- /dev/null
+++ b/isisd/isis_main.c
@@ -0,0 +1,330 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_main.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 <stdio.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "getopt.h"
+#include "thread.h"
+#include "log.h"
+#include "version.h"
+#include "command.h"
+#include "vty.h"
+#include "memory.h"
+#include "stream.h"
+#include "if.h"
+
+#include "isisd/dict.h"
+#include "include-netbsd/iso.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_dynhn.h"
+
+/* Default configuration file name */
+#define ISISD_DEFAULT_CONFIG "isisd.conf"
+/* Default vty port */
+#define ISISD_VTY_PORT 2607
+
+/* isisd options */
+struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "version", no_argument, NULL, 'v'},
+ { "help", no_argument, NULL, 'h'},
+ { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = ISISD_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR ISISD_DEFAULT_CONFIG;
+char *config_file = NULL;
+
+/* isisd program name. */
+char *progname;
+
+int daemon_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+
+/* for reload */
+char _cwd[64];
+char _progpath[64];
+int _argc;
+char **_argv;
+char **_envp;
+
+
+/* Help information display. */
+static void
+usage (int status)
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+ else
+ {
+ printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages IS-IS routing\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-P, --vty_port Set vty's port number\n\
+-v, --version Print program version\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to sambo@cs.tut.fi\n", progname);
+ }
+
+ exit (status);
+}
+
+
+void
+reload ()
+{
+ zlog_info ("Reload");
+ /* FIXME: Clean up func call here */
+ vty_finish ();
+ execve (_progpath, _argv, _envp);
+}
+
+void
+terminate (int i)
+{
+ exit (i);
+}
+
+/*
+ * Signal handlers
+ */
+void
+sighup (int sig)
+{
+ zlog_info ("SIGHUP received");
+ reload ();
+
+ return;
+}
+
+void
+sigint (int sig)
+{
+ zlog_info ("SIGINT received");
+ terminate (0);
+
+ return;
+}
+
+void
+sigterm (int sig)
+{
+ zlog_info ("SIGTERM received");
+ terminate (0);
+}
+
+void
+sigusr1 (int sig)
+{
+ zlog_info ("SIGUSR1 received");
+ zlog_rotate (NULL);
+}
+
+/*
+ * Signal wrapper.
+ */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+ int ret;
+ struct sigaction sig;
+ struct sigaction osig;
+
+ sig.sa_handler = func;
+ sigemptyset (&sig.sa_mask);
+ sig.sa_flags = 0;
+#ifdef SA_RESTART
+ sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+ ret = sigaction (signo, &sig, &osig);
+
+ if (ret < 0)
+ return (SIG_ERR);
+ else
+ return (osig.sa_handler);
+}
+
+void
+signal_init ()
+{
+ signal_set (SIGHUP, sighup);
+ signal_set (SIGINT, sigint);
+ signal_set (SIGTERM, sigterm);
+ signal_set (SIGPIPE, SIG_IGN);
+#ifdef SIGTSTP
+ signal_set (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+ signal_set (SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ signal_set (SIGTTOU, SIG_IGN);
+#endif
+ signal_set (SIGUSR1, sigusr1);
+}
+
+/*
+ * Main routine of isisd. Parse arguments and handle IS-IS state machine.
+ */
+int
+main (int argc, char **argv, char **envp)
+{
+ char *p;
+ int opt, vty_port = ISISD_VTY_PORT;
+ struct thread thread;
+ char *config_file = NULL;
+ char *vty_addr = NULL;
+
+ /* Get the programname without the preceding path. */
+ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+ zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_ISIS,
+ LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+
+ /* for reload */
+ _argc = argc;
+ _argv = argv;
+ _envp = envp;
+ getcwd (_cwd, sizeof (_cwd));
+ if (*argv[0] == '.')
+ snprintf (_progpath, sizeof (_progpath), "%s/%s", _cwd, _argv[0]);
+ else
+ snprintf (_progpath, sizeof (_progpath), "%s", argv[0]);
+
+ /* Command line argument treatment. */
+ while (1)
+ {
+ opt = getopt_long (argc, argv, "df:hAp:P:v", longopts, 0);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt)
+ {
+ case 0:
+ break;
+ case 'd':
+ daemon_mode = 1;
+ break;
+ case 'f':
+ config_file = optarg;
+ break;
+ case 'A':
+ vty_addr = optarg;
+ break;
+ case 'P':
+ vty_port = atoi (optarg);
+ break;
+ case 'v':
+ printf("ISISd version %s\n", ISISD_VERSION);
+ printf("Copyright (c) 2001-2002 Sampo Saaristo,"
+ " Ofer Wald and Hannes Gredler\n");
+ print_version ("Zebra");
+ exit (0);
+ break;
+ case 'h':
+ usage (0);
+ break;
+ default:
+ usage (1);
+ break;
+ }
+ }
+
+ /* thread master */
+ master = thread_master_create ();
+
+ /* random seed from time */
+ srand(time(NULL));
+
+ /*
+ * initializations
+ */
+ signal_init ();
+ cmd_init (1);
+ vty_init ();
+ memory_init ();
+ isis_init ();
+ dyn_cache_init ();
+ sort_node ();
+
+ /* parse config file */
+ /* this is needed three times! because we have interfaces before the areas */
+ vty_read_config (config_file, config_current, config_default);
+#if 0
+ vty_read_config (config_file, config_current, config_default);
+ vty_read_config (config_file, config_current, config_default);
+#endif
+ /* demonize */
+ if (daemon_mode)
+ daemon (0, 0);
+
+ /* Problems with the build env ?*/
+#ifndef PATH_ISISD_PID
+#define PATH_ISISD_PID "/var/run/isisd.pid"
+#endif
+ /* Process ID file creation. */
+ pid_output (PATH_ISISD_PID);
+
+ /* Make isis vty socket. */
+ vty_serv_sock (vty_addr, vty_port ? vty_port : ISISD_VTY_PORT,
+ ISIS_VTYSH_PATH);
+
+ /* Print banner. */
+ zlog_info ("ISISd %s starting: vty@%d", ZEBRA_VERSION, vty_port);
+#ifdef HAVE_IPV6
+ zlog_info ("IPv6 enabled");
+#endif
+ /* Start finite state machine. */
+ while (thread_fetch (master, &thread))
+ thread_call (&thread);
+
+ /* Not reached. */
+ exit (0);
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
new file mode 100644
index 00000000..763ae243
--- /dev/null
+++ b/isisd/isis_misc.c
@@ -0,0 +1,438 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_misc.h
+ * Miscellanous routines
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+
+#include "stream.h"
+#include "vty.h"
+#include "hash.h"
+#include "if.h"
+
+#include "isisd/dict.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_misc.h"
+
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+
+/*
+ * This converts the isonet to its printable format
+ */
+char * isonet_print (u_char *from, int len) {
+ int i = 0;
+ char *pos = isonet;
+
+ if(!from)
+ return "unknown";
+
+ while (i < len) {
+ if (i & 1) {
+ sprintf ( pos, "%02x", *(from + i));
+ pos += 2;
+ } else {
+ if (i == 0) { /* if the area addr is just one byte, eg. 47. */
+ sprintf ( pos, "%02x", *(from + i));
+ pos += 2;
+ } else {
+ sprintf ( pos, "%02x.", *(from + i));
+ pos += 3;
+ }
+ }
+ i++;
+ }
+ *(pos) = '\0';
+ return isonet;
+}
+
+/*
+ * Returns 0 on error, length of buff on ok
+ * extract dot from the dotted str, and insert all the number in a buff
+ */
+int
+dotformat2buff (u_char *buff, u_char *dotted)
+{
+ int dotlen, len = 0;
+ u_char *pos = dotted;
+ u_char number[3];
+ int nextdotpos = 2;
+
+ number[2] = '\0';
+ dotlen = strlen(dotted);
+ if (dotlen > 50) {
+ /* this can't be an iso net, its too long */
+ return 0;
+ }
+
+ while ( (pos - dotted) < dotlen && len < 20 ) {
+ if (*pos == '.') {
+ /* we expect the . at 2, and than every 5 */
+ if ((pos - dotted) != nextdotpos) {
+ len = 0;
+ break;
+ }
+ nextdotpos += 5;
+ pos++;
+ continue;
+ }
+ /* we must have at least two chars left here */
+ if (dotlen - (pos - dotted) < 2) {
+ len = 0;
+ break;
+ }
+
+ if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos+1)))){
+ memcpy (number, pos ,2);
+ pos+=2;
+ } else {
+ len = 0;
+ break;
+ }
+
+ *(buff + len) = (char)strtol(number, NULL, 16);
+ len++;
+ }
+
+ return len;
+}
+/*
+ * conversion of XXXX.XXXX.XXXX to memory
+ */
+int
+sysid2buff (u_char *buff, u_char *dotted)
+ {
+ int len = 0;
+ u_char *pos = dotted;
+ u_char number[3];
+
+ number[2] = '\0';
+ // surely not a sysid_string if not 14 length
+ if (strlen(dotted) != 14) {
+ return 0;
+ }
+
+ while ( len < ISIS_SYS_ID_LEN ) {
+ if (*pos == '.') {
+ /* the . is not positioned correctly */
+ if (((pos - dotted) !=4) && ((pos - dotted) != 9)) {
+ len = 0;
+ break;
+ }
+ pos++;
+ continue;
+ }
+ if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos+1)))){
+ memcpy (number, pos ,2);
+ pos+=2;
+ } else {
+ len = 0;
+ break;
+ }
+
+ *(buff + len) = (char)strtol(number, NULL, 16);
+ len++;
+ }
+
+ return len;
+
+}
+
+/*
+ * converts the nlpids struct (filled by TLV #129)
+ * into a string
+ */
+
+char *
+nlpid2string (struct nlpids *nlpids) {
+ char *pos = nlpidstring;
+ int i;
+
+ for (i=0;i<nlpids->count;i++) {
+ switch (nlpids->nlpids[i]) {
+ case NLPID_IP:
+ pos += sprintf (pos, "IPv4");
+ break;
+ case NLPID_IPV6:
+ pos += sprintf (pos, "IPv6");
+ break;
+ default:
+ pos += sprintf (pos, "unknown");
+ break;
+ }
+ if (nlpids->count-i>1)
+ pos += sprintf (pos, ", ");
+
+ }
+
+ *(pos) = '\0';
+
+ return nlpidstring;
+}
+
+/*
+ * supports the given af ?
+ */
+int
+speaks (struct nlpids *nlpids, int family)
+{
+ int i, speaks = 0;
+
+ if (nlpids == (struct nlpids*)NULL)
+ return speaks;
+ for (i = 0;i < nlpids->count; i++) {
+ if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP)
+ speaks = 1;
+ if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6)
+ speaks = 1;
+ }
+
+ return speaks;
+}
+
+
+/*
+ * Returns 0 on error, IS-IS Circuit Type on ok
+ */
+int
+string2circuit_t (u_char *str)
+{
+
+ if (!str)
+ return 0;
+
+ if (!strcmp(str,"level-1"))
+ return IS_LEVEL_1;
+
+ if (!strcmp(str,"level-2-only") || !strcmp(str,"level-2"))
+ return IS_LEVEL_2;
+
+ if (!strcmp(str,"level-1-2"))
+ return IS_LEVEL_1_AND_2;
+
+ return 0;
+}
+
+const char *
+circuit_t2string (int circuit_t)
+{
+ switch (circuit_t) {
+ case IS_LEVEL_1:
+ return "L1";
+ case IS_LEVEL_2:
+ return "L2";
+ case IS_LEVEL_1_AND_2:
+ return "L1L2";
+ default:
+ return "??";
+ }
+
+ return NULL; /* not reached */
+}
+
+const char *
+syst2string (int type)
+{
+ switch (type) {
+ case ISIS_SYSTYPE_ES:
+ return "ES";
+ case ISIS_SYSTYPE_IS:
+ return "IS";
+ case ISIS_SYSTYPE_L1_IS:
+ return "1";
+ case ISIS_SYSTYPE_L2_IS:
+ return "2";
+ default:
+ return "??";
+ }
+
+ return NULL; /* not reached */
+}
+
+/*
+ * Print functions - we print to static vars
+ */
+char *
+snpa_print (u_char *from)
+{
+ int i = 0;
+ u_char *pos = snpa;
+
+ if(!from)
+ return "unknown";
+
+ while (i < ETH_ALEN - 1) {
+ if (i & 1) {
+ sprintf ( pos, "%02x.", *(from + i));
+ pos += 3;
+ } else {
+ sprintf ( pos, "%02x", *(from + i));
+ pos += 2;
+
+ }
+ i++;
+ }
+
+ sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
+ pos += 2;
+ *(pos) = '\0';
+
+ return snpa;
+}
+
+char *
+sysid_print (u_char *from)
+{
+ int i = 0;
+ char *pos = sysid;
+
+ if(!from)
+ return "unknown";
+
+ while (i < ISIS_SYS_ID_LEN - 1) {
+ if (i & 1) {
+ sprintf ( pos, "%02x.", *(from + i));
+ pos += 3;
+ } else {
+ sprintf ( pos, "%02x", *(from + i));
+ pos += 2;
+
+ }
+ i++;
+ }
+
+ sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
+ pos += 2;
+ *(pos) = '\0';
+
+ return sysid;
+}
+
+char *
+rawlspid_print (u_char *from)
+{
+ char *pos = lspid;
+ if(!from)
+ return "unknown";
+ memcpy(pos, sysid_print(from), 15);
+ pos += 14;
+ sprintf (pos, ".%02x", LSP_PSEUDO_ID(from));
+ pos += 3;
+ sprintf (pos, "-%02x", LSP_FRAGMENT(from));
+ pos += 3;
+
+ *(pos) = '\0';
+
+ return lspid;
+}
+
+char *
+time2string (u_int32_t time) {
+ char *pos = datestring;
+ u_int32_t rest;
+
+ if (time==0)
+ return "-";
+
+ if(time/SECS_PER_YEAR)
+ pos += sprintf (pos, "%uY",time/SECS_PER_YEAR);
+ rest=time%SECS_PER_YEAR;
+ if(rest/SECS_PER_MONTH)
+ pos += sprintf (pos, "%uM",rest/SECS_PER_MONTH);
+ rest=rest%SECS_PER_MONTH;
+ if(rest/SECS_PER_WEEK)
+ pos += sprintf (pos, "%uw",rest/SECS_PER_WEEK);
+ rest=rest%SECS_PER_WEEK;
+ if(rest/SECS_PER_DAY)
+ pos += sprintf (pos, "%ud",rest/SECS_PER_DAY);
+ rest=rest%SECS_PER_DAY;
+ if(rest/SECS_PER_HOUR)
+ pos += sprintf (pos, "%uh",rest/SECS_PER_HOUR);
+ rest=rest%SECS_PER_HOUR;
+ if(rest/SECS_PER_MINUTE)
+ pos += sprintf (pos, "%um",rest/SECS_PER_MINUTE);
+ rest=rest%SECS_PER_MINUTE;
+ if(rest)
+ pos += sprintf (pos, "%us",rest);
+
+ *(pos) = 0;
+
+ return datestring;
+}
+
+/*
+ * routine to decrement a timer by a random
+ * number
+ *
+ * first argument is the timer and the second is
+ * the jitter
+ */
+unsigned long
+isis_jitter (unsigned long timer, unsigned long jitter)
+{
+ int j,k;
+
+ if (jitter>=100)
+ return timer;
+
+ if (timer == 1)
+ return timer;
+ /*
+ * randomizing just the percent value provides
+ * no good random numbers - hence the spread
+ * to RANDOM_SPREAD (100000), which is ok as
+ * most IS-IS timers are no longer than 16 bit
+ */
+
+ j = 1 + (int) ((RANDOM_SPREAD * rand()) / (RAND_MAX + 1.0 ));
+
+ k = timer - (timer * (100 - jitter))/100;
+
+ timer = timer - (k * j / RANDOM_SPREAD);
+
+ return timer;
+}
+
+struct in_addr
+newprefix2inaddr (u_char *prefix_start, u_char prefix_masklen)
+{
+ memset(&new_prefix, 0, sizeof (new_prefix));
+ memcpy(&new_prefix, prefix_start, (prefix_masklen & 0x3F) ?
+ ((((prefix_masklen & 0x3F)-1)>>3)+1) : 0);
+ return new_prefix;
+}
+
+
+
+
+
diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h
new file mode 100644
index 00000000..0e219c65
--- /dev/null
+++ b/isisd/isis_misc.h
@@ -0,0 +1,94 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_misc.h
+ * Miscellanous routines
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_MISC_H
+#define _ZEBRA_ISIS_MISC_H
+
+int dotformat2buff (u_char *, u_char *);
+int string2circuit_t (u_char *);
+const char *circuit_t2string (int);
+const char *syst2string (int);
+struct in_addr newprefix2inaddr (u_char *prefix_start, u_char prefix_masklen);
+/*
+ * Converting input to memory stored format
+ * return value of 0 indicates wrong input
+ */
+int dotformat2buff (u_char *, u_char *);
+int sysid2buff (u_char *, u_char *);
+
+/*
+ * Printing functions
+ */
+char *isonet_print (u_char *, int len);
+char *sysid_print (u_char *);
+char *snpa_print (u_char *);
+char *rawlspid_print (u_char *);
+char *time2string (u_int32_t);
+/* typedef struct nlpids nlpids; */
+char *nlpid2string (struct nlpids *);
+
+
+/*
+ * misc functions
+ */
+int speaks (struct nlpids *nlpids, int family);
+unsigned long isis_jitter (unsigned long timer, unsigned long jitter);
+
+/*
+ * macros
+ */
+#define GETSYSID(A,L) (A->area_addr + (A->addr_len - (L + 1)))
+
+
+/* staticly assigned vars for printing purposes */
+struct in_addr new_prefix;
+/* len of xxxx.xxxx.xxxx + place for #0 termination */
+char sysid[15];
+/* len of xxxx.xxxx.xxxx + place for #0 termination */
+char snpa[15];
+/* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */
+char isonet[51];
+/* + place for #0 termination */
+/* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */
+char lspid[21];
+/* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
+char datestring[20];
+char nlpidstring[30];
+
+/* used for calculating nice string representation instead of plain seconds */
+
+#define SECS_PER_MINUTE 60
+#define SECS_PER_HOUR 3600
+#define SECS_PER_DAY 86400
+#define SECS_PER_WEEK 604800
+#define SECS_PER_MONTH 2628000
+#define SECS_PER_YEAR 31536000
+
+enum {
+ ISIS_UI_LEVEL_BRIEF,
+ ISIS_UI_LEVEL_DETAIL,
+ ISIS_UI_LEVEL_EXTENSIVE,
+};
+
+
+#endif
diff --git a/isisd/isis_network.c b/isisd/isis_network.c
new file mode 100644
index 00000000..d22f3dd8
--- /dev/null
+++ b/isisd/isis_network.c
@@ -0,0 +1,622 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <zebra.h>
+#include <net/ethernet.h> /* the L2 protocols */
+
+#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"
+
+/*
+ * 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
+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_info ("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", strerror (errno));
+ return ISIS_WARNING;
+ }
+
+ return ISIS_OK;
+}
+
+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", 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", 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
+
+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",
+ strerror (errno));
+ return ISIS_WARNING;
+ }
+
+ zlog_info ("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",
+ 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_info ("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");
+ }
+
+ /*
+ * 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");
+ }
+
+ /*
+ * ...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",
+ 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;
+
+
+#ifdef GNU_LINUX
+ retval = open_packet_socket (circuit);
+#else
+ retval = open_bpf_dev (circuit);
+#endif
+
+ if (retval == ISIS_OK) {
+ 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;
+ }
+ }
+
+ 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, &addr_len);
+
+ if (bytesread < 0) {
+ zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
+ circuit->fd, 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, &addr_len);
+
+ /* then we lose the LLC */
+ memcpy (STREAM_DATA (circuit->rcv_stream),
+ sock_buff + LLC_LEN, bytesread - LLC_LEN);
+ circuit->rcv_stream->putp = bytesread - LLC_LEN;
+ circuit->rcv_stream->endp = 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 = recvfrom (circuit->fd, STREAM_DATA (circuit->rcv_stream),
+ circuit->interface->mtu, 0,
+ (struct sockaddr *)&s_addr, &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;
+ }
+
+ circuit->rcv_stream->putp = bytesread;
+ circuit->rcv_stream->endp = bytesread;
+
+ /* 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,
+ circuit->snd_stream->putp + 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,
+ circuit->snd_stream->putp, 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", strerror (errno));
+ }
+
+ if (bytestoread) {
+ bytesread = read (circuit->fd, readbuff, readblen);
+ }
+ if (bytesread < 0) {
+ zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s", 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 */
+ memcpy (STREAM_DATA (circuit->rcv_stream),
+ readbuff + offset,
+ bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
+
+ circuit->rcv_stream->putp = bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN;
+ circuit->rcv_stream->endp = bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN;
+ circuit->rcv_stream->getp = 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", strerror (errno));
+
+ return ISIS_OK;
+}
+
+int
+isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char *ssnpa)
+{
+ int bytesread;
+
+ bytesread = read (circuit->fd, STREAM_DATA(circuit->rcv_stream),
+ circuit->interface->mtu);
+
+ if (bytesread < 0) {
+ zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", strerror (errno));
+ return ISIS_WARNING;
+ }
+
+ circuit->rcv_stream->putp = bytesread;
+ circuit->rcv_stream->endp = bytesread;
+
+ 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,
+ circuit->snd_stream->putp + 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_network.h b/isisd/isis_network.h
new file mode 100644
index 00000000..7633f9e0
--- /dev/null
+++ b/isisd/isis_network.h
@@ -0,0 +1,37 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_network.h
+ *
+ * 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.
+ */
+
+
+#ifndef _ZEBRA_ISIS_NETWORK_H
+#define _ZEBRA_ISIS_NETWORK_H
+
+extern u_char ALL_L1_ISYSTEMS[];
+extern u_char ALL_L2_ISYSTEMS[];
+
+int isis_sock_init (struct isis_circuit *circuit);
+
+int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char *ssnpa);
+int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char *ssnpa);
+int isis_send_pdu_bcast (struct isis_circuit *circuit, int level);
+int isis_send_pdu_p2p (struct isis_circuit *circuit, int level);
+
+#endif /* _ZEBRA_ISIS_NETWORK_H */
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
new file mode 100644
index 00000000..8d636b30
--- /dev/null
+++ b/isisd/isis_pdu.c
@@ -0,0 +1,2478 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_pdu.c
+ * PDU processing
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "memory.h"
+#include "thread.h"
+#include "linklist.h"
+#include "log.h"
+#include "stream.h"
+#include "vty.h"
+#include "hash.c"
+#include "prefix.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_adjacency.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/iso_checksum.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_events.h"
+
+extern struct thread_master *master;
+extern struct isis *isis;
+
+#define ISIS_MINIMUM_FIXED_HDR_LEN 15
+#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
+
+#ifndef PNBBY
+#define PNBBY 8
+#endif /* PNBBY */
+
+/* Utility mask array. */
+static u_char maskbit[] =
+{
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+};
+
+/*
+ * HELPER FUNCS
+ */
+
+/*
+ * Compares two sets of area addresses
+ */
+static int
+area_match (struct list *left, struct list *right)
+{
+ struct area_addr *addr1, *addr2;
+ struct listnode *node1, *node2;
+
+ LIST_LOOP (left, addr1, node1) {
+ LIST_LOOP (right, addr2, node2) {
+ if (addr1->addr_len == addr2->addr_len &&
+ !memcmp (addr1->area_addr, addr2->area_addr, (int)addr1->addr_len))
+ return 1; /* match */
+ }
+ }
+
+ return 0; /* mismatch */
+}
+
+/*
+ * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
+ * param ip1 the IS interface ip address structure
+ * param ip2 the IIH's ip address
+ * return 0 the IIH's IP is not in the IS's subnetwork
+ * 1 the IIH's IP is in the IS's subnetwork
+ */
+int
+ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
+{
+ u_char *addr1, *addr2;
+ int shift, offset;
+ int len;
+
+ addr1 = (u_char *) &ip1->prefix.s_addr;
+ addr2 = (u_char *) &ip2->s_addr;
+ len = ip1->prefixlen;
+
+ shift = len % PNBBY;
+ offset = len / PNBBY;
+
+ while (offset--) {
+ if (addr1[offset] != addr2[offset]) {
+ return 0;
+ }
+ }
+
+ if (shift) {
+ if (maskbit[shift] & (addr1[offset] ^ addr2[offset])) {
+ return 0;
+ }
+ }
+
+ return 1; /* match */
+}
+
+
+/*
+ * Compares two set of ip addresses
+ * param left the local interface's ip addresses
+ * param right the iih interface's ip address
+ * return 0 no match;
+ * 1 match;
+ */
+static int
+ip_match (struct list *left, struct list *right)
+{
+ struct prefix_ipv4 *ip1;
+ struct in_addr *ip2;
+ struct listnode *node1, *node2;
+
+ LIST_LOOP (left, ip1, node1) {
+ LIST_LOOP (right, ip2, node2) {
+ if (ip_same_subnet(ip1, ip2)) {
+ return 1; /* match */
+ }
+ }
+
+ }
+ return 0;
+}
+
+/*
+ * Checks whether we should accept a PDU of given level
+ */
+static int
+accept_level (int level, int circuit_t)
+{
+ int retval = ((circuit_t & level) == level); /* simple approach */
+
+ return retval;
+}
+
+int
+authentication_check (struct isis_passwd *one, struct isis_passwd *theother)
+{
+ if (one->type != theother->type) {
+ zlog_warn ("Unsupported authentication type %d", theother->type );
+ return 1; /* Auth fail (different authentication types)*/
+ }
+ switch (one->type) {
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ if (one->len != theother->len)
+ return 1; /* Auth fail () - passwd len mismatch */
+ return memcmp (one->passwd, theother->passwd, one->len);
+ break;
+ default:
+ zlog_warn ("Unsupported authentication type");
+ break;
+ }
+ return 0; /* Auth pass */
+}
+
+/*
+ * Processing helper functions
+ */
+void
+tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
+{
+ int i;
+ struct nlpids *tlv_nlpids;
+
+ if (tlvs->nlpids) {
+
+ tlv_nlpids = tlvs->nlpids;
+
+ adj->nlpids.count = tlv_nlpids->count;
+
+ for (i=0;i<tlv_nlpids->count;i++) {
+ adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
+ }
+ }
+}
+
+void
+del_ip_addr (void *val)
+{
+ XFREE (MTYPE_ISIS_TMP, val);
+}
+
+void
+tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
+{
+ struct listnode *node;
+ struct in_addr *ipv4_addr, *malloced;
+
+ if (adj->ipv4_addrs) {
+ adj->ipv4_addrs->del = del_ip_addr;
+ list_delete (adj->ipv4_addrs);
+ }
+ adj->ipv4_addrs = list_new ();
+ if (tlvs->ipv4_addrs) {
+ LIST_LOOP (tlvs->ipv4_addrs, ipv4_addr, node) {
+ malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr));
+ memcpy (malloced, ipv4_addr, sizeof (struct in_addr));
+ listnode_add (adj->ipv4_addrs, malloced);
+ }
+ }
+}
+
+#ifdef HAVE_IPV6
+void
+tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
+{
+ struct listnode *node;
+ struct in6_addr *ipv6_addr, *malloced;
+
+ if (adj->ipv6_addrs) {
+ adj->ipv6_addrs->del = del_ip_addr;
+ list_delete (adj->ipv6_addrs);
+ }
+ adj->ipv6_addrs = list_new ();
+ if (tlvs->ipv6_addrs) {
+ LIST_LOOP (tlvs->ipv6_addrs, ipv6_addr, node) {
+ malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr));
+ memcpy (malloced, ipv6_addr, sizeof (struct in6_addr));
+ listnode_add (adj->ipv6_addrs, malloced);
+ }
+ }
+
+}
+#endif /* HAVE_IPV6 */
+
+
+
+/*
+ * RECEIVE SIDE
+ */
+
+/*
+ * Process P2P IIH
+ * ISO - 10589
+ * Section 8.2.5 - Receiving point-to-point IIH PDUs
+ *
+ */
+static int
+process_p2p_hello (struct isis_circuit *circuit)
+{
+ int retval = ISIS_OK;
+ struct isis_p2p_hello_hdr *hdr;
+ struct isis_adjacency *adj;
+ u_int32_t expected = 0, found;
+ struct tlvs tlvs;
+
+ if ((stream_get_endp (circuit->rcv_stream) -
+ stream_get_getp (circuit->rcv_stream)) <
+ ISIS_P2PHELLO_HDRLEN) {
+ zlog_warn ("Packet too short");
+ return ISIS_WARNING;
+ }
+
+ /* 8.2.5.1 PDU acceptance tests */
+
+ /* 8.2.5.1 a) external domain untrue */
+ /* FIXME: not useful at all? */
+
+ /* 8.2.5.1 b) ID Length mismatch */
+ /* checked at the handle_pdu */
+
+ /* 8.2.5.2 IIH PDU Processing */
+
+ /* 8.2.5.2 a) 1) Maximum Area Addresses */
+ /* Already checked, and can also be ommited */
+
+ /*
+ * Get the header
+ */
+ hdr = (struct isis_p2p_hello_hdr*) STREAM_PNT(circuit->rcv_stream);
+ circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN;
+
+ /* hdr.circuit_t = stream_getc (stream);
+ stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
+ hdr.hold_time = stream_getw (stream);
+ hdr.pdu_len = stream_getw (stream);
+ hdr.local_id = stream_getc (stream); */
+
+ /*
+ * My interpertation of the ISO, if no adj exists we will create one for
+ * the circuit
+ */
+
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_info("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
+ " cir id %02d, length %d",
+ circuit->area->area_tag, circuit->interface->name,
+ circuit_t2string(circuit->circuit_is_type),
+ circuit->circuit_id,ntohs(hdr->pdu_len));
+ }
+
+ adj = circuit->u.p2p.neighbor;
+ if ( !adj ) {
+ adj = isis_new_adj (hdr->source_id," ", 0, circuit);
+ if (adj == NULL)
+ return ISIS_ERROR;
+ circuit->u.p2p.neighbor = adj;
+ isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
+ adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
+ }
+
+ /* 8.2.6 Monitoring point-to-point adjacencies */
+ adj->hold_time = ntohs (hdr->hold_time);
+ adj->last_upd = time (NULL);
+
+ /*
+ * Lets get the TLVS now
+ */
+ expected |= TLVFLAG_AREA_ADDRS;
+ expected |= TLVFLAG_AUTH_INFO;
+ expected |= TLVFLAG_NLPID;
+ expected |= TLVFLAG_IPV4_ADDR;
+ expected |= TLVFLAG_IPV6_ADDR;
+
+ retval = parse_tlvs (circuit->area->area_tag,
+ STREAM_PNT (circuit->rcv_stream),
+ ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN
+ - ISIS_FIXED_HDR_LEN,
+ &expected,
+ &found,
+ &tlvs);
+
+ if (retval > ISIS_WARNING) {
+ free_tlvs (&tlvs);
+ return retval;
+ };
+
+ /* 8.2.5.1 c) Authentication */
+ if (circuit->passwd.type) {
+ if (!(found & TLVFLAG_AUTH_INFO) ||
+ authentication_check (&circuit->passwd, &tlvs.auth_info)) {
+ isis_event_auth_failure (circuit->area->area_tag,
+ "P2P hello authentication failure",
+ hdr->source_id);
+ return ISIS_OK;
+ }
+ }
+
+ /* we do this now because the adj may not survive till the end... */
+
+ /* we need to copy addresses to the adj */
+ tlvs_to_adj_ipv4_addrs (&tlvs,adj);
+
+#ifdef HAVE_IPV6
+ tlvs_to_adj_ipv6_addrs (&tlvs,adj);
+#endif /* HAVE_IPV6 */
+
+ /* lets take care of the expiry */
+ if(adj->t_expire) {
+ thread_cancel (adj->t_expire);
+ }
+ adj->t_expire = thread_add_timer (master, isis_adj_expire, adj,
+ (long)adj->hold_time);
+
+ /* 8.2.5.2 a) a match was detected */
+ if (area_match (circuit->area->area_addrs, tlvs.area_addrs)) {
+ /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
+ if (circuit->area->is_type == IS_LEVEL_1) {
+ switch (hdr->circuit_t) {
+ case IS_LEVEL_1:
+ case IS_LEVEL_1_AND_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (4) adj state up */
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
+ /* (5) adj usage level 1 */
+ adj->adj_usage = ISIS_ADJ_LEVEL1;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ ; /* accept */
+ }
+ break;
+ case IS_LEVEL_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (7) reject - wrong system type event */
+ zlog_warn ("wrongSystemType");
+ return ISIS_WARNING; /* Reject */
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ /* (6) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ }
+ break;
+ }
+ }
+
+ /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
+ if (circuit->area->is_type == IS_LEVEL_1_AND_2) {
+ switch (hdr->circuit_t) {
+ case IS_LEVEL_1:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (6) adj state up */
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
+ /* (7) adj usage level 1 */
+ adj->adj_usage = ISIS_ADJ_LEVEL1;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ ; /* accept */
+ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
+ (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
+ /* (8) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ }
+ break;
+ case IS_LEVEL_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (6) adj state up */
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
+ /* (9) adj usage level 2 */
+ adj->adj_usage = ISIS_ADJ_LEVEL2;
+ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
+ (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) {
+ /* (8) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ ; /* Accept */
+ }
+ break;
+ case IS_LEVEL_1_AND_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (6) adj state up */
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
+ /* (10) adj usage level 1 */
+ adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
+ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
+ (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
+ /* (8) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
+ ; /* Accept */
+ }
+ break;
+ }
+ }
+
+ /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
+ if (circuit->area->is_type == IS_LEVEL_2) {
+ switch (hdr->circuit_t) {
+ case IS_LEVEL_1:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (5) reject - wrong system type event */
+ zlog_warn ("wrongSystemType");
+ return ISIS_WARNING; /* Reject */
+ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
+ (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
+ /* (6) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ }
+ break;
+ case IS_LEVEL_1_AND_2:
+ case IS_LEVEL_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (7) adj state up */
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
+ /* (8) adj usage level 2 */
+ adj->adj_usage = ISIS_ADJ_LEVEL2;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
+ /* (6) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ ; /* Accept */
+ }
+ break;
+ }
+ }
+ }
+ /* 8.2.5.2 b) if no match was detected */
+ else
+ {
+ if (circuit->area->is_type == IS_LEVEL_1) {
+ /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
+ /* 8.2.5.2 b) 2)is_type L1 and adj is up */
+ } else {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Down - Area Mismatch");
+ }
+ }
+ /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
+ else
+ {
+ switch (hdr->circuit_t) {
+ case IS_LEVEL_1:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (6) reject - Area Mismatch event */
+ zlog_warn ("AreaMismatch");
+ return ISIS_WARNING; /* Reject */
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ /* (7) down - area mismatch */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
+
+ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
+ (adj->adj_usage == ISIS_ADJ_LEVEL2)) {
+ /* (7) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ }
+ break;
+ case IS_LEVEL_1_AND_2:
+ case IS_LEVEL_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* (8) adj state up */
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
+ /* (9) adj usage level 2 */
+ adj->adj_usage = ISIS_ADJ_LEVEL2;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ /* (7) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
+ if (hdr->circuit_t == IS_LEVEL_2) {
+ /* (7) down - wrong system */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
+ } else {
+ /* (7) down - area mismatch */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
+ }
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ ; /* Accept */
+ }
+ break;
+ }
+ }
+ }
+ /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
+ /* FIXME - Missing parts */
+
+
+ /* some of my own understanding of the ISO, why the heck does
+ * it not say what should I change the system_type to...
+ */
+ switch (adj->adj_usage) {
+ case ISIS_ADJ_LEVEL1:
+ adj->sys_type = ISIS_SYSTYPE_L1_IS;
+ break;
+ case ISIS_ADJ_LEVEL2:
+ adj->sys_type = ISIS_SYSTYPE_L2_IS;
+ break;
+ case ISIS_ADJ_LEVEL1AND2:
+ adj->sys_type = ISIS_SYSTYPE_L2_IS;
+ break;
+ case ISIS_ADJ_NONE:
+ adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
+ break;
+ }
+
+ adj->circuit_t = hdr->circuit_t;
+ adj->level = hdr->circuit_t;
+
+ free_tlvs (&tlvs);
+
+ return retval;
+}
+
+
+/*
+ * Process IS-IS LAN Level 1/2 Hello PDU
+ */
+static int
+process_lan_hello (int level, struct isis_circuit *circuit, u_char *ssnpa)
+{
+ int retval = ISIS_OK;
+ struct isis_lan_hello_hdr hdr;
+ struct isis_adjacency *adj;
+ u_int32_t expected = 0, found;
+ struct tlvs tlvs;
+ u_char *snpa;
+ struct listnode *node;
+
+ if ((stream_get_endp (circuit->rcv_stream) -
+ stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN) {
+ zlog_warn ("Packet too short");
+ return ISIS_WARNING;
+ }
+
+ if (circuit->ext_domain) {
+ zlog_info ("level %d LAN Hello received over circuit with "
+ "externalDomain = true", level);
+ return ISIS_WARNING;
+ }
+
+ if (!accept_level (level, circuit->circuit_is_type)) {
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_info ("ISIS-Adj (%s): Interface level mismatch, %s",
+ circuit->area->area_tag, circuit->interface->name);
+ }
+ return ISIS_WARNING;
+ }
+
+#if 0
+ /* Cisco's debug message compatability */
+ if (!accept_level (level, circuit->area->is_type)) {
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_info ("ISIS-Adj (%s): is type mismatch",
+ circuit->area->area_tag);
+ }
+ return ISIS_WARNING;
+ }
+#endif
+ /*
+ * Fill the header
+ */
+ hdr.circuit_t = stream_getc (circuit->rcv_stream);
+ stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
+ hdr.hold_time = stream_getw (circuit->rcv_stream);
+ hdr.pdu_len = stream_getw (circuit->rcv_stream);
+ hdr.prio = stream_getc (circuit->rcv_stream);
+ stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
+
+ if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 &&
+ hdr.circuit_t != IS_LEVEL_1_AND_2 ) {
+ zlog_warn ("Level %d LAN Hello with Circuit Type %d", level,
+ hdr.circuit_t);
+ return ISIS_ERROR;
+ }
+ /*
+ * Then get the tlvs
+ */
+ expected |= TLVFLAG_AUTH_INFO;
+ expected |= TLVFLAG_AREA_ADDRS;
+ expected |= TLVFLAG_LAN_NEIGHS;
+ expected |= TLVFLAG_NLPID;
+ expected |= TLVFLAG_IPV4_ADDR;
+ expected |= TLVFLAG_IPV6_ADDR;
+
+ retval = parse_tlvs (circuit->area->area_tag,
+ STREAM_PNT (circuit->rcv_stream),
+ hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
+ &expected,
+ &found,
+ &tlvs);
+
+ if (retval > ISIS_WARNING) {
+ zlog_warn ("parse_tlvs() failed");
+ goto out;
+ }
+
+ if (!(found & TLVFLAG_AREA_ADDRS)) {
+ zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello", level);
+ retval = ISIS_WARNING;
+ goto out;
+ }
+
+ if (circuit->passwd.type) {
+ if (!(found & TLVFLAG_AUTH_INFO) ||
+ authentication_check (&circuit->passwd, &tlvs.auth_info)) {
+ isis_event_auth_failure (circuit->area->area_tag,
+ "LAN hello authentication failure",
+ hdr.source_id);
+ retval = ISIS_WARNING;
+ goto out;
+ }
+ }
+
+ /*
+ * Accept the level 1 adjacency only if a match between local and
+ * remote area addresses is found
+ */
+ if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs)) {
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_info ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
+ circuit->area->area_tag, level,circuit->interface->name);
+ }
+ retval = ISIS_OK;
+ goto out;
+ }
+
+ /*
+ * it's own IIH PDU - discard silently
+ */
+ if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN)) {
+ zlog_info ("ISIS-Adj (%s): it's own IIH PDU - discarded",
+ circuit->area->area_tag);
+
+ retval = ISIS_OK;
+ goto out;
+ }
+
+ /*
+ * check if it's own interface ip match iih ip addrs
+ */
+ if (!(found & TLVFLAG_IPV4_ADDR) || !ip_match(circuit->ip_addrs, tlvs.ipv4_addrs)) {
+ zlog_info("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
+ circuit->interface->name);
+ retval = ISIS_WARNING;
+ goto out;
+ }
+
+
+ adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
+ if (!adj) {
+ /*
+ * Do as in 8.4.2.5
+ */
+ adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
+ if (adj == NULL)
+ retval = ISIS_ERROR;
+ goto out;
+
+ adj->level = level;
+ isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
+
+ if (level == 1) {
+ adj->sys_type = ISIS_SYSTYPE_L1_IS;
+ } else {
+ adj->sys_type = ISIS_SYSTYPE_L2_IS;
+ }
+ 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]);
+ }
+
+ switch (level) {
+ case 1 :
+ if (memcmp(circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) {
+ thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+ memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+ }
+ break;
+ case 2 :
+ if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) {
+ thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+ memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+ }
+ break;
+ }
+
+#if 0
+ /* Old solution: believe the lan-header always
+ */
+ if (level == 1) {
+ memcpy(circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+ } else if (level == 2) {
+ memcpy(circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+ }
+#endif
+
+ adj->hold_time = hdr.hold_time;
+ adj->last_upd = time (NULL);
+ adj->prio[level-1] = hdr.prio;
+
+ memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+
+ /* which protocol are spoken ??? */
+ if (found & TLVFLAG_NLPID)
+ tlvs_to_adj_nlpids (&tlvs, adj);
+
+ /* we need to copy addresses to the adj */
+ if (found & TLVFLAG_IPV4_ADDR)
+ tlvs_to_adj_ipv4_addrs (&tlvs, adj);
+
+#ifdef HAVE_IPV6
+ if (found & TLVFLAG_IPV6_ADDR)
+ tlvs_to_adj_ipv6_addrs (&tlvs, adj);
+#endif /* HAVE_IPV6 */
+
+ adj->circuit_t = hdr.circuit_t;
+
+ /* lets take care of the expiry */
+ if (adj->t_expire) {
+ thread_cancel (adj->t_expire);
+ }
+ adj->t_expire = thread_add_timer (master, isis_adj_expire, adj,
+ (long)adj->hold_time);
+
+ /*
+ * If the snpa for this circuit is found from LAN Neighbours TLV
+ * we have two-way communication -> adjacency can be put to state "up"
+ */
+
+ if (found & TLVFLAG_LAN_NEIGHS) {
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ LIST_LOOP (tlvs.lan_neighs, snpa, node)
+ if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) {
+ isis_adj_state_change (adj, ISIS_ADJ_UP,
+ "own SNPA found in LAN Neighbours TLV");
+ }
+ }
+ }
+
+ out:
+ /* DEBUG_ADJ_PACKETS */
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ /* FIXME: is this place right? fix missing info */
+ zlog_info ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
+ "cirID %u, length %ld",
+ circuit->area->area_tag,
+ level,snpa_print(ssnpa), circuit->interface->name,
+ circuit_t2string(circuit->circuit_is_type),
+ circuit->circuit_id,
+ stream_get_endp (circuit->rcv_stream));
+ }
+
+
+ free_tlvs (&tlvs);
+
+ return retval;
+}
+
+/*
+ * Process Level 1/2 Link State
+ * ISO - 10589
+ * Section 7.3.15.1 - Action on receipt of a link state PDU
+ */
+static int
+process_lsp (int level, struct isis_circuit *circuit, u_char *ssnpa)
+{
+ struct isis_link_state_hdr *hdr;
+ struct isis_adjacency *adj = NULL;
+ struct isis_lsp *lsp, *lsp0 = NULL;
+ int retval = ISIS_OK, comp = 0;
+ u_char lspid[ISIS_SYS_ID_LEN + 2];
+ struct isis_passwd *passwd;
+
+ /* Sanity check - FIXME: move to correct place */
+ if ((stream_get_endp (circuit->rcv_stream) -
+ stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN ) {
+ zlog_warn ("Packet too short");
+ return ISIS_WARNING;
+ }
+
+ /* Reference the header */
+ hdr = (struct isis_link_state_hdr*)STREAM_PNT (circuit->rcv_stream);
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS) {
+ zlog_info ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
+ "lifetime %us, len %lu, on %s",
+ circuit->area->area_tag,
+ level,
+ rawlspid_print(hdr->lsp_id),
+ ntohl(hdr->seq_num),
+ ntohs(hdr->checksum),
+ ntohs(hdr->rem_lifetime),
+ circuit->rcv_stream->endp,
+ circuit->interface->name);
+ }
+
+ assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN);
+
+ /* Checksum sanity check - FIXME: move to correct place */
+ /* 12 = sysid+pdu+remtime */
+ if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
+ ntohs (hdr->pdu_len) - 12, &hdr->checksum)) {
+ zlog_info ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id),
+ ntohs(hdr->checksum));
+
+ return ISIS_WARNING;
+ }
+
+ /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
+ if (circuit->ext_domain) {
+ zlog_info ("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
+ "externalDomain = true",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id),
+ level);
+
+ return ISIS_WARNING;
+ }
+
+ /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
+ if (!accept_level (level, circuit->circuit_is_type)) {
+ zlog_info ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
+ " type %s",
+ circuit->area->area_tag,
+ rawlspid_print(hdr->lsp_id),
+ level,
+ circuit_t2string (circuit->circuit_is_type));
+
+ return ISIS_WARNING;
+ }
+
+ /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
+
+ /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
+
+ /* 7.3.15.1 a) 7 - password check */
+ (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) :
+ (passwd = &circuit->area->domain_passwd);
+ if (passwd->type) {
+ if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area,
+ ntohs (hdr->pdu_len), passwd)) {
+ isis_event_auth_failure (circuit->area->area_tag,
+ "LSP authentication failure",
+ hdr->lsp_id);
+ return ISIS_WARNING;
+ }
+ }
+ /* Find the LSP in our database and compare it to this Link State header */
+ lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]);
+ if (lsp)
+ comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num,
+ hdr->checksum, hdr->rem_lifetime);
+ if (lsp && (lsp->own_lsp
+#ifdef TOPOLOGY_GENERATE
+ || lsp->from_topology
+#endif /* TOPOLOGY_GENERATE */
+ ))
+ goto dontcheckadj;
+
+ /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
+ /* for broadcast circuits, snpa should be compared */
+ /* FIXME : Point To Point */
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]);
+ if (!adj) {
+ zlog_info ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
+ "lifetime %us on %s",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id),
+ ntohl (hdr->seq_num),
+ ntohs (hdr->checksum),
+ ntohs (hdr->rem_lifetime),
+ circuit->interface->name);
+ return ISIS_WARNING; /* Silently discard */
+ }
+ }
+
+ /* for non broadcast, we just need to find same level adj */
+ else {
+ /* If no adj, or no sharing of level */
+ if (!circuit->u.p2p.neighbor) {
+ return ISIS_OK; /* Silently discard */
+ } else {
+ if (((level == 1) &&
+ (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
+ ((level == 2) &&
+ (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
+ return ISIS_WARNING; /* Silently discard */
+ }
+ }
+ dontcheckadj:
+ /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
+
+ /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */
+
+ /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it*/
+
+
+ /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4*/
+ if (hdr->rem_lifetime == 0) {
+ if (!lsp) {
+ /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
+ /* only needed on explicit update, eg - p2p */
+ if (circuit->circ_type == CIRCUIT_T_P2P)
+ ack_lsp (hdr, circuit, level);
+ return retval; /* FIXME: do we need a purge? */
+ } else {
+ if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN )) {
+ /* LSP by some other system -> do 7.3.16.4 b) */
+ /* 7.3.16.4 b) 1) */
+ if (comp == LSP_NEWER) {
+ lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area);
+ /* ii */
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ /* iii */
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+ /* v */
+ ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags); /* FIXME: OTHER than c */
+ /* iv */
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ ISIS_SET_FLAG(lsp->SSNflags, circuit);
+
+ } /* 7.3.16.4 b) 2) */
+ else if (comp == LSP_EQUAL) {
+ /* i */
+ ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+ /* ii*/
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ ISIS_SET_FLAG(lsp->SSNflags, circuit);
+ } /* 7.3.16.4 b) 3) */
+ else {
+ ISIS_SET_FLAG(lsp->SRMflags, circuit);
+ ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
+ }
+ } else {
+ /* our own LSP -> 7.3.16.4 c) */
+ if (LSP_PSEUDO_ID(lsp->lsp_header->lsp_id) != circuit->circuit_id ||
+ (LSP_PSEUDO_ID(lsp->lsp_header->lsp_id) == circuit->circuit_id &&
+ circuit->u.bc.is_dr[level - 1] == 1) ) {
+ lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
+ zlog_info ("LSP LEN: %d", ntohs (lsp->lsp_header->pdu_len));
+ iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+ ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ zlog_info ("ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08x",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id),
+ ntohl (lsp->lsp_header->seq_num));
+ lsp->lsp_header->rem_lifetime = htons (isis_jitter
+ (circuit->area->
+ max_lsp_lifetime[level-1],
+ MAX_AGE_JITTER));
+
+ } else {
+ /* Got purge for own pseudo-lsp, and we are not DR */
+ lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level);
+ }
+ }
+ }
+ return retval;
+ }
+ /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
+ * purge */
+ if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN ) == 0) {
+ if (!lsp) {
+ /* 7.3.16.4: initiate a purge */
+ lsp_purge_non_exist (hdr, circuit->area);
+ return ISIS_OK;
+ }
+ /* 7.3.15.1 d) - If this is our own lsp and we have it */
+
+ /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
+ * has information that the current sequence number for source S is
+ * "greater" than that held by S, ... */
+
+ else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) {
+ /* 7.3.16.1 */
+ lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
+
+ iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+ ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ zlog_info ("ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08x",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id),
+ ntohl (lsp->lsp_header->seq_num));
+ lsp->lsp_header->rem_lifetime = htons (isis_jitter
+ (circuit->
+ area->max_lsp_lifetime[level-1],
+ MAX_AGE_JITTER));
+
+ }
+ } else {
+ /* 7.3.15.1 e) - This lsp originated on another system */
+
+ /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
+ if ((!lsp || comp == LSP_NEWER)){
+ /* i */
+ if (lsp) {
+#ifdef EXTREME_DEBUG
+ zlog_info ("level %d number is - %ld", level,
+ circuit->area->lspdb[level-1]->dict_nodecount);
+#endif /* EXTREME DEBUG */
+ lsp_search_and_destroy (hdr->lsp_id, circuit->area->lspdb[level-1]);
+ /* exists, so we overwrite */
+#ifdef EXTREME_DEBUG
+ zlog_info ("level %d number is - %ld",level,
+ circuit->area->lspdb[level-1]->dict_nodecount);
+#endif /* EXTREME DEBUG */
+ }
+ /*
+ * If this lsp is a frag, need to see if we have zero lsp present
+ */
+ if (LSP_FRAGMENT (hdr->lsp_id) != 0) {
+ memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
+ LSP_FRAGMENT (lspid) = 0;
+ lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
+ if (!lsp0) {
+ zlog_info ("Got lsp frag, while zero lsp not database");
+ return ISIS_OK;
+ }
+ }
+ lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, ntohs (hdr->pdu_len),
+ lsp0, circuit->area);
+ lsp->level = level;
+ lsp->adj = adj;
+ lsp_insert (lsp, circuit->area->lspdb[level-1]);
+ /* ii */
+ ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ /* iii */
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+
+ /* iv */
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ ISIS_SET_FLAG (lsp->SSNflags, circuit);
+ /* FIXME: v) */
+ }
+ /* 7.3.15.1 e) 2) LSP equal to the one in db */
+ else if (comp == LSP_EQUAL) {
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+ lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area);
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ ISIS_SET_FLAG (lsp->SSNflags, circuit);
+ }
+ }
+ /* 7.3.15.1 e) 3) LSP older than the one in db */
+ else {
+ ISIS_SET_FLAG(lsp->SRMflags, circuit);
+ ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
+ }
+ }
+ if (lsp)
+ lsp->adj = adj;
+ return retval;
+}
+
+/*
+ * Process Sequence Numbers
+ * ISO - 10589
+ * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
+ */
+
+int
+process_snp (int snp_type, int level, struct isis_circuit *circuit,
+ u_char *ssnpa)
+{
+ int retval = ISIS_OK;
+ int cmp, own_lsp;
+ char typechar = ' ';
+ int len;
+ struct isis_adjacency *adj;
+ struct isis_complete_seqnum_hdr *chdr = NULL;
+ struct isis_partial_seqnum_hdr *phdr = NULL;
+ uint32_t found = 0, expected = 0;
+ struct isis_lsp *lsp;
+ struct lsp_entry *entry;
+ struct listnode *node,*node2;
+ struct tlvs tlvs;
+ struct list *lsp_list = NULL;
+ struct isis_passwd *passwd;
+
+ if (snp_type == ISIS_SNP_CSNP_FLAG) {
+ /* getting the header info */
+ typechar = 'C';
+ chdr = (struct isis_complete_seqnum_hdr*)STREAM_PNT(circuit->rcv_stream);
+ circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;
+ len = ntohs(chdr->pdu_len);
+ if (len < ISIS_CSNP_HDRLEN) {
+ zlog_warn ("Received a CSNP with bogus length!");
+ return ISIS_OK;
+ }
+ } else {
+ typechar = 'P';
+ phdr = (struct isis_partial_seqnum_hdr*)STREAM_PNT(circuit->rcv_stream);
+ circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;
+ len = ntohs(phdr->pdu_len);
+ if (len < ISIS_PSNP_HDRLEN) {
+ zlog_warn ("Received a CSNP with bogus length!");
+ return ISIS_OK;
+ }
+ }
+
+ /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
+ if (circuit->ext_domain) {
+
+ zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
+ "skipping: circuit externalDomain = true",
+ circuit->area->area_tag,
+ level,
+ typechar,
+ circuit->interface->name);
+
+ return ISIS_OK;
+ }
+
+ /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
+ if (!accept_level (level, circuit->circuit_is_type)) {
+
+ zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
+ "skipping: circuit type %s does not match level %d",
+ circuit->area->area_tag,
+ level,
+ typechar,
+ circuit->interface->name,
+ circuit_t2string (circuit->circuit_is_type),
+ level);
+
+ return ISIS_OK;
+ }
+
+ /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
+ if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
+ (circuit->circ_type == CIRCUIT_T_BROADCAST)) {
+ if (!circuit->u.bc.is_dr[level-1]) {
+
+ zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
+ "skipping: we are not the DIS",
+ circuit->area->area_tag,
+ level,
+ typechar,
+ snpa_print(ssnpa),
+ circuit->interface->name);
+
+ return ISIS_OK;
+ }
+ }
+
+ /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
+
+ /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
+ * - already checked */
+
+ /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */
+ /* for broadcast circuits, snpa should be compared */
+ /* FIXME : Do we need to check SNPA? */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ if (snp_type == ISIS_SNP_CSNP_FLAG) {
+ adj = isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]);
+ } else {
+ /* a psnp on a broadcast, how lovely of Juniper :) */
+ adj = isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]);
+ }
+ if (!adj)
+ return ISIS_OK; /* Silently discard */
+ } else {
+ if (!circuit->u.p2p.neighbor)
+ return ISIS_OK; /* Silently discard */
+ }
+
+ /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
+
+ /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
+
+ memset (&tlvs, 0, sizeof (struct tlvs));
+
+ /* parse the SNP */
+ expected |= TLVFLAG_LSP_ENTRIES;
+ expected |= TLVFLAG_AUTH_INFO;
+ retval = parse_tlvs (circuit->area->area_tag,
+ STREAM_PNT(circuit->rcv_stream),
+ len - circuit->rcv_stream->getp,
+ &expected,
+ &found,
+ &tlvs);
+
+ if (retval > ISIS_WARNING) {
+ zlog_warn ("something went very wrong processing SNP");
+ free_tlvs (&tlvs);
+ return retval;
+ }
+
+ (level == 1) ? (passwd = &circuit->area->area_passwd) :
+ (passwd = &circuit->area->domain_passwd);
+ if (passwd->type) {
+ if (!(found & TLVFLAG_AUTH_INFO) ||
+ authentication_check (passwd, &tlvs.auth_info)) {
+ isis_event_auth_failure (circuit->area->area_tag, "SNP authentication"
+ " failure", phdr ?
+ phdr->source_id : chdr->source_id);
+ return ISIS_OK;
+ }
+ }
+
+ /* debug isis snp-packets */
+ if (isis->debugs & DEBUG_SNP_PACKETS) {
+ zlog_info ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
+ circuit->area->area_tag,
+ level,
+ typechar,
+ snpa_print(ssnpa),
+ circuit->interface->name);
+ if (tlvs.lsp_entries) {
+ LIST_LOOP (tlvs.lsp_entries,entry,node) {
+ zlog_info("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x,"
+ " cksum 0x%04x, lifetime %us",
+ circuit->area->area_tag,
+ typechar,
+ rawlspid_print (entry->lsp_id),
+ ntohl (entry->seq_num),
+ ntohs (entry->checksum),
+ ntohs (entry->rem_lifetime));
+ }
+ }
+ }
+
+ /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
+ if (tlvs.lsp_entries) {
+ LIST_LOOP (tlvs.lsp_entries, entry, node) {
+ lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]);
+ own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ if (lsp) {
+ /* 7.3.15.2 b) 1) is this LSP newer */
+ cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num,
+ entry->checksum, entry->rem_lifetime);
+ /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
+ if (cmp == LSP_EQUAL) {
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+ /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
+ } else if (cmp == LSP_OLDER) {
+ ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
+ ISIS_SET_FLAG (lsp->SRMflags, circuit);
+ } else {
+ /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p*/
+ if (own_lsp) {
+ lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
+ ISIS_SET_FLAG (lsp->SRMflags, circuit);
+ } else {
+ ISIS_SET_FLAG (lsp->SSNflags, circuit);
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+ }
+ }
+ } else {
+ /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0,
+ * insert it and set SSN on it */
+ if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
+ memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
+ lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
+ 0, 0, entry->checksum, level);
+ lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+ ISIS_SET_FLAG (lsp->SSNflags, circuit);
+ }
+ }
+ }
+ }
+
+ /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
+ if (snp_type == ISIS_SNP_CSNP_FLAG) {
+ /*
+ * Build a list from our own LSP db bounded with start_ and stop_lsp_id
+ */
+ lsp_list = list_new ();
+ lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
+ lsp_list, circuit->area->lspdb[level - 1]);
+
+ /* Fixme: Find a better solution */
+ if (tlvs.lsp_entries) {
+ LIST_LOOP (tlvs.lsp_entries, entry, node) {
+ LIST_LOOP (lsp_list, lsp, node2) {
+ if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0) {
+ list_delete_node (lsp_list, node2);
+ break;
+ }
+ }
+ }
+ }
+ /* on remaining LSPs we set SRM (neighbor knew not of) */
+ LIST_LOOP (lsp_list, lsp, node2) {
+ ISIS_SET_FLAG (lsp->SRMflags, circuit);
+ }
+ /* lets free it */
+ list_free (lsp_list);
+ }
+
+ free_tlvs (&tlvs);
+ return retval;
+}
+
+int
+process_csnp (int level, struct isis_circuit *circuit, u_char *ssnpa)
+{
+
+ /* Sanity check - FIXME: move to correct place */
+ if ((stream_get_endp (circuit->rcv_stream) -
+ stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN) {
+ zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
+ return ISIS_WARNING;
+ }
+
+ return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
+}
+
+int
+process_psnp (int level, struct isis_circuit *circuit, u_char *ssnpa)
+{
+
+ if ((stream_get_endp (circuit->rcv_stream) -
+ stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) {
+ zlog_warn ("Packet too short");
+ return ISIS_WARNING;
+ }
+
+ return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
+}
+
+
+
+/*
+ * Process ISH
+ * ISO - 10589
+ * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
+ * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
+ 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59
+ 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00
+ 0x03 0x00 0x81 0x01 0xcc
+ */
+int
+process_is_hello (struct isis_circuit *circuit)
+{
+ struct isis_adjacency *adj;
+ int retval = ISIS_OK;
+ u_char neigh_len;
+ u_char *sysid;
+
+ /* In this point in time we are not yet able to handle is_hellos
+ * on lan - Sorry juniper...
+ */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ return retval;
+
+ neigh_len = stream_getc (circuit->rcv_stream);
+ sysid = STREAM_PNT(circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN;
+ adj = circuit->u.p2p.neighbor;
+ if (!adj) {
+ /* 8.2.2 */
+ adj = isis_new_adj (sysid, " ", 0, circuit);
+ if (adj == NULL)
+ return ISIS_ERROR;
+
+ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
+ adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
+ circuit->u.p2p.neighbor = adj;
+ }
+ /* 8.2.2 a)*/
+ if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid,sysid,
+ ISIS_SYS_ID_LEN)) {
+ /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
+ /* 8.2.2 a) 2) delete the adj */
+ XFREE (MTYPE_ISIS_ADJACENCY, adj);
+ /* 8.2.2 a) 3) create a new adj */
+ adj = isis_new_adj (sysid, " ", 0, circuit);
+ if (adj == NULL)
+ return ISIS_ERROR;
+
+ /* 8.2.2 a) 3) i */
+ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
+ /* 8.2.2 a) 3) ii */
+ adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
+ /* 8.2.2 a) 4) quite meaningless */
+ }
+ /* 8.2.2 b) ignore on condition */
+ if ((adj->adj_state == ISIS_ADJ_INITIALIZING) &&
+ (adj->sys_type == ISIS_SYSTYPE_IS)) {
+ /* do nothing */
+ } else {
+ /* 8.2.2 c) respond with a p2p IIH */
+ send_hello (circuit, 1);
+ }
+ /* 8.2.2 d) type is IS */
+ adj->sys_type = ISIS_SYSTYPE_IS;
+ /* 8.2.2 e) FIXME: Circuit type of? */
+
+
+ return retval;
+}
+
+
+/*
+ * PDU Dispatcher
+ */
+
+int
+isis_handle_pdu (struct isis_circuit *circuit, u_char *ssnpa)
+{
+
+ struct isis_fixed_hdr *hdr;
+ struct esis_fixed_hdr *esis_hdr;
+
+ int retval=ISIS_OK;
+
+ /*
+ * Let's first read data from stream to the header
+ */
+ hdr = (struct isis_fixed_hdr*)STREAM_DATA(circuit->rcv_stream);
+
+ if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)){
+ zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
+ return ISIS_ERROR;
+ }
+
+ /* now we need to know if this is an ISO 9542 packet and
+ * take real good care of it, waaa!
+ */
+ if (hdr->idrp == ISO9542_ESIS){
+ esis_hdr = (struct esis_fixed_hdr*)STREAM_DATA(circuit->rcv_stream);
+ stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN);
+ /* FIXME: Need to do some acceptence tests */
+ /* example length... */
+ switch (esis_hdr->pdu_type) {
+ case ESH_PDU:
+ /* FIXME */
+ break;
+ case ISH_PDU:
+ zlog_info ("AN ISH PDU!!");
+ retval = process_is_hello (circuit);
+ break;
+ default:
+ return ISIS_ERROR;
+ }
+ return retval;
+ } else {
+ stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
+ }
+ /*
+ * and then process it
+ */
+
+ if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) {
+ zlog_err ("Fixed header length = %d", hdr->length);
+ return ISIS_ERROR;
+ }
+
+ if (hdr->version1 != 1) {
+ zlog_warn ("Unsupported ISIS version %u", hdr->version1);
+ return ISIS_WARNING;
+ }
+ /* either 6 or 0 */
+ if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) {
+ zlog_err ("IDFieldLengthMismatch: ID Length field in a received PDU %u, "
+ "while the parameter for this IS is %u", hdr->id_len,
+ ISIS_SYS_ID_LEN);
+ return ISIS_ERROR;
+ }
+
+ if (hdr->version2 != 1) {
+ zlog_warn ("Unsupported ISIS version %u", hdr->version2);
+ return ISIS_WARNING;
+ }
+ /* either 3 or 0 */
+ if ((hdr->max_area_addrs != 0) && (hdr->max_area_addrs != isis->max_area_addrs)) {
+ zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
+ "received PDU %u while the parameter for this IS is %u",
+ hdr->max_area_addrs, isis->max_area_addrs);
+ return ISIS_ERROR;
+ }
+
+ switch (hdr->pdu_type) {
+ case L1_LAN_HELLO:
+ retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa);
+ break;
+ case L2_LAN_HELLO:
+ retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa);
+ break;
+ case P2P_HELLO:
+ retval = process_p2p_hello (circuit);
+ break;
+ case L1_LINK_STATE:
+ retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa);
+ break;
+ case L2_LINK_STATE:
+ retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa);
+ break;
+ case L1_COMPLETE_SEQ_NUM:
+ retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa);
+ break;
+ case L2_COMPLETE_SEQ_NUM:
+ retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa);
+ break;
+ case L1_PARTIAL_SEQ_NUM:
+ retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa);
+ break;
+ case L2_PARTIAL_SEQ_NUM:
+ retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa);
+ break;
+ default:
+ return ISIS_ERROR;
+ }
+
+ return retval;
+}
+
+
+#ifdef GNU_LINUX
+int
+isis_receive (struct thread *thread)
+{
+
+ struct isis_circuit *circuit;
+ u_char ssnpa[ETH_ALEN];
+ int retval;
+
+ /*
+ * Get the circuit
+ */
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ if (circuit->rcv_stream == NULL)
+ circuit->rcv_stream = stream_new (ISO_MTU(circuit));
+ else
+ stream_reset (circuit->rcv_stream);
+
+ retval = circuit->rx (circuit, ssnpa);
+ circuit->t_read = NULL;
+
+ if (retval == ISIS_OK)
+ retval = isis_handle_pdu (circuit, ssnpa);
+
+ /*
+ * prepare for next packet.
+ */
+ circuit->t_read = thread_add_read (master, isis_receive, circuit,
+ circuit->fd);
+
+ return retval;
+}
+
+#else
+int
+isis_receive (struct thread *thread)
+{
+
+ struct isis_circuit *circuit;
+ u_char ssnpa[ETH_ALEN];
+ int retval;
+
+ /*
+ * Get the circuit
+ */
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ circuit->t_read = NULL;
+
+ if (circuit->rcv_stream == NULL)
+ circuit->rcv_stream = stream_new (ISO_MTU(circuit));
+ else
+ stream_reset (circuit->rcv_stream);
+
+ retval = circuit->rx (circuit, ssnpa);
+
+ if (retval == ISIS_OK)
+ retval = isis_handle_pdu (circuit, ssnpa);
+
+ /*
+ * prepare for next packet.
+ */
+ circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
+ listcount
+ (circuit->area->circuit_list)*100);
+
+
+ return retval;
+}
+
+#endif
+
+ /* filling of the fixed isis header */
+void
+fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
+{
+ memset (hdr, 0, sizeof (struct isis_fixed_hdr));
+
+ hdr->idrp = ISO10589_ISIS;
+
+ switch (pdu_type) {
+ case L1_LAN_HELLO:
+ case L2_LAN_HELLO:
+ hdr->length = ISIS_LANHELLO_HDRLEN;
+ break;
+ case P2P_HELLO:
+ hdr->length = ISIS_P2PHELLO_HDRLEN;
+ break;
+ case L1_LINK_STATE:
+ case L2_LINK_STATE:
+ hdr->length = ISIS_LSP_HDR_LEN;
+ break;
+ case L1_COMPLETE_SEQ_NUM:
+ case L2_COMPLETE_SEQ_NUM:
+ hdr->length = ISIS_CSNP_HDRLEN;
+ break;
+ case L1_PARTIAL_SEQ_NUM:
+ case L2_PARTIAL_SEQ_NUM:
+ hdr->length = ISIS_PSNP_HDRLEN;
+ break;
+ default:
+ zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
+ return;
+ }
+ hdr->length += ISIS_FIXED_HDR_LEN;
+ hdr->pdu_type = pdu_type;
+ hdr->version1 = 1;
+ hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */
+ hdr->version2 = 1;
+ hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */
+}
+
+
+/*
+ * SEND SIDE
+ */
+void
+fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type,
+ struct stream *stream)
+{
+ fill_fixed_hdr (hdr,pdu_type);
+
+ stream_putc (stream, hdr->idrp);
+ stream_putc (stream, hdr->length);
+ stream_putc (stream, hdr->version1);
+ stream_putc (stream, hdr->id_len);
+ stream_putc (stream, hdr->pdu_type);
+ stream_putc (stream, hdr->version2);
+ stream_putc (stream, hdr->reserved);
+ stream_putc (stream, hdr->max_area_addrs);
+
+ return;
+}
+
+
+int
+send_hello (struct isis_circuit *circuit, int level)
+{
+ struct isis_fixed_hdr fixed_hdr;
+ struct isis_lan_hello_hdr hello_hdr;
+ struct isis_p2p_hello_hdr p2p_hello_hdr;
+
+ u_int32_t interval;
+ unsigned long len_pointer, length;
+ int retval;
+
+ if (circuit->interface->mtu == 0) {
+ zlog_warn ("circuit has zero MTU");
+ return ISIS_WARNING;
+ }
+
+ if (!circuit->snd_stream)
+ circuit->snd_stream = stream_new (ISO_MTU(circuit));
+ else
+ stream_reset (circuit->snd_stream);
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ if (level == 1)
+ fill_fixed_hdr_andstream(&fixed_hdr, L1_LAN_HELLO, circuit->snd_stream);
+ else
+ fill_fixed_hdr_andstream(&fixed_hdr, L2_LAN_HELLO, circuit->snd_stream);
+ else
+ fill_fixed_hdr_andstream(&fixed_hdr, P2P_HELLO, circuit->snd_stream);
+
+ /*
+ * Fill LAN Level 1 or 2 Hello PDU header
+ */
+ memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
+ interval = circuit->hello_multiplier[level - 1] *
+ circuit->hello_interval[level - 1];
+ if (interval > USHRT_MAX)
+ interval = USHRT_MAX;
+ hello_hdr.circuit_t = circuit->circuit_is_type;
+ memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
+ hello_hdr.hold_time = htons((u_int16_t)interval);
+
+ hello_hdr.pdu_len = 0; /* Update the PDU Length later */
+ len_pointer = stream_get_putp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
+
+
+ /* copy the shared part of the hello to the p2p hello if needed */
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
+ p2p_hello_hdr.local_id = circuit->circuit_id;
+ /* FIXME: need better understanding */
+ stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN);
+ } else {
+ hello_hdr.prio = circuit->u.bc.priority[level - 1];
+ if(level == 1 && circuit->u.bc.l1_desig_is) {
+ memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
+ } else if (level == 2 && circuit->u.bc.l2_desig_is){
+ memcpy(hello_hdr.lan_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
+ }
+ stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN);
+ }
+
+ /*
+ * Then the variable length part
+ */
+ /* add circuit password */
+ if (circuit->passwd.type)
+ if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
+ circuit->passwd.passwd, circuit->snd_stream))
+ return ISIS_WARNING;
+ /* Area Addresses TLV */
+ assert (circuit->area);
+ if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0)
+ if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
+ return ISIS_WARNING;
+
+ /* LAN Neighbors TLV */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0)
+ if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
+ circuit->snd_stream))
+ return ISIS_WARNING;
+ if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0)
+ if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
+ circuit->snd_stream))
+ return ISIS_WARNING;
+ }
+
+ /* Protocols Supported TLV */
+ if (circuit->nlpids.count > 0)
+ if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
+ return ISIS_WARNING;
+ /* IP interface Address TLV */
+ if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0)
+ if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
+ return ISIS_WARNING;
+
+#ifdef HAVE_IPV6
+ /* IPv6 Interface Address TLV */
+ if (circuit->ipv6_router && circuit->ipv6_link &&
+ circuit->ipv6_link->count > 0)
+ if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
+ return ISIS_WARNING;
+#endif /* HAVE_IPV6 */
+
+ if (circuit->u.bc.pad_hellos)
+ if (tlv_add_padding (circuit->snd_stream))
+ return ISIS_WARNING;
+
+ length = stream_get_putp (circuit->snd_stream);
+ /* Update PDU length */
+ stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t)length);
+
+ retval = circuit->tx (circuit, level);
+ if (retval)
+ zlog_warn ("sending of LAN Level %d Hello failed", level);
+
+ /* DEBUG_ADJ_PACKETS */
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ zlog_info ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
+ circuit->area->area_tag, level, circuit->interface->name,
+ STREAM_SIZE(circuit->snd_stream));
+ } else {
+ zlog_info ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
+ circuit->area->area_tag, circuit->interface->name,
+ STREAM_SIZE(circuit->snd_stream));
+ }
+ }
+
+
+ return retval;
+}
+
+int
+send_lan_hello (struct isis_circuit *circuit, int level)
+{
+ return send_hello (circuit,level);
+}
+
+int
+send_lan_l1_hello (struct thread *thread)
+{
+
+ struct isis_circuit *circuit;
+ int retval;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+ circuit->u.bc.t_send_lan_hello[0] = NULL;
+
+ if (circuit->u.bc.run_dr_elect[0])
+ retval = isis_dr_elect (circuit, 1);
+
+ retval = send_lan_hello (circuit, 1);
+
+ /* set next timer thread */
+ circuit->u.bc.t_send_lan_hello[0] =
+ thread_add_timer (master, send_lan_l1_hello, circuit,
+ isis_jitter (circuit->hello_interval[0], IIH_JITTER));
+
+ return retval;
+}
+
+int
+send_lan_l2_hello (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ int retval;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+ circuit->u.bc.t_send_lan_hello[1] = NULL;
+
+ if (circuit->u.bc.run_dr_elect[1])
+ retval = isis_dr_elect (circuit, 2);
+
+ retval = send_lan_hello (circuit, 2);
+
+ /* set next timer thread*/
+ circuit->u.bc.t_send_lan_hello[1] =
+ thread_add_timer (master, send_lan_l2_hello, circuit,
+ isis_jitter (circuit->hello_interval[1], IIH_JITTER));
+
+ return retval;
+}
+
+int
+send_p2p_hello (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+ circuit->u.p2p.t_send_p2p_hello = NULL;
+
+ send_hello(circuit,1);
+
+ /* set next timer thread*/
+ circuit->u.p2p.t_send_p2p_hello = thread_add_timer
+ (master, send_p2p_hello, circuit, isis_jitter (circuit->hello_interval[1],
+ IIH_JITTER));
+
+ return ISIS_OK;
+}
+
+int
+build_csnp (int level, u_char *start, u_char *stop, struct list *lsps,
+ struct isis_circuit *circuit)
+{
+ struct isis_fixed_hdr fixed_hdr;
+ struct isis_passwd *passwd;
+ int retval = ISIS_OK;
+ unsigned long lenp;
+ u_int16_t length;
+
+ if (level ==1)
+ fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
+ circuit->snd_stream);
+ else
+ fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM,
+ circuit->snd_stream);
+
+ /*
+ * Fill Level 1 or 2 Complete Sequence Numbers header
+ */
+
+ lenp = stream_get_putp (circuit->snd_stream);
+ stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
+ /* no need to send the source here, it is always us if we csnp */
+ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+ /* with zero circuit id - ref 9.10, 9.11 */
+ stream_putc (circuit->snd_stream, 0x00);
+
+ stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
+ stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
+
+ /*
+ * And TLVs
+ */
+ if (level == 1)
+ passwd = &circuit->area->area_passwd;
+ else
+ passwd = &circuit->area->domain_passwd;
+
+ if (passwd->type)
+ retval = tlv_add_authinfo (passwd->type, passwd->len,
+ passwd->passwd, circuit->snd_stream);
+
+ if (!retval && lsps) {
+ retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+ }
+ length = (u_int16_t)stream_get_putp (circuit->snd_stream);
+ assert (length >= ISIS_CSNP_HDRLEN);
+ /* Update PU length */
+ stream_putw_at (circuit->snd_stream, lenp, length);
+
+ return retval;
+}
+
+/*
+ * FIXME: support multiple CSNPs
+ */
+
+int
+send_csnp (struct isis_circuit *circuit, int level)
+{
+ int retval = ISIS_OK;
+ u_char start[ISIS_SYS_ID_LEN + 2];
+ u_char stop[ISIS_SYS_ID_LEN + 2];
+ struct list *list = NULL;
+ struct listnode *node;
+ struct isis_lsp *lsp;
+
+ memset (start,0x00, ISIS_SYS_ID_LEN + 2);
+ memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
+
+ if (circuit->area->lspdb[level-1] &&
+ dict_count (circuit->area->lspdb[level-1]) > 0) {
+ list = list_new ();
+ lsp_build_list (start, stop, list, circuit->area->lspdb[level-1]);
+
+ if (circuit->snd_stream == NULL)
+ circuit->snd_stream = stream_new (ISO_MTU(circuit));
+ else
+ stream_reset (circuit->snd_stream);
+
+ retval = build_csnp (level, start, stop, list, circuit);
+
+ if (isis->debugs & DEBUG_SNP_PACKETS) {
+ zlog_info ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
+ circuit->area->area_tag, level, circuit->interface->name,
+ STREAM_SIZE(circuit->snd_stream));
+ LIST_LOOP (list, lsp, node) {
+ zlog_info("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
+ " cksum 0x%04x, lifetime %us",
+ circuit->area->area_tag,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime));
+ }
+ }
+
+ list_delete (list);
+
+ if (retval == ISIS_OK)
+ retval = circuit->tx (circuit, level);
+ }
+ return retval;
+}
+
+int
+send_l1_csnp (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ int retval = ISIS_OK;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ circuit->t_send_csnp[0] = NULL;
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) {
+ send_csnp(circuit,1);
+ }
+ /* set next timer thread */
+ circuit->t_send_csnp[0] = thread_add_timer (master,
+ send_l1_csnp,
+ circuit,
+ isis_jitter
+ (circuit->csnp_interval[0],
+ CSNP_JITTER));
+
+ return retval;
+}
+
+int
+send_l2_csnp (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ int retval = ISIS_OK;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ circuit->t_send_csnp[1] = NULL;
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) {
+ send_csnp(circuit,2);
+ }
+ /* set next timer thread */
+ circuit->t_send_csnp[1] = thread_add_timer (master,
+ send_l2_csnp,
+ circuit,
+ isis_jitter
+ (circuit->csnp_interval[1],
+ CSNP_JITTER));
+ return retval;
+}
+
+int
+build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
+{
+ struct isis_fixed_hdr fixed_hdr;
+ unsigned long lenp;
+ u_int16_t length;
+ int retval = 0;
+ struct isis_lsp *lsp;
+ struct isis_passwd *passwd;
+ struct listnode *node;
+
+ if (level == 1)
+ fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
+ circuit->snd_stream);
+ else
+ fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
+ circuit->snd_stream);
+
+ /*
+ * Fill Level 1 or 2 Partial Sequence Numbers header
+ */
+ lenp = stream_get_putp (circuit->snd_stream);
+ stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */
+ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+ stream_putc (circuit->snd_stream, circuit->idx);
+
+ /*
+ * And TLVs
+ */
+
+ if (level == 1)
+ passwd = &circuit->area->area_passwd;
+ else
+ passwd = &circuit->area->domain_passwd;
+
+ if (passwd->type)
+ retval = tlv_add_authinfo (passwd->type, passwd->len,
+ passwd->passwd, circuit->snd_stream);
+
+ if (!retval && lsps) {
+ retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+ }
+
+ if (isis->debugs & DEBUG_SNP_PACKETS) {
+ LIST_LOOP (lsps, lsp, node) {
+ zlog_info("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x,"
+ " cksum 0x%04x, lifetime %us",
+ circuit->area->area_tag,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime));
+ }
+ }
+
+ length = (u_int16_t)stream_get_putp (circuit->snd_stream);
+ assert (length >= ISIS_PSNP_HDRLEN);
+ /* Update PDU length */
+ stream_putw_at (circuit->snd_stream, lenp, length);
+
+ return ISIS_OK;
+}
+
+/*
+ * 7.3.15.4 action on expiration of partial SNP interval
+ * level 1
+ */
+int
+send_psnp (int level, struct isis_circuit *circuit)
+{
+ int retval = ISIS_OK;
+ struct isis_lsp *lsp;
+ struct list *list = NULL;
+ struct listnode *node;
+
+ if ((circuit->circ_type == CIRCUIT_T_BROADCAST &&
+ !circuit->u.bc.is_dr[level - 1]) ||
+ circuit->circ_type != CIRCUIT_T_BROADCAST) {
+
+ if (circuit->area->lspdb[level-1] &&
+ dict_count (circuit->area->lspdb[level-1]) > 0) {
+ list = list_new ();
+ lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level-1]);
+
+ if (listcount(list) > 0) {
+ if (circuit->snd_stream == NULL)
+ circuit->snd_stream = stream_new (ISO_MTU(circuit));
+ else
+ stream_reset (circuit->snd_stream);
+
+
+ if (isis->debugs & DEBUG_SNP_PACKETS)
+ zlog_info ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
+ circuit->area->area_tag, level, circuit->interface->name,
+ STREAM_SIZE(circuit->snd_stream));
+
+ retval = build_psnp (level, circuit, list);
+ if (retval == ISIS_OK)
+ retval = circuit->tx (circuit, level);
+
+ if (retval == ISIS_OK) {
+ /*
+ * sending succeeded, we can clear SSN flags of this circuit
+ * for the LSPs in list
+ */
+ for (node = listhead (list); node; nextnode(node)) {
+ lsp = getdata (node);
+ ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
+ }
+ }
+ }
+ list_delete (list);
+ }
+ }
+
+ return retval;
+}
+
+int
+send_l1_psnp (struct thread *thread)
+{
+
+ struct isis_circuit *circuit;
+ int retval = ISIS_OK;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ circuit->t_send_psnp[0] = NULL;
+
+ send_psnp (1, circuit);
+ /* set next timer thread */
+ circuit->t_send_psnp[0] = thread_add_timer (master,
+ send_l1_psnp,
+ circuit,
+ isis_jitter
+ (circuit->psnp_interval[0],
+ PSNP_JITTER));
+
+ return retval;
+}
+
+/*
+ * 7.3.15.4 action on expiration of partial SNP interval
+ * level 2
+ */
+int
+send_l2_psnp (struct thread *thread)
+{
+
+ struct isis_circuit *circuit;
+ int retval = ISIS_OK;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ circuit->t_send_psnp[1] = NULL;
+
+ send_psnp (2, circuit);
+
+ /* set next timer thread */
+ circuit->t_send_psnp[1] = thread_add_timer (master,
+ send_l2_psnp,
+ circuit,
+ isis_jitter
+ (circuit->psnp_interval[1],
+ PSNP_JITTER));
+
+ return retval;
+}
+
+
+void
+build_link_state (struct isis_lsp *lsp, struct isis_circuit *circuit,
+ struct stream *stream)
+{
+ unsigned long length;
+
+ stream_put (stream, lsp->pdu, ntohs(lsp->lsp_header->pdu_len));
+ length = stream_get_putp (stream);
+
+ return;
+}
+
+
+/*
+ * ISO 10589 - 7.3.14.3
+ */
+int
+send_lsp (struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ struct isis_lsp *lsp;
+ struct listnode *node;
+ int retval = 0;
+
+ circuit = THREAD_ARG (thread);
+ assert (circuit);
+
+ if (circuit->state == C_STATE_UP) {
+ node = listhead (circuit->lsp_queue);
+ assert (node);
+
+ lsp = getdata (node);
+
+ /*
+ * Do not send if levels do not match
+ */
+ if (!(lsp->level & circuit->circuit_is_type))
+ goto dontsend;
+
+ /*
+ * Do not send if we do not have adjacencies in state up on the circuit
+ */
+ if (circuit->upadjcount[lsp->level - 1] == 0)
+ goto dontsend;
+ /* only send if it needs sending */
+ if ((time(NULL) - lsp->last_sent) >=
+ circuit->area->lsp_gen_interval[lsp->level-1]) {
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS) {
+ zlog_info ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
+ " lifetime %us on %s",
+ circuit->area->area_tag,
+ lsp->level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl(lsp->lsp_header->seq_num),
+ ntohs(lsp->lsp_header->checksum),
+ ntohs(lsp->lsp_header->rem_lifetime),
+ circuit->interface->name);
+ }
+ /* copy our lsp to the send buffer */
+ circuit->snd_stream->getp = lsp->pdu->getp;
+ circuit->snd_stream->putp = lsp->pdu->putp;
+ circuit->snd_stream->endp = lsp->pdu->endp;
+ memcpy (circuit->snd_stream->data, lsp->pdu->data, lsp->pdu->endp);
+
+ retval = circuit->tx (circuit, lsp->level);
+
+ /*
+ * If the sending succeeded, we can del the lsp from circuits lsp_queue
+ */
+ if (retval == ISIS_OK) {
+ list_delete_node (circuit->lsp_queue, node);
+
+ /*
+ * On broadcast circuits also the SRMflag can be cleared
+ */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+
+ if (flags_any_set (lsp->SRMflags) == 0) {
+ /*
+ * need to remember when we were last sent
+ */
+ lsp->last_sent = time (NULL);
+ }
+ } else {
+ zlog_info ("sending of level %d link state failed", lsp->level);
+ }
+ } else {
+ /* my belief is that if it wasn't his time, the lsp can be removed
+ * from the queue
+ */
+ dontsend:
+ list_delete_node (circuit->lsp_queue, node);
+ }
+#if 0
+ /*
+ * If there are still LSPs send next one after lsp-interval (33 msecs)
+ */
+ if (listcount (circuit->lsp_queue) > 0)
+ thread_add_timer (master, send_lsp, circuit,
+ 1);
+#endif
+ }
+
+ return retval;
+}
+
+int
+ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
+ int level)
+{
+ unsigned long lenp;
+ int retval;
+ u_int16_t length;
+ struct isis_fixed_hdr fixed_hdr;
+
+ if (!circuit->snd_stream)
+ circuit->snd_stream = stream_new (ISO_MTU(circuit));
+ else
+ stream_reset (circuit->snd_stream);
+
+// fill_llc_hdr (stream);
+ if (level == 1)
+ fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
+ circuit->snd_stream);
+ else
+ fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
+ circuit->snd_stream);
+
+
+ lenp = stream_get_putp (circuit->snd_stream);
+ stream_putw (circuit->snd_stream, 0); /* PDU length */
+ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+ stream_putc (circuit->snd_stream, circuit->idx);
+ stream_putc (circuit->snd_stream, 9); /* code */
+ stream_putc (circuit->snd_stream, 16); /* len */
+
+ stream_putw (circuit->snd_stream, ntohs(hdr->rem_lifetime));
+ stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
+ stream_putl (circuit->snd_stream, ntohl(hdr->seq_num));
+ stream_putw (circuit->snd_stream, ntohs(hdr->checksum));
+
+ length = (u_int16_t)stream_get_putp (circuit->snd_stream);
+ /* Update PDU length */
+ stream_putw_at (circuit->snd_stream, lenp, length);
+
+ retval = circuit->tx (circuit, level);
+
+ return retval;
+}
+
+#if 0
+/*
+ * ISH PDU Processing
+ */
+
+
+ /*
+ * Let's first check if the local and remote system have any common area
+ * addresses
+ */
+ if (area_match(tlvs.area_addrs, isis->man_area_addrs) == 0) {
+ if (circuit->circuit_t == IS_LEVEL_2) {
+ /* do as in table 8 (p. 40) */
+ switch (circuit_type) {
+ case IS_LEVEL_1:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ /* Reject */
+ zlog_warn("areaMismatch");
+ retval = ISIS_WARNING;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch",
+ circuit->adjdb);
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2 ||
+ adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System",
+ circuit->adjdb);
+ }
+ break;
+ case IS_LEVEL_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL, circuit->adjdb);
+ adj->adj_usage = ISIS_ADJ_LEVEL2;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1 ||
+ adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System",
+ circuit->adjdb);
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ ; /* Accept */
+ }
+ break;
+ case IS_LEVEL_1_AND_2:
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL, circuit->adjdb);
+ adj->adj_usage = ISIS_ADJ_LEVEL2;
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System",
+ circuit->adjdb);
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch",
+ circuit->adjdb);
+ } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ ; /* Accept */
+ }
+ break;
+ }
+ goto mismatch;
+ } else {
+ isis_delete_adj (adj, circuit->adjdb);
+ zlog_warn("areaMismatch");
+ return ISIS_WARNING;
+ }
+ }
+
+mismatch:
+#endif
+
+
+
+
diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h
new file mode 100644
index 00000000..99403680
--- /dev/null
+++ b/isisd/isis_pdu.h
@@ -0,0 +1,257 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_pdu.h
+ * PDU processing
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_PDU_H
+#define _ZEBRA_ISIS_PDU_H
+
+/*
+ * ISO 9542 - 7.5,7.6
+ *
+ * ES to IS Fixed Header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Intradomain Routeing Protocol Discriminator |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Length Indicator |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Version/Protocol ID extension |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Reserved = 0 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | 0 | 0 | 0 | PDU Type |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Holding Time | 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Checksum | 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+
+struct esis_fixed_hdr
+{
+ u_char idrp;
+ u_char length;
+ u_char version;
+ u_char id_len;
+ u_char pdu_type;
+ u_int16_t holdtime;
+ u_int16_t checksum;
+} __attribute__((packed));
+
+#define ESIS_FIXED_HDR_LEN 9
+
+#define ESH_PDU 2
+#define ISH_PDU 4
+#define RD_PDU 5
+
+/*
+ * IS to IS Fixed Header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Intradomain Routeing Protocol Discriminator |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Length Indicator |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Version/Protocol ID extension |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | R | R | R | PDU Type |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Version |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Reserved |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Maximum Area Addresses |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+
+struct isis_fixed_hdr
+{
+ u_char idrp;
+ u_char length;
+ u_char version1;
+ u_char id_len;
+ u_char pdu_type;
+ u_char version2;
+ u_char reserved;
+ u_char max_area_addrs;
+};
+
+#define ISIS_FIXED_HDR_LEN 8
+
+/*
+ * IS-IS PDU types.
+ */
+
+#define L1_LAN_HELLO 15
+#define L2_LAN_HELLO 16
+/*
+ * L1 and L2 LAN IS to IS Hello PDU header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Reserved | Circuit Type | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Source ID + id_len
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Holding Time | 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | PDU Lenght | 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | R | Priority | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | LAN ID | id_len + 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct isis_lan_hello_hdr {
+ u_char circuit_t;
+ u_char source_id[ISIS_SYS_ID_LEN];
+ u_int16_t hold_time;
+ u_int16_t pdu_len;
+ u_char prio;
+ u_char lan_id[ISIS_SYS_ID_LEN + 1];
+} __attribute__((packed));
+#define ISIS_LANHELLO_HDRLEN 19
+
+#define P2P_HELLO 17
+/*
+ * Point-to-point IS to IS hello PDU header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Reserved | Circuit Type | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Source ID + id_len
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Holding Time + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + PDU Lenght + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Local Circuit ID | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct isis_p2p_hello_hdr {
+ u_char circuit_t;
+ u_char source_id[ISIS_SYS_ID_LEN];
+ u_int16_t hold_time;
+ u_int16_t pdu_len;
+ u_char local_id;
+} __attribute__((packed));
+#define ISIS_P2PHELLO_HDRLEN 12
+
+#define L1_LINK_STATE 18
+#define L2_LINK_STATE 20
+/*
+ * L1 and L2 IS to IS link state PDU header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + PDU Length + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Remaining Lifetime + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | LSP ID | id_len + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Sequence Number + 4
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Checksum + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | P | ATT |LSPDBOL| ISTYPE |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct isis_link_state_hdr {
+ u_int16_t pdu_len;
+ u_int16_t rem_lifetime;
+ u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ u_int32_t seq_num;
+ u_int16_t checksum;
+ u_int8_t lsp_bits;
+} __attribute__((packed));
+#define ISIS_LSP_HDR_LEN 19
+
+#define L1_COMPLETE_SEQ_NUM 24
+#define L2_COMPLETE_SEQ_NUM 25
+/*
+ * L1 and L2 IS to IS complete sequence numbers PDU header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + PDU Lenght + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Source ID + id_len + 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Start LSP ID + id_len + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + End LSP ID + id_len + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct isis_complete_seqnum_hdr {
+ u_int16_t pdu_len;
+ u_char source_id[ISIS_SYS_ID_LEN + 1];
+ u_char start_lsp_id[ISIS_SYS_ID_LEN + 2];
+ u_char stop_lsp_id[ISIS_SYS_ID_LEN + 2];
+};
+#define ISIS_CSNP_HDRLEN 25
+
+#define L1_PARTIAL_SEQ_NUM 26
+#define L2_PARTIAL_SEQ_NUM 27
+/*
+ * L1 and L2 IS to IS partial sequence numbers PDU header
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + PDU Length + 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + Source ID + id_len + 1
+ * +---------------------------------------------------------------+
+ */
+struct isis_partial_seqnum_hdr {
+ u_int16_t pdu_len;
+ u_char source_id[ISIS_SYS_ID_LEN + 1];
+};
+#define ISIS_PSNP_HDRLEN 9
+
+/*
+ * Function for receiving IS-IS PDUs
+ */
+int isis_receive (struct thread *thread);
+
+/*
+ * calling arguments for snp_process ()
+ */
+#define ISIS_SNP_PSNP_FLAG 0
+#define ISIS_SNP_CSNP_FLAG 1
+
+/*
+ * Sending functions
+ */
+int send_lan_l1_hello (struct thread *thread);
+int send_lan_l2_hello (struct thread *thread);
+int send_p2p_hello (struct thread *thread);
+int send_csnp (struct isis_circuit *circuit, int level);
+int send_l1_csnp (struct thread *thread);
+int send_l2_csnp (struct thread *thread);
+int send_l1_psnp (struct thread *thread);
+int send_l2_psnp (struct thread *thread);
+int send_lsp (struct thread *thread);
+int ack_lsp (struct isis_link_state_hdr *hdr,
+ struct isis_circuit *circuit, int level);
+void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);
+int send_hello (struct isis_circuit *circuit, int level);
+
+
+int authentication_check (struct isis_passwd *one,
+ struct isis_passwd *theother);
+
+#endif /* _ZEBRA_ISIS_PDU_H */
+
+
+
+
+
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
new file mode 100644
index 00000000..74231adc
--- /dev/null
+++ b/isisd/isis_route.c
@@ -0,0 +1,615 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_route.c
+ * Copyright (C) 2001,2002 Sampo Saaristo
+ * Tampere University of Technology
+ * Institute of Communications Engineering
+ *
+ * based on ../ospf6d/ospf6_route.[ch]
+ * by Yasuhiro Ohara
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "hash.h"
+#include "if.h"
+#include "table.h"
+
+#include "isis_constants.h"
+#include "isis_common.h"
+#include "dict.h"
+#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_spf.h"
+#include "isis_route.h"
+#include "isis_zebra.h"
+
+extern struct isis *isis;
+extern struct thread_master *master;
+
+struct isis_nexthop *
+isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
+
+{
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+
+ for (node = listhead (isis->nexthops); node; nextnode (node)) {
+ nexthop = getdata (node);
+ if (nexthop->ifindex != ifindex)
+ continue;
+ if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0)
+ continue;
+
+ nexthop->lock++;
+ return nexthop;
+ }
+
+ nexthop = XMALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop));
+ if (!nexthop) {
+ zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!");
+ }
+
+ memset (nexthop, 0, sizeof (struct isis_nexthop));
+ nexthop->ifindex = ifindex;
+ memcpy (&nexthop->ip, ip, sizeof (struct in_addr));
+ listnode_add (isis->nexthops, nexthop);
+ nexthop->lock++;
+
+ return nexthop;
+}
+
+
+void
+isis_nexthop_delete (struct isis_nexthop *nexthop)
+{
+ nexthop->lock--;
+ if (nexthop->lock == 0) {
+ listnode_delete (isis->nexthops, nexthop);
+ XFREE (MTYPE_ISIS_NEXTHOP, nexthop);
+ }
+
+ return;
+}
+
+int
+nexthoplookup (struct list *nexthops, struct in_addr *ip,
+ unsigned int ifindex)
+{
+ struct listnode *node;
+ struct isis_nexthop *nh;
+
+ for (node = listhead (nexthops); node; nextnode (node)) {
+ nh = getdata (node);
+ if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) &&
+ ifindex == nh->ifindex)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+nexthop_print (struct isis_nexthop *nh)
+{
+ u_char buf[BUFSIZ];
+
+ inet_ntop (AF_INET, &nh->ip, buf, BUFSIZ);
+
+ zlog_info (" %s %u", buf, nh->ifindex);
+}
+
+void
+nexthops_print (struct list *nhs)
+{
+ struct listnode *node;
+
+ for (node = listhead(nhs); node; nextnode (node))
+ nexthop_print (getdata (node));
+}
+
+#ifdef HAVE_IPV6
+
+struct isis_nexthop6 *
+isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex)
+{
+
+ struct isis_nexthop6 *nexthop6;
+
+ nexthop6 = XMALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6));
+ if (!nexthop6) {
+ zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!");
+ }
+
+ memset (nexthop6, 0, sizeof (struct isis_nexthop6));
+ nexthop6->ifindex = ifindex;
+ memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr));
+ nexthop6->lock++;
+
+ return nexthop6;
+}
+
+struct isis_nexthop6 *
+isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex)
+
+{
+ struct listnode *node;
+ struct isis_nexthop6 *nexthop6;
+
+ for (node = listhead (isis->nexthops6); node; nextnode (node)) {
+ nexthop6 = getdata (node);
+ if (nexthop6->ifindex != ifindex)
+ continue;
+ if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0)
+ continue;
+
+ nexthop6->lock++;
+ return nexthop6;
+ }
+
+ nexthop6 = isis_nexthop6_new (ip6, ifindex);
+
+ return nexthop6;
+}
+
+
+void
+isis_nexthop6_delete (struct isis_nexthop6 *nexthop6)
+{
+
+ nexthop6->lock--;
+ if (nexthop6->lock == 0) {
+ listnode_delete (isis->nexthops6, nexthop6);
+ XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6);
+ }
+
+ return;
+}
+
+int
+nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6,
+ unsigned int ifindex)
+{
+ struct listnode *node;
+ struct isis_nexthop6 *nh6;
+
+ for (node = listhead (nexthops6); node; nextnode (node)) {
+ nh6 = getdata (node);
+ if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) &&
+ ifindex == nh6->ifindex)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+nexthop6_print (struct isis_nexthop6 *nh6)
+{
+ u_char buf[BUFSIZ];
+
+ inet_ntop (AF_INET6, &nh6->ip6, buf, BUFSIZ);
+
+ zlog_info (" %s %u", buf, nh6->ifindex);
+}
+
+void
+nexthops6_print (struct list *nhs6)
+{
+ struct listnode *node;
+
+ for (node = listhead(nhs6); node; nextnode (node))
+ nexthop6_print (getdata (node));
+}
+
+
+#endif /* HAVE_IPV6 */
+
+void
+adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj)
+{
+ struct isis_nexthop *nh;
+ struct listnode *node;
+ struct in_addr *ipv4_addr;
+
+ if (adj->ipv4_addrs == NULL)
+ return;
+ for (node = listhead (adj->ipv4_addrs); node; nextnode (node)) {
+ ipv4_addr = getdata (node);
+ if (!nexthoplookup (nexthops, ipv4_addr,
+ adj->circuit->interface->ifindex)) {
+ nh = isis_nexthop_create (ipv4_addr,
+ adj->circuit->interface->ifindex);
+ listnode_add (nexthops, nh);
+ }
+ }
+}
+
+#ifdef HAVE_IPV6
+void
+adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj)
+{
+ struct listnode *node;
+ struct in6_addr *ipv6_addr;
+ struct isis_nexthop6 *nh6;
+
+ if (!adj->ipv6_addrs)
+ return;
+
+ for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) {
+ ipv6_addr = getdata (node);
+ if (!nexthop6lookup (nexthops6, ipv6_addr,
+ adj->circuit->interface->ifindex)) {
+ nh6 = isis_nexthop6_create (ipv6_addr,
+ adj->circuit->interface->ifindex);
+ listnode_add (nexthops6, nh6);
+ }
+ }
+}
+#endif /* HAVE_IPV6 */
+
+struct isis_route_info *
+isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
+ struct list *adjacencies)
+{
+ struct isis_route_info *rinfo;
+ struct isis_adjacency *adj;
+ struct listnode *node;
+
+ rinfo = XMALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info));
+ if (!rinfo) {
+ zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!");
+ return NULL;
+ }
+ memset (rinfo, 0, sizeof (struct isis_route_info));
+
+ if (family == AF_INET) {
+ rinfo->nexthops = list_new ();
+ for (node = listhead (adjacencies); node; nextnode (node)) {
+ adj = getdata (node);
+ adjinfo2nexthop (rinfo->nexthops, adj);
+ }
+ }
+#ifdef HAVE_IPV6
+ if (family == AF_INET6) {
+ rinfo->nexthops6 = list_new ();
+ for (node = listhead (adjacencies); node; nextnode (node)) {
+ adj =getdata (node);
+ adjinfo2nexthop6 (rinfo->nexthops6, adj);
+ }
+ }
+
+#endif /* HAVE_IPV6 */
+
+ rinfo->cost = cost;
+ rinfo->depth = depth;
+
+ return rinfo;
+}
+
+
+void
+isis_route_info_delete (struct isis_route_info *route_info)
+{
+
+ if (route_info->nexthops) {
+ route_info->nexthops->del = (void *)isis_nexthop_delete;
+ list_delete (route_info->nexthops);
+ }
+
+#ifdef HAVE_IPV6
+ if (route_info->nexthops6) {
+ route_info->nexthops6->del = (void *)isis_nexthop6_delete;
+ list_delete (route_info->nexthops6);
+ }
+#endif /* HAVE_IPV6 */
+
+ XFREE (MTYPE_ISIS_ROUTE_INFO, route_info);
+}
+
+int
+isis_route_info_same_attrib (struct isis_route_info *new,
+ struct isis_route_info *old)
+{
+ if (new->cost != old->cost)
+ return 0;
+ if (new->depth != old->depth)
+ return 0;
+
+ return 1;
+}
+
+int
+isis_route_info_same (struct isis_route_info *new, struct isis_route_info *old,
+ u_char family)
+{
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+#ifdef HAVE_IPV6
+ struct isis_nexthop6 *nexthop6;
+#endif /* HAVE_IPV6 */
+ if (!isis_route_info_same_attrib (new, old))
+ return 0;
+
+ if (family == AF_INET) {
+ for (node = listhead (new->nexthops); node; nextnode (node)) {
+ nexthop = (struct isis_nexthop *) getdata (node);
+ if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) == 0)
+ return 0;
+ }
+
+ for (node = listhead (old->nexthops); node; nextnode (node)) {
+ nexthop = (struct isis_nexthop *) getdata (node);
+ if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) == 0)
+ return 0;
+ }
+ }
+#ifdef HAVE_IPV6
+ else if (family == AF_INET6) {
+ for (node = listhead (new->nexthops6); node; nextnode (node)) {
+ nexthop6 = (struct isis_nexthop6 *) getdata (node);
+ if (nexthop6lookup (old->nexthops6, &nexthop6->ip6,
+ nexthop6->ifindex) == 0)
+ return 0;
+ }
+
+ for (node = listhead (old->nexthops6); node; nextnode (node)) {
+ nexthop6 = (struct isis_nexthop6 *) getdata (node);
+ if (nexthop6lookup (new->nexthops6, &nexthop6->ip6,
+ nexthop6->ifindex) == 0)
+ return 0;
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+ return 1;
+}
+
+
+void
+isis_nexthops_merge (struct list *new, struct list *old)
+{
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+
+ for (node = listhead (new); node; nextnode (node)) {
+ nexthop = (struct isis_nexthop *) getdata (node);
+ if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
+ continue;
+ listnode_add (old, nexthop);
+ nexthop->lock++;
+ }
+}
+
+
+#ifdef HAVE_IPV6
+void
+isis_nexthops6_merge (struct list *new, struct list *old)
+{
+ struct listnode *node;
+ struct isis_nexthop6 *nexthop6;
+
+ for (node = listhead (new); node; nextnode (node)) {
+ nexthop6 = (struct isis_nexthop6 *) getdata (node);
+ if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
+ continue;
+ listnode_add (old, nexthop6);
+ nexthop6->lock++;
+ }
+}
+#endif /* HAVE_IPV6 */
+
+void
+isis_route_info_merge (struct isis_route_info *new,
+ struct isis_route_info *old, u_char family)
+{
+
+ if (family == AF_INET)
+ isis_nexthops_merge (new->nexthops, old->nexthops);
+#ifdef HAVE_IPV6
+ else if (family == AF_INET6)
+ isis_nexthops6_merge (new->nexthops6, old->nexthops6);
+#endif /* HAVE_IPV6 */
+
+ return;
+}
+
+
+int
+isis_route_info_prefer_new (struct isis_route_info *new,
+ struct isis_route_info *old)
+{
+
+ if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
+ return 1;
+
+ if (new->cost < old->cost)
+ return 1;
+
+ return 0;
+}
+
+
+struct isis_route_info *
+isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
+ struct list *adjacencies, struct isis_area *area)
+{
+ struct route_node *route_node;
+ struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
+ u_char buff[BUFSIZ];
+ u_char family;
+
+ family = prefix->family;
+ /* for debugs */
+ prefix2str (prefix, buff, BUFSIZ);
+
+ rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
+ if (!rinfo_new) {
+ zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
+ area->area_tag);
+ return NULL;
+ }
+
+ if (family == AF_INET)
+ route_node = route_node_get (area->route_table, prefix);
+#ifdef HAVE_IPV6
+ else if (family == AF_INET6)
+ route_node = route_node_get (area->route_table6, prefix);
+#endif /* HAVE_IPV6 */
+ else
+ return NULL;
+ rinfo_old = route_node->info;
+ if (!rinfo_old) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
+ SET_FLAG(rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ route_node->info = rinfo_new;
+ return rinfo_new;
+ }
+
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte (%s) route already exists: %s", area->area_tag, buff);
+
+ if (isis_route_info_same (rinfo_new, rinfo_old, family)) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
+ isis_route_info_delete (rinfo_new);
+ route_info = rinfo_old;
+ } else if (isis_route_info_same_attrib (rinfo_new, rinfo_old)) {
+ /* merge the nexthop lists */
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte (%s) route changed (same attribs): %s",
+ area->area_tag, buff);
+#ifdef EXTREME_DEBUG
+ zlog_info ("Old nexthops");
+ nexthops6_print (rinfo_old->nexthops6);
+ zlog_info ("New nexthops");
+ nexthops6_print (rinfo_new->nexthops6);
+#endif /* EXTREME_DEBUG */
+ isis_route_info_merge (rinfo_new, rinfo_old, family);
+ isis_route_info_delete (rinfo_new);
+ route_info = rinfo_old;
+ } else {
+ if (isis_route_info_prefer_new (rinfo_new, rinfo_old)) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte (%s) route changed: %s", area->area_tag, buff);
+ isis_route_info_delete (rinfo_old);
+ route_info = rinfo_new;
+ } else {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte (%s) route rejected: %s", area->area_tag, buff);
+ isis_route_info_delete (rinfo_new);
+ route_info = rinfo_old;
+ }
+ }
+
+ SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ route_node->info = route_info;
+
+ return route_info;
+}
+
+void
+isis_route_delete (struct prefix *prefix, struct route_table *table)
+{
+ struct route_node *rode;
+ struct isis_route_info *rinfo;
+ char buff[BUFSIZ];
+
+ /* for log */
+ prefix2str (prefix, buff, BUFSIZ);
+
+
+ rode = route_node_get (table, prefix);
+ rinfo = rode->info;
+
+ if (rinfo == NULL) {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte: tried to delete non-existant route %s", buff);
+ return;
+ }
+
+ if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) {
+ UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_info ("ISIS-Rte: route delete %s", buff);
+ isis_zebra_route_update (prefix, rinfo);
+ }
+ isis_route_info_delete (rinfo);
+ rode->info = NULL;
+
+ return;
+}
+
+int
+isis_route_validate (struct thread *thread)
+{
+ struct isis_area *area;
+ struct route_table *table;
+ struct route_node *rode;
+ struct isis_route_info *rinfo;
+ u_char buff[BUFSIZ];
+#ifdef HAVE_IPV6
+ int v6done = 0;
+#endif
+ area = THREAD_ARG (thread);
+ table = area->route_table;
+#ifdef HAVE_IPV6
+ again:
+#endif
+ for (rode = route_top (table); rode; rode = route_next (rode)) {
+ if (rode->info == NULL)
+ continue;
+ rinfo = rode->info;
+
+ if (isis->debugs & DEBUG_RTE_EVENTS) {
+ prefix2str (&rode->p, buff, BUFSIZ);
+ zlog_info ("ISIS-Rte (%s): route validate: %s %s %s",
+ area->area_tag,
+ (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
+ "sync'ed": "nosync"),
+ (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
+ "active": "inactive"), buff);
+ }
+
+ isis_zebra_route_update (&rode->p, rinfo);
+ if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
+ isis_route_delete (&rode->p, area->route_table);
+ }
+#ifdef HAVE_IPV6
+ if (v6done)
+ return ISIS_OK;
+ table = area->route_table6;
+ v6done = 1;
+ goto again;
+#endif
+
+ return ISIS_OK;
+}
diff --git a/isisd/isis_route.h b/isisd/isis_route.h
new file mode 100644
index 00000000..7137948e
--- /dev/null
+++ b/isisd/isis_route.h
@@ -0,0 +1,61 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_route.h
+ *
+ * Copyright (C) 2001,2002 Sampo Saaristo
+ * Tampere University of Technology
+ * Institute of Communications Engineering
+ *
+ * based on ../ospf6d/ospf6_route.[ch]
+ * by Yasuhiro Ohara
+ *
+ * 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_ROUTE_H
+#define _ZEBRA_ISIS_ROUTE_H
+
+#ifdef HAVE_IPV6
+struct isis_nexthop6 {
+ unsigned int ifindex;
+ struct in6_addr ip6;
+ unsigned int lock;
+};
+#endif /* HAVE_IPV6 */
+
+struct isis_nexthop {
+ unsigned int ifindex;
+ struct in_addr ip;
+ unsigned int lock;
+};
+
+struct isis_route_info {
+#define ISIS_ROUTE_FLAG_ZEBRA_SYNC 0x01
+#define ISIS_ROUTE_FLAG_ACTIVE 0x02
+ u_char flag;
+ u_int32_t cost;
+ u_int32_t depth;
+ struct list *nexthops;
+#ifdef HAVE_IPV6
+ struct list *nexthops6;
+#endif /* HAVE_IPV6 */
+};
+
+struct isis_route_info *isis_route_create (struct prefix *prefix,
+ u_int32_t cost, u_int32_t depth,
+ struct list *adjacencies,
+ struct isis_area *area);
+
+int isis_route_validate (struct thread *thread);
+
+#endif /* _ZEBRA_ISIS_ROUTE_H */
diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c
new file mode 100644
index 00000000..4df983d2
--- /dev/null
+++ b/isisd/isis_routemap.c
@@ -0,0 +1,100 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_routemap.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 <stdlib.h>
+#include <stdio.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "hash.h"
+#include "if.h"
+#include "table.h"
+#include "routemap.h"
+
+#include "isis_constants.h"
+#include "isis_common.h"
+#include "dict.h"
+#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_spf.h"
+#include "isis_route.h"
+#include "isis_zebra.h"
+
+extern struct isis *isis;
+
+void
+isis_route_map_upd()
+{
+ int i = 0;
+
+ if (!isis)
+ return;
+
+ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) {
+ if (isis->rmap[i].name)
+ isis->rmap[i].map = isis->rmap[i].map =
+ route_map_lookup_by_name (isis->rmap[i].name);
+ else
+ isis->rmap[i].map = NULL;
+ }
+ /* FIXME: do the address family sub-mode AF_INET6 here ? */
+}
+
+void
+isis_route_map_event(route_map_event_t event, char *name)
+{
+ int type;
+
+ if (!isis)
+ return;
+
+ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
+ if (isis->rmap[type].name && isis->rmap[type].map &&
+ !strcmp (isis->rmap[type].name, name)) {
+ isis_distribute_list_update (type);
+ }
+ }
+}
+
+
+void
+isis_route_map_init (void)
+{
+ route_map_init ();
+ route_map_init_vty ();
+
+ route_map_add_hook (isis_route_map_upd);
+ route_map_delete_hook (isis_route_map_upd);
+ route_map_event_hook (isis_route_map_event);
+
+}
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
new file mode 100644
index 00000000..d6949817
--- /dev/null
+++ b/isisd/isis_spf.c
@@ -0,0 +1,1293 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_spf.c
+ * The SPT algorithm
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "thread.h"
+#include "linklist.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 "isis_constants.h"
+#include "isis_common.h"
+#include "dict.h"
+#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);
+
+/* performace issue ???? */
+void
+union_adjlist( struct list *target, struct list *source )
+{
+ struct isis_adjacency *adj, *adj2;
+ struct listnode *node, *node2;
+
+ zlog_info ("Union adjlist!");
+ for (node = listhead (source); node; nextnode (node)) {
+ adj = getdata (node);
+
+ /* lookup adjacency in the source list */
+ for (node2 = listhead (target); node2; nextnode (node2)) {
+ adj2 = getdata(node2);
+ if (adj == adj2) break;
+ }
+
+ if (!node2) listnode_add (target, adj);
+ }
+}
+
+
+/* 7.2.7 */
+void
+remove_excess_adjs (struct list *adjs)
+{
+ struct listnode *node, *excess = NULL;
+ struct isis_adjacency *adj, *candidate = NULL;
+ int comp;
+
+ for (node = listhead (adjs); node; nextnode (node)) {
+ if (excess == NULL)
+ excess = node;
+ candidate = getdata (excess);
+ adj = getdata (node);
+ if (candidate->sys_type < adj->sys_type) {
+ excess = node;
+ candidate = adj;
+ continue;
+ }
+ if (candidate->sys_type > adj->sys_type)
+ continue;
+
+ comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
+ if (comp > 0) {
+ excess = node;
+ candidate = adj;
+ continue;
+ }
+ if (comp < 0)
+ continue;
+
+ if (candidate->circuit->circuit_id > adj->circuit->circuit_id) {
+ excess = node;
+ candidate = adj;
+ continue;
+ }
+
+ if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
+ continue;
+
+ comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
+ if (comp > 0) {
+ excess = node;
+ candidate = adj;
+ continue;
+ }
+ }
+
+ list_delete_node (adjs, excess);
+
+ return;
+}
+
+const char *
+vtype2string (enum vertextype vtype)
+{
+ switch (vtype) {
+ case VTYPE_PSEUDO_IS:
+ return "pseudo_IS";
+ break;
+ case VTYPE_NONPSEUDO_IS:
+ return "IS";
+ break;
+ case VTYPE_ES:
+ return "ES";
+ break;
+ case VTYPE_IPREACH_INTERNAL:
+ return "IP internal";
+ break;
+ case VTYPE_IPREACH_EXTERNAL:
+ return "IP external";
+ break;
+#ifdef HAVE_IPV6
+ case VTYPE_IP6REACH_INTERNAL:
+ return "IP6 internal";
+ break;
+ case VTYPE_IP6REACH_EXTERNAL:
+ return "IP6 external";
+ break;
+#endif /* HAVE_IPV6 */
+ default:
+ return "UNKNOWN";
+ }
+ return NULL; /* Not reached */
+}
+
+char *
+vid2string (struct isis_vertex *vertex, u_char *buff)
+{
+ switch (vertex->type) {
+ case VTYPE_PSEUDO_IS:
+ return rawlspid_print (vertex->N.id);
+ break;
+ case VTYPE_NONPSEUDO_IS:
+ case VTYPE_ES:
+ return sysid_print (vertex->N.id);
+ break;
+ case VTYPE_IPREACH_INTERNAL:
+ case VTYPE_IPREACH_EXTERNAL:
+#ifdef HAVE_IPV6
+ case VTYPE_IP6REACH_INTERNAL:
+ case VTYPE_IP6REACH_EXTERNAL:
+#endif /* HAVE_IPV6 */
+ prefix2str ((struct prefix *)&vertex->N.prefix, buff, BUFSIZ);
+ break;
+ default:
+ return "UNKNOWN";
+ }
+
+ return buff;
+}
+
+struct isis_spftree *
+isis_spftree_new ()
+{
+ struct isis_spftree *tree;
+
+ tree = XMALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
+ if (tree == NULL) {
+ zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
+ return NULL;
+ }
+ memset (tree, 0, sizeof (struct isis_spftree));
+
+ tree->tents = list_new ();
+ tree->paths = list_new ();
+ return tree;
+}
+
+void
+isis_vertex_del (struct isis_vertex *vertex)
+{
+
+ list_delete (vertex->Adj_N);
+
+ XFREE (MTYPE_ISIS_VERTEX, vertex);
+
+ return;
+}
+
+void
+isis_spftree_del (struct isis_spftree *spftree)
+{
+
+ spftree->tents->del = (void *)isis_vertex_del;
+ list_delete (spftree->tents);
+
+ spftree->paths->del = (void *)isis_vertex_del;
+ list_delete (spftree->paths);
+
+ XFREE (MTYPE_ISIS_SPFTREE, spftree);
+
+ return;
+}
+
+void
+spftree_area_init (struct isis_area *area)
+{
+
+ if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL) {
+ area->spftree[0] = isis_spftree_new ();
+#ifdef HAVE_IPV6
+ area->spftree6[0] = isis_spftree_new ();
+#endif
+
+ /* thread_add_timer (master, isis_run_spf_l1, area,
+ isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
+ }
+
+ if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL) {
+ area->spftree[1] = isis_spftree_new ();
+#ifdef HAVE_IPV6
+ area->spftree6[1] = isis_spftree_new ();
+#endif
+ /* thread_add_timer (master, isis_run_spf_l2, area,
+ isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
+ }
+
+ return;
+}
+
+struct isis_vertex *
+isis_vertex_new (void *id, enum vertextype vtype)
+{
+ struct isis_vertex *vertex;
+
+ vertex = XMALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
+ if (vertex == NULL) {
+ zlog_err ("isis_vertex_new Out of memory!");
+ return NULL;
+ }
+
+ memset (vertex, 0, sizeof (struct isis_vertex));
+ vertex->type = vtype;
+ switch (vtype) {
+ case VTYPE_ES:
+ case VTYPE_NONPSEUDO_IS:
+ memcpy (vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN);
+ break;
+ case VTYPE_PSEUDO_IS:
+ memcpy (vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN + 1);
+ break;
+ case VTYPE_IPREACH_INTERNAL:
+ case VTYPE_IPREACH_EXTERNAL:
+#ifdef HAVE_IPV6
+ case VTYPE_IP6REACH_INTERNAL:
+ case VTYPE_IP6REACH_EXTERNAL:
+#endif /* HAVE_IPV6 */
+ memcpy (&vertex->N.prefix, (struct prefix *)id,
+ sizeof (struct prefix));
+ break;
+ default:
+ zlog_err ("WTF!");
+ }
+
+ vertex->Adj_N = list_new ();
+
+ return vertex;
+}
+
+/*
+ * Add this IS to the root of SPT
+ */
+void
+isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
+ int level)
+{
+ 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]);
+
+ if (lsp == NULL)
+ zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
+
+ vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
+ vertex->lsp = lsp;
+
+ listnode_add (spftree->paths, vertex);
+
+#ifdef EXTREME_DEBUG
+ zlog_info ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
+ vtype2string(vertex->type), vid2string(vertex, buff),
+ vertex->depth, vertex->d_N);
+#endif /* EXTREME_DEBUG */
+
+ return;
+}
+
+struct isis_vertex *
+isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
+{
+ struct listnode *node;
+ struct isis_vertex *vertex;
+ struct prefix *p1, *p2;
+
+ for (node = listhead (list); node; nextnode (node)) {
+ vertex = getdata (node);
+ if (vertex->type != vtype)
+ continue;
+ switch (vtype) {
+ case VTYPE_ES:
+ case VTYPE_NONPSEUDO_IS:
+ if (memcmp ((u_char *)id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
+ return vertex;
+ break;
+ case VTYPE_PSEUDO_IS:
+ if (memcmp ((u_char *)id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
+ return vertex;
+ break;
+ case VTYPE_IPREACH_INTERNAL:
+ case VTYPE_IPREACH_EXTERNAL:
+#ifdef HAVE_IPV6
+ case VTYPE_IP6REACH_INTERNAL:
+ case VTYPE_IP6REACH_EXTERNAL:
+#endif /* HAVE_IPV6 */
+ p1 = (struct prefix *)id;
+ p2 = (struct prefix *)&vertex->N.id;
+ if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
+ memcmp (&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen)) == 0)
+ return vertex;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/*
+ * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
+ */
+struct isis_vertex *
+isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
+ void *id, struct isis_adjacency *adj, u_int16_t cost,
+ int depth, int family)
+{
+ struct isis_vertex *vertex, *v;
+ struct listnode *node;
+#ifdef EXTREME_DEBUG
+ u_char buff[BUFSIZ];
+#endif
+
+ vertex = isis_vertex_new (id, vtype);
+ vertex->d_N = cost;
+ vertex->depth = depth;
+
+ if (adj)
+ listnode_add (vertex->Adj_N, adj);
+#ifdef EXTREME_DEBUG
+ zlog_info ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
+ 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;
+ }
+ for (node = listhead (spftree->tents); node; nextnode (node)) {
+ v = getdata (node);
+ if (v->d_N > vertex->d_N) {
+ list_add_node_prev (spftree->tents, node, vertex);
+ break;
+ } else if (v->d_N == vertex->d_N) {
+ /* Tie break, add according to type */
+ while (v && v->d_N == vertex->d_N && v->type > vertex->type) {
+ if (v->type > vertex->type) {
+ break;
+ }
+ nextnode (node);
+ (node) ? (v = getdata (node)) : (v = NULL);
+ }
+ list_add_node_prev (spftree->tents, node, vertex);
+ break;
+ } else if (node->next == NULL) {
+ list_add_node_next (spftree->tents, node, vertex);
+ break;
+ }
+ }
+ return vertex;
+}
+
+struct isis_vertex *
+isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
+ void *id, struct isis_adjacency *adj, u_int16_t cost,
+ int family)
+{
+ struct isis_vertex *vertex;
+
+ vertex = isis_find_vertex (spftree->tents, id, vtype);
+
+ if (vertex) {
+ /* C.2.5 c) */
+ if (vertex->d_N == cost) {
+ if (adj)
+ listnode_add (vertex->Adj_N, adj);
+ /* d) */
+ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
+ remove_excess_adjs (vertex->Adj_N);
+ }
+ /* f) */
+ else if (vertex->d_N > cost) {
+ listnode_delete (spftree->tents, vertex);
+ goto add2tent;
+ }
+ /* e) do nothing */
+ return vertex;
+ }
+
+ add2tent:
+ return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
+}
+
+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)
+{
+ struct isis_vertex *vertex;
+#ifdef EXTREME_DEBUG
+ u_char buff[255];
+#endif
+
+ /* C.2.6 b) */
+ if (dist > MAX_PATH_METRIC)
+ return;
+ /* c) */
+ vertex = isis_find_vertex (spftree->paths, id, vtype);
+ if (vertex) {
+#ifdef EXTREME_DEBUG
+ zlog_info ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
+ vtype2string(vtype), vid2string(vertex, buff), dist);
+#endif /* EXTREME_DEBUG */
+ assert (dist >= vertex->d_N);
+ return;
+ }
+
+ vertex = isis_find_vertex (spftree->tents, id, vtype);
+ /* d) */
+ if (vertex) {
+ /* 1) */
+#ifdef EXTREME_DEBUG
+ zlog_info ("ISIS-Spf: process_N %s %s dist %d",
+ vtype2string(vtype), vid2string(vertex, buff), dist);
+#endif /* EXTREME_DEBUG */
+ if (vertex->d_N == dist) {
+ if (adj)
+ listnode_add (vertex->Adj_N, adj);
+ /* 2) */
+ if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
+ remove_excess_adjs (vertex->Adj_N);
+ /* 3) */
+ return;
+ } else if (vertex->d_N < dist) {
+ return;
+ /* 4) */
+ } else {
+ listnode_delete (spftree->tents, vertex);
+ }
+ }
+
+ isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
+ return;
+}
+
+/*
+ * C.2.6 Step 1
+ */
+int
+isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
+ uint16_t cost, uint16_t depth, int family)
+{
+ struct listnode *node, *fragnode = NULL;
+ u_int16_t dist;
+ struct is_neigh *is_neigh;
+ struct ipv4_reachability *ipreach;
+ enum vertextype vtype;
+ struct prefix prefix;
+#ifdef HAVE_IPV6
+ struct ipv6_reachability *ip6reach;
+#endif /* HAVE_IPV6 */
+
+
+ if (!lsp->adj)
+ return ISIS_WARNING;
+ if (lsp->tlv_data.nlpids == NULL ||
+ !speaks (lsp->tlv_data.nlpids, family))
+ return ISIS_OK;
+
+ lspfragloop:
+ if (lsp->lsp_header->seq_num == 0) {
+ zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
+ " - do not process");
+ return ISIS_WARNING;
+ }
+
+ if (!ISIS_MASK_LSP_OL_BIT(lsp->lsp_header->lsp_bits)) {
+ if (lsp->tlv_data.is_neighs) {
+ for (node = listhead (lsp->tlv_data.is_neighs); node; nextnode (node)) {
+ is_neigh = getdata (node);
+ /* C.2.6 a) */
+ /* Two way connectivity */
+ if (!memcmp (is_neigh->neigh_id, isis->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);
+ }
+ }
+ if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) {
+ prefix.family = AF_INET;
+ for (node = listhead (lsp->tlv_data.ipv4_int_reachs); node;
+ nextnode (node)) {
+ ipreach = getdata (node);
+ dist = cost + ipreach->metrics.metric_default;
+ vtype = VTYPE_IPREACH_INTERNAL;
+ prefix.u.prefix4 = ipreach->prefix;
+ prefix.prefixlen = ip_masklen (ipreach->mask);
+ process_N (spftree, vtype, (void *)&prefix, dist, depth + 1,
+ lsp->adj, family);
+ }
+ }
+
+ if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) {
+ prefix.family = AF_INET;
+ for (node = listhead (lsp->tlv_data.ipv4_ext_reachs); node;
+ nextnode (node)) {
+ ipreach = getdata (node);
+ dist = cost + ipreach->metrics.metric_default;
+ vtype = VTYPE_IPREACH_EXTERNAL;
+ prefix.u.prefix4 = ipreach->prefix;
+ prefix.prefixlen = ip_masklen (ipreach->mask);
+ process_N (spftree, vtype, (void *)&prefix, dist, depth + 1,
+ lsp->adj, family);
+ }
+ }
+#ifdef HAVE_IPV6
+ if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) {
+ prefix.family = AF_INET6;
+ for (node = listhead (lsp->tlv_data.ipv6_reachs); node;
+ nextnode (node)) {
+ ip6reach = getdata (node);
+ dist = cost + ip6reach->metric;
+ vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
+ VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
+ prefix.prefixlen = ip6reach->prefix_len;
+ memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
+ PSIZE(ip6reach->prefix_len));
+ process_N (spftree, vtype, (void *)&prefix, dist, depth + 1,
+ lsp->adj, family);
+ }
+ }
+#endif /* HAVE_IPV6 */
+ }
+
+ if (fragnode == NULL)
+ fragnode = listhead (lsp->lspu.frags);
+ else
+ fragnode = nextnode (fragnode);
+
+ if (fragnode) {
+ lsp = getdata (fragnode);
+ goto lspfragloop;
+ }
+
+ return ISIS_OK;
+}
+
+int
+isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,struct isis_lsp *lsp,
+ uint16_t cost, uint16_t depth, int family)
+{
+ struct listnode *node, *fragnode = NULL;
+ struct is_neigh *is_neigh;
+ enum vertextype vtype;
+
+ pseudofragloop:
+
+ if (lsp->lsp_header->seq_num == 0) {
+ zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
+ " - do not process");
+ return ISIS_WARNING;
+ }
+
+ for (node = (lsp->tlv_data.is_neighs ?
+ listhead (lsp->tlv_data.is_neighs) : NULL);
+ node; nextnode (node)) {
+ is_neigh = getdata (node);
+ 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))
+ continue;
+ if (isis_find_vertex (spftree->tents, (void *)is_neigh->neigh_id, vtype)
+ == NULL &&
+ isis_find_vertex (spftree->paths, (void *)is_neigh->neigh_id, vtype)
+ == NULL) {
+ /* C.2.5 i) */
+ isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj,
+ cost, depth, family);
+ }
+ }
+
+ if (fragnode == NULL)
+ fragnode = listhead (lsp->lspu.frags);
+ else
+ fragnode = nextnode (fragnode);
+
+ if (fragnode) {
+ lsp = getdata (fragnode);
+ goto pseudofragloop;
+ }
+
+
+ return ISIS_OK;
+}
+
+int
+isis_spf_preload_tent (struct isis_spftree *spftree,
+ struct isis_area *area, int level, int family)
+{
+ struct isis_vertex *vertex;
+ struct isis_circuit *circuit;
+ struct listnode *cnode, *anode, *ipnode;
+ struct isis_adjacency *adj;
+ struct isis_lsp *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];
+#ifdef HAVE_IPV6
+ struct prefix_ipv6 *ipv6;
+#endif /* HAVE_IPV6 */
+
+ for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode)) {
+ circuit = getdata (cnode);
+ if (circuit->state != C_STATE_UP)
+ continue;
+ if (!(circuit->circuit_is_type & level))
+ continue;
+ if (family == AF_INET && !circuit->ip_router)
+ continue;
+#ifdef HAVE_IPV6
+ if (family == AF_INET6 && !circuit->ipv6_router)
+ continue;
+#endif /* HAVE_IPV6 */
+ /*
+ * Add IP(v6) addresses of this circuit
+ */
+ if (family == AF_INET) {
+ prefix.family = AF_INET;
+ for (ipnode = (circuit->ip_addrs ? listhead (circuit->ip_addrs) : NULL);
+ ipnode; nextnode (ipnode)) {
+ ipv4 = getdata (ipnode);
+ prefix.u.prefix4 = ipv4->prefix;
+ prefix.prefixlen = ipv4->prefixlen;
+ isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, NULL, 0,
+ family);
+ }
+ }
+#ifdef HAVE_IPV6
+ if (family == AF_INET6) {
+ prefix.family = AF_INET6;
+ for (ipnode = (circuit->ipv6_non_link ? listhead
+ (circuit->ipv6_non_link) : NULL); ipnode;
+ nextnode (ipnode)) {
+ ipv6 = getdata (ipnode);
+ prefix.prefixlen = ipv6->prefixlen;
+ prefix.u.prefix6 = ipv6->prefix;
+ isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
+ &prefix, NULL, 0, family);
+ }
+ }
+#endif /* HAVE_IPV6 */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST ) {
+ /*
+ * Add the adjacencies
+ */
+ adj_list = list_new ();
+ adjdb = circuit->u.bc.adjdb[level - 1];
+ isis_adj_build_up_list (adjdb, adj_list);
+ if (listcount (adj_list) == 0) {
+ list_delete (adj_list);
+ zlog_warn ("ISIS-Spf: no L%d adjacencies on circuit %s",
+ level, circuit->interface->name);
+ continue;
+ }
+ anode = listhead (adj_list);
+ while (anode) {
+ adj = getdata (anode);
+ if (!speaks (&adj->nlpids, family))
+ continue;
+ switch (adj->sys_type) {
+ case ISIS_SYSTYPE_ES:
+ isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
+ circuit->metrics[level - 1].metric_default,
+ family);
+ break;
+ case ISIS_SYSTYPE_IS:
+ case ISIS_SYSTYPE_L1_IS:
+ case ISIS_SYSTYPE_L2_IS:
+ vertex =
+ isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
+ adj->sysid, adj,
+ circuit->metrics[level - 1].metric_default,
+ family);
+ 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");
+ /* else {
+ isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
+ } */
+ break;
+ case ISIS_SYSTYPE_UNKNOWN:
+ default:
+ zlog_warn ("isis_spf_preload_tent unknow adj type");
+ }
+ anode = nextnode (anode);
+ }
+ list_delete (adj_list);
+ /*
+ * Add the pseudonode
+ */
+ if (level == 1)
+ 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);
+ 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");
+ }
+ if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) {
+ zlog_warn ("ISIS-Spf: No lsp found for DR");
+ } else {
+ isis_spf_process_pseudo_lsp
+ (spftree, lsp, circuit->metrics[level - 1].metric_default, 0,
+ family);
+
+ }
+ } else if (circuit->circ_type == CIRCUIT_T_P2P ) {
+ adj = circuit->u.p2p.neighbor;
+ if (!adj)
+ continue;
+ switch (adj->sys_type) {
+ case ISIS_SYSTYPE_ES:
+ isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
+ circuit->metrics[level - 1].metric_default,
+ family);
+ 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, adj,
+ circuit->metrics[level - 1].metric_default,
+ family);
+ break;
+ case ISIS_SYSTYPE_UNKNOWN:
+ default:
+ zlog_warn ("isis_spf_preload_tent unknow adj type");
+ break;
+ }
+ } else {
+ zlog_warn ("isis_spf_preload_tent unsupported media");
+ retval = ISIS_WARNING;
+ }
+
+ }
+
+ return retval;
+}
+
+/*
+ * The parent(s) for vertex is set when added to TENT list
+ * now we just put the child pointer(s) in place
+ */
+void
+add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
+ struct isis_area *area)
+{
+
+#ifdef EXTREME_DEBUG
+ u_char buff[BUFSIZ];
+#endif /* EXTREME_DEBUG */
+ listnode_add (spftree->paths, vertex);
+
+#ifdef EXTREME_DEBUG
+ zlog_info ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
+ vtype2string(vertex->type), vid2string(vertex, buff),
+ vertex->depth, vertex->d_N);
+#endif /* EXTREME_DEBUG */
+ if (vertex->type > VTYPE_ES) {
+ if (listcount(vertex->Adj_N) > 0)
+ isis_route_create ((struct prefix *)&vertex->N.prefix,
+ vertex->d_N, vertex->depth, vertex->Adj_N, area);
+ else if (isis->debugs & DEBUG_SPF_EVENTS)
+ zlog_info ("ISIS-Spf: no adjacencies do not install route");
+ }
+
+ return;
+}
+
+
+void
+init_spt (struct isis_spftree *spftree)
+{
+ spftree->tents->del = spftree->paths->del = (void *)isis_vertex_del;
+ list_delete_all_node (spftree->tents);
+ list_delete_all_node (spftree->paths);
+ spftree->tents->del = spftree->paths->del = NULL;
+
+ return;
+}
+
+int
+isis_run_spf (struct isis_area *area, int level, int family)
+{
+ int retval = ISIS_OK;
+ struct listnode *node;
+ struct isis_vertex *vertex;
+ struct isis_spftree *spftree = NULL;
+ u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ struct isis_lsp *lsp;
+
+ 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);
+
+ /*
+ * C.2.5 Step 0
+ */
+ init_spt (spftree);
+ /* a) */
+ isis_spf_add_self (spftree, area, level);
+ /* b) */
+ retval = isis_spf_preload_tent (spftree, area, level, family);
+
+ /*
+ * C.2.7 Step 2
+ */
+ if (listcount (spftree->tents) == 0) {
+ zlog_warn ("ISIS-Spf: TENT is empty");
+ spftree->lastrun = time (NULL);
+ return retval;
+ }
+
+ while (listcount (spftree->tents) > 0) {
+ node = listhead (spftree->tents);
+ vertex = getdata (node);
+ /* 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);
+ if (vertex->type == VTYPE_PSEUDO_IS ||
+ vertex->type == VTYPE_NONPSEUDO_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]);
+ if (lsp) {
+ if (LSP_PSEUDO_ID (lsp_id)) {
+ isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
+ vertex->depth, family);
+
+ } else {
+ isis_spf_process_lsp (spftree, lsp, vertex->d_N, vertex->depth,
+ family);
+ }
+ } else {
+ zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id));
+ }
+ }
+ }
+
+ thread_add_event (master, isis_route_validate, area, 0);
+ spftree->lastrun = time (NULL);
+ spftree->pending = 0;
+
+ if (level == 1)
+ spftree->t_spf_periodic = thread_add_timer (master,
+ isis_run_spf_l1, area,
+ isis_jitter
+ (PERIODIC_SPF_INTERVAL, 10));
+ else
+ spftree->t_spf_periodic = thread_add_timer (master,
+ isis_run_spf_l2, area,
+ isis_jitter
+ (PERIODIC_SPF_INTERVAL, 10));
+
+ return retval;
+}
+
+int
+isis_run_spf_l1 (struct thread *thread)
+{
+ struct isis_area *area;
+ int retval = ISIS_OK;
+
+ area = THREAD_ARG(thread);
+ assert (area);
+
+ 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_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF",
+ area->area_tag);
+ }
+
+ if (area->ip_circuits)
+ retval = isis_run_spf (area, 1, AF_INET);
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits)
+ retval = isis_run_spf (area, 1, AF_INET6);
+#endif
+ return retval;
+}
+
+int
+isis_run_spf_l2 (struct thread *thread)
+{
+ struct isis_area *area;
+ int retval = ISIS_OK;
+
+ area = THREAD_ARG(thread);
+ assert (area);
+
+ if (!(area->is_type & IS_LEVEL_2)) {
+ 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_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF",
+ area->area_tag);
+ }
+
+ if (area->ip_circuits)
+ retval = isis_run_spf (area, 2, AF_INET);
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits)
+ retval = isis_run_spf (area, 2, AF_INET6);
+#endif
+
+ return retval;
+}
+
+int
+isis_spf_schedule (struct isis_area *area, int level)
+{
+ int retval = ISIS_OK;
+ struct isis_spftree *spftree = area->spftree[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) {
+ if (level == 1)
+ thread_add_timer (master, isis_run_spf_l1, area,
+ 60);
+ else
+ thread_add_timer (master, isis_run_spf_l2, area,
+ 60);
+
+ spftree->pending = 1;
+ return retval;
+ }
+ if (spftree->t_spf_periodic)
+ thread_cancel (spftree->t_spf_periodic);
+
+ if (diff < MINIMUM_SPF_INTERVAL) {
+ if (level == 1)
+ thread_add_timer (master, isis_run_spf_l1, area,
+ MINIMUM_SPF_INTERVAL - diff);
+ else
+ thread_add_timer (master, isis_run_spf_l2, area,
+ MINIMUM_SPF_INTERVAL - diff);
+
+ spftree->pending = 1;
+ } else {
+ spftree->pending = 0;
+ retval = isis_run_spf (area, level, AF_INET);
+ }
+
+ return retval;
+}
+
+#ifdef HAVE_IPV6
+int
+isis_spf_schedule6 (struct isis_area *area, int level)
+{
+ int retval = ISIS_OK;
+ struct isis_spftree *spftree = area->spftree6[level - 1];
+ time_t diff, now = time (NULL);
+
+ if (spftree->pending)
+ return retval;
+
+ diff = now - spftree->lastrun;
+
+ if (spftree->t_spf_periodic)
+ thread_cancel (spftree->t_spf_periodic);
+
+ /* FIXME: let's wait a minute before doing the SPF */
+ if (now - isis->uptime < 60 || isis->uptime == 0) {
+ if (level == 1)
+ thread_add_timer (master, isis_run_spf_l1, area,
+ 60);
+ else
+ thread_add_timer (master, isis_run_spf_l2, area,
+ 60);
+
+ spftree->pending = 1;
+ return retval;
+ }
+
+
+ if (diff < MINIMUM_SPF_INTERVAL) {
+ if (level == 1)
+ thread_add_timer (master, isis_run_spf_l1, area,
+ MINIMUM_SPF_INTERVAL - diff);
+ else
+ thread_add_timer (master, isis_run_spf_l2, area,
+ MINIMUM_SPF_INTERVAL - diff);
+
+ spftree->pending = 1;
+ } else {
+ spftree->pending = 0;
+ retval = isis_run_spf (area, level, AF_INET6);
+ }
+
+ return retval;
+}
+
+#endif
+
+void
+isis_print_paths (struct vty *vty, struct list *paths)
+{
+ struct listnode *node, *anode;
+ struct isis_vertex *vertex;
+ struct isis_dynhn *dyn, *nh_dyn = NULL;
+ struct isis_adjacency *adj;
+#ifdef EXTREME_DEBUG
+ u_char buff[255];
+#endif
+
+ vty_out (vty, "System Id Metric Next-Hop"
+ " Interface SNPA%s", VTY_NEWLINE);
+ for (node = listhead (paths); node; nextnode (node)) {
+ vertex = getdata (node);
+ if (vertex->type != VTYPE_NONPSEUDO_IS)
+ continue;
+ if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
+ vty_out (vty, "%s --%s", host.name, VTY_NEWLINE);
+ } else {
+ dyn = dynhn_find_by_id ((u_char *)vertex->N.id);
+ anode = listhead (vertex->Adj_N);
+ adj = getdata (anode);
+ if (adj) {
+ nh_dyn = dynhn_find_by_id (adj->sysid);
+ vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
+ (dyn != NULL) ? dyn->name.name :
+ (u_char *)rawlspid_print ((u_char *)vertex->N.id),
+ vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
+ (u_char *)rawlspid_print (adj->sysid),
+ adj->circuit->interface->name,
+ snpa_print (adj->snpa), VTY_NEWLINE);
+ } else {
+ vty_out (vty, "%s %u %s", dyn ? dyn->name.name :
+ (u_char *)rawlspid_print (vertex->N.id),
+ vertex->d_N, VTY_NEWLINE);
+ }
+
+ }
+#if 0
+ vty_out (vty, "%s %s %u %s", vtype2string(vertex->type),
+ vid2string(vertex, buff), vertex->d_N, VTY_NEWLINE);
+#endif
+ }
+
+
+}
+
+DEFUN (show_isis_topology,
+ show_isis_topology_cmd,
+ "show isis topology",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS paths to Intermediate Systems\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+ int level;
+
+ if (!isis->area_list || isis->area_list->count == 0)
+ return CMD_SUCCESS;
+
+ for (node = listhead (isis->area_list); node; nextnode (node)) {
+ area = getdata (node);
+
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+
+ for (level=0; level < ISIS_LEVELS; level++) {
+ if (area->ip_circuits > 0 && area->spftree[level]
+ && area->spftree[level]->paths->count > 0) {
+ 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);
+ }
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits > 0 && area->spftree6[level]
+ && area->spftree6[level]->paths->count > 0) {
+ 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);
+ }
+#endif /* HAVE_IPV6 */
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_isis_topology_l1,
+ show_isis_topology_l1_cmd,
+ "show isis topology level-1",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS paths to Intermediate Systems\n"
+ "Paths to all level-1 routers in the area\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+
+ if (!isis->area_list || isis->area_list->count == 0)
+ return CMD_SUCCESS;
+
+ for (node = listhead (isis->area_list); node; nextnode (node)) {
+ area = getdata (node);
+
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+
+ if (area->ip_circuits > 0 && area->spftree[0]
+ && area->spftree[0]->paths->count > 0) {
+ vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
+ VTY_NEWLINE);
+ isis_print_paths (vty, area->spftree[0]->paths);
+ }
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits > 0 && area->spftree6[0]
+ && area->spftree6[0]->paths->count > 0) {
+ vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
+ VTY_NEWLINE);
+ isis_print_paths (vty, area->spftree6[0]->paths);
+ }
+#endif /* HAVE_IPV6 */
+ }
+
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_isis_topology_l2,
+ show_isis_topology_l2_cmd,
+ "show isis topology level-2",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS paths to Intermediate Systems\n"
+ "Paths to all level-2 routers in the domain\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+
+ if (!isis->area_list || isis->area_list->count == 0)
+ return CMD_SUCCESS;
+
+ for (node = listhead (isis->area_list); node; nextnode (node)) {
+ area = getdata (node);
+
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+
+ if (area->ip_circuits > 0 && area->spftree[1]
+ && area->spftree[1]->paths->count > 0) {
+ vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
+ VTY_NEWLINE);
+ isis_print_paths (vty, area->spftree[1]->paths);
+ }
+#ifdef HAVE_IPV6
+ if (area->ipv6_circuits > 0 && area->spftree6[1]
+ && area->spftree6[1]->paths->count > 0) {
+ vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
+ VTY_NEWLINE);
+ isis_print_paths (vty, area->spftree6[1]->paths);
+ }
+#endif /* HAVE_IPV6 */
+ }
+
+
+ return CMD_SUCCESS;
+}
+
+
+void
+isis_spf_cmds_init ()
+{
+ install_element (VIEW_NODE, &show_isis_topology_cmd);
+ install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
+ install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
+
+ install_element (ENABLE_NODE, &show_isis_topology_cmd);
+ install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
+ install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
+}
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
new file mode 100644
index 00000000..59e4b6b5
--- /dev/null
+++ b/isisd/isis_spf.h
@@ -0,0 +1,85 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_spf.h
+ * IS-IS Shortest Path First algorithm
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_SPF_H
+#define _ZEBRA_ISIS_SPF_H
+
+enum vertextype {
+ VTYPE_PSEUDO_IS = 1,
+ VTYPE_NONPSEUDO_IS,
+ VTYPE_ES,
+ VTYPE_IPREACH_INTERNAL,
+ VTYPE_IPREACH_EXTERNAL
+#ifdef HAVE_IPV6
+ ,
+ VTYPE_IP6REACH_INTERNAL,
+ VTYPE_IP6REACH_EXTERNAL
+#endif /* HAVE_IPV6 */
+};
+
+/*
+ * Triple <N, d(N), {Adj(N)}>
+ */
+struct isis_vertex
+{
+ enum vertextype type;
+
+ union {
+ u_char id [ISIS_SYS_ID_LEN + 1];
+ struct prefix prefix;
+ } N;
+
+ struct isis_lsp *lsp;
+ 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 isis_spftree
+{
+ struct thread *t_spf_periodic; /* periodic spf threads */
+ time_t lastrun; /* for scheduling */
+ int pending; /* already scheduled */
+ struct list *paths; /* the SPT */
+ struct list *tents; /* TENT */
+
+ u_int32_t timerun; /* statistics */
+};
+
+void spftree_area_init (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
+#endif /* _ZEBRA_ISIS_SPF_H */
+
+
+
+
+
+
+
+
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
new file mode 100644
index 00000000..b51cee91
--- /dev/null
+++ b/isisd/isis_tlv.c
@@ -0,0 +1,1014 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_tlv.c
+ * IS-IS TLV related routines
+ *
+ * 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>
+
+#include "log.h"
+#include "linklist.h"
+#include "stream.h"
+#include "memory.h"
+#include "prefix.h"
+#include "vty.h"
+#include "if.h"
+
+#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/isis_tlv.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_lsp.h"
+
+extern struct isis *isis;
+
+void
+free_tlv (void *val)
+{
+ XFREE (MTYPE_ISIS_TLV, val);
+
+ return;
+}
+
+/*
+ * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
+ * is only a caution to avoid memory leaks
+ */
+void
+free_tlvs (struct tlvs *tlvs)
+{
+ if (tlvs->area_addrs) {
+ list_delete (tlvs->area_addrs);
+ }
+ if (tlvs->is_neighs) {
+ list_delete (tlvs->is_neighs);
+ }
+ if (tlvs->te_is_neighs) {
+ list_delete (tlvs->te_is_neighs);
+ }
+ if (tlvs->es_neighs) {
+ list_delete (tlvs->es_neighs);
+ }
+ if (tlvs->lsp_entries) {
+ list_delete (tlvs->lsp_entries);
+ }
+ if (tlvs->lan_neighs) {
+ list_delete (tlvs->lan_neighs);
+ }
+ if (tlvs->prefix_neighs) {
+ list_delete (tlvs->prefix_neighs);
+ }
+ if (tlvs->ipv4_addrs) {
+ list_delete (tlvs->ipv4_addrs);
+ }
+ if (tlvs->ipv4_int_reachs) {
+ list_delete (tlvs->ipv4_int_reachs);
+ }
+ if (tlvs->ipv4_ext_reachs) {
+ list_delete (tlvs->ipv4_ext_reachs);
+ }
+ if (tlvs->te_ipv4_reachs) {
+ list_delete (tlvs->te_ipv4_reachs);
+ }
+#ifdef HAVE_IPV6
+ if (tlvs->ipv6_addrs) {
+ list_delete (tlvs->ipv6_addrs);
+ }
+ if (tlvs->ipv6_reachs) {
+ list_delete (tlvs->ipv6_reachs);
+ }
+#endif /* HAVE_IPV6 */
+ return;
+}
+
+/*
+ * Parses the tlvs found in the variant length part of the PDU.
+ * Caller tells with flags in "expected" which TLV's it is interested in.
+ */
+int
+parse_tlvs (char *areatag, u_char *stream, int size, u_int32_t *expected,
+ u_int32_t *found, struct tlvs *tlvs)
+{
+ u_char type, length;
+ struct lan_neigh *lan_nei;
+ struct area_addr *area_addr;
+ struct is_neigh *is_nei;
+ struct te_is_neigh *te_is_nei;
+ struct es_neigh *es_nei;
+ struct lsp_entry *lsp_entry;
+ struct in_addr *ipv4_addr;
+ struct ipv4_reachability *ipv4_reach;
+ struct te_ipv4_reachability *te_ipv4_reach;
+#ifdef HAVE_IPV6
+ struct in6_addr *ipv6_addr;
+ struct ipv6_reachability *ipv6_reach;
+ int prefix_octets;
+#endif /* HAVE_IPV6 */
+ u_char virtual;
+ int value_len, retval = ISIS_OK;
+ u_char *pnt = stream;
+
+ *found = 0;
+ memset (tlvs, 0, sizeof (struct tlvs));
+
+ while (pnt < stream + size - 2) {
+ type = *pnt;
+ length = *(pnt+1);
+ pnt += 2;
+ value_len = 0;
+ if ( pnt + length > stream + size ) {
+ zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
+ "boundaries", areatag, type, length);
+ retval = ISIS_WARNING;
+ break;
+ }
+ switch (type) {
+ case AREA_ADDRESSES:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Address Length |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Area Address |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * : :
+ */
+ *found |= TLVFLAG_AREA_ADDRS;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("TLV Area Adresses len %d", length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_AREA_ADDRS) {
+ while (length > value_len) {
+ area_addr = (struct area_addr*)pnt;
+ value_len += area_addr->addr_len + 1;
+ pnt += area_addr->addr_len + 1;
+ if (!tlvs->area_addrs) tlvs->area_addrs = list_new ();
+ listnode_add (tlvs->area_addrs, area_addr);
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case IS_NEIGHBOURS:
+ *found |= TLVFLAG_IS_NEIGHS;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IS Neighbours length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (TLVFLAG_IS_NEIGHS & *expected) {
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Virtual Flag |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+ virtual = *pnt; /* FIXME: what is the use for this? */
+ pnt++;
+ value_len ++;
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | 0 | I/E | Default Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Delay Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Expense Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Error Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Neighbour ID |
+ * +---------------------------------------------------------------+
+ * : :
+ */
+ while (length > value_len) {
+ is_nei = (struct is_neigh*)pnt;
+ value_len += 4 + ISIS_SYS_ID_LEN + 1;
+ pnt += 4 + ISIS_SYS_ID_LEN + 1;
+ if (!tlvs->is_neighs) tlvs->is_neighs = list_new ();
+ listnode_add (tlvs->is_neighs, is_nei);
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case TE_IS_NEIGHBOURS:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Neighbour ID | 7
+ * +---------------------------------------------------------------+
+ * | TE Metric | 3
+ * +---------------------------------------------------------------+
+ * | SubTLVs Length | 1
+ * +---------------------------------------------------------------+
+ * : :
+ */
+ *found |= TLVFLAG_TE_IS_NEIGHS;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): Extended IS Neighbours length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (TLVFLAG_TE_IS_NEIGHS & *expected) {
+ while (length > value_len) {
+ te_is_nei = (struct te_is_neigh*)pnt;
+ value_len += 11;
+ pnt += 11;
+ /* FIXME - subtlvs are handled here, for now we skip */
+ value_len += te_is_nei->sub_tlvs_length;
+ pnt += te_is_nei->sub_tlvs_length;
+
+
+ if (!tlvs->te_is_neighs) tlvs->te_is_neighs = list_new ();
+ listnode_add (tlvs->te_is_neighs, te_is_nei);
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case ES_NEIGHBOURS:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | 0 | I/E | Default Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Delay Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Expense Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Error Metric |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Neighbour ID |
+ * +---------------------------------------------------------------+
+ * | Neighbour ID |
+ * +---------------------------------------------------------------+
+ * : :
+ */
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): ES Neighbours length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ *found |= TLVFLAG_ES_NEIGHS;
+ if (*expected & TLVFLAG_ES_NEIGHS) {
+ es_nei = (struct es_neigh*)pnt;
+ value_len += 4;
+ pnt += 4;
+ while (length > value_len) {
+ /* FIXME FIXME FIXME - add to the list */
+ /* sys_id->id = pnt;*/
+ value_len += ISIS_SYS_ID_LEN;
+ pnt += ISIS_SYS_ID_LEN;
+ /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid;*/
+ }
+ if (!tlvs->es_neighs) tlvs->es_neighs = list_new ();
+ listnode_add (tlvs->es_neighs, es_nei);
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case LAN_NEIGHBOURS:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | LAN Address |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * : :
+ */
+ *found |= TLVFLAG_LAN_NEIGHS;
+ #ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): LAN Neigbours length %d",
+ areatag,
+ length);
+ #endif /* EXTREME_TLV_DEBUG */
+ if (TLVFLAG_LAN_NEIGHS & *expected) {
+ while (length > value_len) {
+ lan_nei = (struct lan_neigh*)pnt;
+ if (!tlvs->lan_neighs) tlvs->lan_neighs = list_new ();
+ listnode_add (tlvs->lan_neighs, lan_nei);
+ value_len += ETH_ALEN;
+ pnt += ETH_ALEN;
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case PADDING:
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("TLV padding %d", length);
+#endif /* EXTREME_TLV_DEBUG */
+ pnt += length;
+ break;
+
+ case LSP_ENTRIES:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Remaining Lifetime | 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | LSP ID | id+2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | LSP Sequence Number | 4
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Checksum | 2
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("LSP Entries length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ *found |= TLVFLAG_LSP_ENTRIES;
+ if (TLVFLAG_LSP_ENTRIES & *expected) {
+ while (length > value_len) {
+ lsp_entry = (struct lsp_entry*)pnt;
+ value_len += 10 + ISIS_SYS_ID_LEN;
+ pnt += 10 + ISIS_SYS_ID_LEN;
+ if (!tlvs->lsp_entries) tlvs->lsp_entries = list_new ();
+ listnode_add (tlvs->lsp_entries, lsp_entry);
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case CHECKSUM:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | 16 bit fletcher CHECKSUM |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * : :
+ */
+ *found |= TLVFLAG_CHECKSUM;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): Checksum length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_CHECKSUM) {
+ tlvs->checksum = (struct checksum*)pnt;
+ }
+ pnt += length;
+ break;
+
+ case PROTOCOLS_SUPPORTED:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | NLPID |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * : :
+ */
+ *found |= TLVFLAG_NLPID;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): Protocols Supported length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_NLPID) {
+ tlvs->nlpids = (struct nlpids*)(pnt-1);
+ }
+ pnt += length;
+ break;
+
+ case IPV4_ADDR:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + IP version 4 address + 4
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * : :
+ */
+ *found |= TLVFLAG_IPV4_ADDR;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IPv4 Address length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_IPV4_ADDR) {
+ while (length > value_len) {
+ ipv4_addr = (struct in_addr*)pnt;
+ zlog_info ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag,
+ inet_ntoa (*ipv4_addr), pnt);
+ if (!tlvs->ipv4_addrs) tlvs->ipv4_addrs = list_new();
+ listnode_add (tlvs->ipv4_addrs, ipv4_addr);
+ value_len += 4;
+ pnt += 4;
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case AUTH_INFO:
+ *found |= TLVFLAG_AUTH_INFO;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IS-IS Authentication Information",
+ areatag);
+#endif
+ if (*expected & TLVFLAG_AUTH_INFO) {
+ tlvs->auth_info.type = *pnt;
+ pnt++;
+ memcpy (tlvs->auth_info.passwd, pnt, length - 1);
+ pnt += length - 1;
+ }
+ else {
+ pnt += length;
+ }
+ break;
+
+ case DYNAMIC_HOSTNAME:
+ *found |= TLVFLAG_DYN_HOSTNAME;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): Dynamic Hostname length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_DYN_HOSTNAME) {
+ /* the length is also included in the pointed struct */
+ tlvs->hostname = (struct hostname*)(pnt - 1);
+ }
+ pnt += length;
+ break;
+
+ case TE_ROUTER_ID:
+ /* +---------------------------------------------------------------+
+ * + Router ID + 4
+ * +---------------------------------------------------------------+
+ */
+ *found |= TLVFLAG_TE_ROUTER_ID;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): TE Router ID %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_TE_ROUTER_ID) {
+ tlvs->router_id = (struct te_router_id*)(pnt);
+ }
+ pnt += length;
+ break;
+
+ case IPV4_INT_REACHABILITY:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | 0 | I/E | Default Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Delay Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Expense Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Error Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | ip address | 4
+ * +---------------------------------------------------------------+
+ * | address mask | 4
+ * +---------------------------------------------------------------+
+ * : :
+ */
+ *found |= TLVFLAG_IPV4_INT_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IPv4 internal Reachability length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) {
+ while (length > value_len) {
+ ipv4_reach = (struct ipv4_reachability*)pnt;
+ if (!tlvs->ipv4_int_reachs) tlvs->ipv4_int_reachs = list_new();
+ listnode_add (tlvs->ipv4_int_reachs, ipv4_reach);
+ value_len += 12;
+ pnt += 12;
+ }
+ }
+ else {
+ pnt += length;
+ }
+ break;
+
+ case IPV4_EXT_REACHABILITY:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | 0 | I/E | Default Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Delay Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Expense Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | S | I/E | Error Metric | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | ip address | 4
+ * +---------------------------------------------------------------+
+ * | address mask | 4
+ * +---------------------------------------------------------------+
+ * : :
+ */
+ *found |= TLVFLAG_TE_IPV4_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IPv4 external Reachability length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) {
+ while (length > value_len) {
+ ipv4_reach = (struct ipv4_reachability*)pnt;
+ if (!tlvs->ipv4_ext_reachs) tlvs->ipv4_ext_reachs = list_new();
+ listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach);
+ value_len += 12;
+ pnt += 12;
+ }
+ }
+ else {
+ pnt += length;
+ }
+ break;
+
+ case TE_IPV4_REACHABILITY:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | TE Metric | 4
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | U/D | sTLV? | Prefix Mask Len | 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Prefix | 0-4
+ * +---------------------------------------------------------------+
+ * | sub tlvs |
+ * +---------------------------------------------------------------+
+ * : :
+ */
+ *found |= TLVFLAG_TE_IPV4_REACHABILITY;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IPv4 extended Reachability length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) {
+ while (length > value_len) {
+ te_ipv4_reach = (struct te_ipv4_reachability*)pnt;
+ if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new();
+ listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach);
+ /* this trickery is permitable since no subtlvs are defined */
+ value_len += 5 + ((te_ipv4_reach->control & 0x3F) ?
+ ((((te_ipv4_reach->control & 0x3F)-1)>>3)+1) : 0);
+ pnt += 5 + ((te_ipv4_reach->control & 0x3F) ?
+ ((((te_ipv4_reach->control & 0x3F)-1)>>3)+1) : 0);
+ }
+ }
+ else {
+ pnt += length;
+ }
+ break;
+
+#ifdef HAVE_IPV6
+ case IPV6_ADDR:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * + IP version 6 address + 16
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * : :
+ */
+ *found |= TLVFLAG_IPV6_ADDR;
+#ifdef EXTREME_TLV_DEBUG
+ zlog_info ("ISIS-TLV (%s): IPv6 Address length %d",
+ areatag,
+ length);
+#endif /* EXTREME_TLV_DEBUG */
+ if (*expected & TLVFLAG_IPV6_ADDR) {
+ while (length > value_len) {
+ ipv6_addr = (struct in6_addr*)pnt;
+ if (!tlvs->ipv6_addrs) tlvs->ipv6_addrs = list_new();
+ listnode_add (tlvs->ipv6_addrs, ipv6_addr);
+ value_len += 16;
+ pnt += 16;
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+
+ case IPV6_REACHABILITY:
+ /* +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Default Metric | 4
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | Control Informantion |
+ * +---------------------------------------------------------------+
+ * | IPv6 Prefix Length |--+
+ * +---------------------------------------------------------------+ |
+ * | IPv6 Prefix |<-+
+ * +---------------------------------------------------------------+
+ */
+ *found |= TLVFLAG_IPV6_REACHABILITY;
+ if (*expected & TLVFLAG_IPV6_REACHABILITY) {
+ while (length > value_len) {
+ ipv6_reach = (struct ipv6_reachability*)pnt;
+ prefix_octets = ((ipv6_reach->prefix_len + 7) / 8);
+ value_len += prefix_octets + 6;
+ pnt += prefix_octets + 6;
+ /* FIXME: sub-tlvs */
+ if (!tlvs->ipv6_reachs) tlvs->ipv6_reachs = list_new();
+ listnode_add (tlvs->ipv6_reachs, ipv6_reach);
+ }
+ } else {
+ pnt += length;
+ }
+ break;
+#endif /* HAVE_IPV6 */
+
+ case WAY3_HELLO:
+ /* +---------------------------------------------------------------+
+ * | Adjacency state | 1
+ * +---------------------------------------------------------------+
+ * | Extended Local Circuit ID | 4
+ * +---------------------------------------------------------------+
+ * | Neighbor System ID (If known) | 0-8
+ * (probably 6)
+ * +---------------------------------------------------------------+
+ * | Neighbor Local Circuit ID (If known) | 4
+ * +---------------------------------------------------------------+
+ */
+ *found |= TLVFLAG_3WAY_HELLO;
+ if (*expected & TLVFLAG_3WAY_HELLO) {
+ while (length > value_len) {
+ /* FIXME: make this work */
+/* Adjacency State (one octet):
+ 0 = Up
+ 1 = Initializing
+ 2 = Down
+ Extended Local Circuit ID (four octets)
+ Neighbor System ID if known (zero to eight octets)
+ Neighbor Extended Local Circuit ID (four octets, if Neighbor
+ System ID is present) */
+ pnt += length;
+ }
+ } else {
+ pnt += length;
+ }
+
+ break;
+
+ default:
+ zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d",
+ areatag,
+ type,
+ length);
+
+ retval = ISIS_WARNING;
+ pnt += length;
+ break;
+ }
+ }
+
+ return retval;
+}
+
+int
+add_tlv (u_char tag, u_char len, u_char *value, struct stream *stream)
+{
+
+ if (STREAM_SIZE (stream) - stream_get_putp (stream) < len + 2) {
+ zlog_warn ("No room for TLV of type %d", tag);
+ return ISIS_WARNING;
+ }
+
+ stream_putc (stream, tag); /* TAG */
+ stream_putc (stream, len); /* LENGTH */
+ stream_put (stream, value, (int)len); /* VALUE */
+
+#ifdef EXTREME_DEBUG
+ zlog_info ("Added TLV %d len %d", tag, len);
+#endif /* EXTREME DEBUG */
+ return ISIS_OK;
+}
+
+
+int
+tlv_add_area_addrs (struct list *area_addrs, struct stream *stream)
+{
+ struct listnode *node;
+ struct area_addr *area_addr;
+
+ u_char value [255];
+ u_char *pos = value;
+
+ for (node = listhead (area_addrs); node; nextnode (node)) {
+ area_addr = getdata (node);
+ if (pos - value + area_addr->addr_len > 255)
+ goto err;
+ *pos = area_addr->addr_len;
+ pos ++;
+ memcpy (pos, area_addr->area_addr, (int)area_addr->addr_len);
+ pos += area_addr->addr_len;
+ }
+
+ return add_tlv (AREA_ADDRESSES, pos - value, value, stream);
+
+ err:
+ zlog_warn ("tlv_add_area_addrs(): TLV longer than 255");
+ return ISIS_WARNING;
+}
+
+int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream)
+{
+ struct listnode *node;
+ struct is_neigh *is_neigh;
+ u_char value [255];
+ u_char *pos = value;
+ int retval;
+
+ *pos = 0; /*is_neigh->virtual; */
+ pos ++;
+
+ for (node = listhead (is_neighs); node; nextnode (node)) {
+ is_neigh = getdata (node);
+ if (pos - value + IS_NEIGHBOURS_LEN > 255) {
+ retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ *pos = is_neigh->metrics.metric_default;
+ pos ++;
+ *pos = is_neigh->metrics.metric_delay;
+ pos ++;
+ *pos = is_neigh->metrics.metric_expense;
+ pos ++;
+ *pos = is_neigh->metrics.metric_error;
+ pos ++;
+ memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
+ pos += ISIS_SYS_ID_LEN + 1;
+ }
+
+ return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
+}
+
+
+int
+tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream)
+{
+ struct listnode *node;
+ u_char *snpa;
+ u_char value [255];
+ u_char *pos = value;
+ int retval;
+
+ for (node = listhead (lan_neighs); node; nextnode (node)) {
+ snpa = getdata (node);
+ if (pos - value + ETH_ALEN > 255) {
+ retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ memcpy (pos, snpa, ETH_ALEN);
+ pos += ETH_ALEN;
+ }
+
+ return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream);
+}
+
+
+/*
+ u_char value[255];
+ u_char *pos = value;
+
+ if (circuit->ip_router) {
+ *pos = (u_char)NLPID_IP;
+ pos ++;
+ }
+ if (circuit->ipv6_router) {
+ *pos = (u_char)NLPID_IPV6;
+ pos ++;
+ }
+*/
+
+int
+tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)
+{
+
+ return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count,
+ nlpids->nlpids, stream);
+}
+
+int tlv_add_authinfo (char auth_type, char auth_len, char *auth_value,
+ struct stream *stream)
+{
+ u_char value[255];
+ u_char *pos = value;
+ pos++;
+ memcpy (pos, auth_value, auth_len);
+
+ return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
+}
+
+int
+tlv_add_checksum (struct checksum *checksum, struct stream *stream)
+{
+ u_char value[255];
+ u_char *pos = value;
+ return add_tlv (CHECKSUM, pos - value,
+ value, stream);
+}
+
+int
+tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream)
+{
+ struct listnode *node;
+ struct prefix_ipv4 *ipv4;
+ u_char value[255];
+ u_char *pos = value;
+ int retval;
+
+ for (node = listhead (ip_addrs); node; nextnode (node)) {
+ ipv4 = getdata (node);
+ if (pos - value + IPV4_MAX_BYTELEN > 255) {
+ retval = add_tlv (IPV4_ADDR, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ *(u_int32_t*)pos = ipv4->prefix.s_addr;
+ pos += IPV4_MAX_BYTELEN;
+ }
+
+ return add_tlv (IPV4_ADDR, pos - value, value, stream);
+}
+
+int
+tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream)
+{
+ return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name, stream);
+}
+
+int
+tlv_add_lsp_entries (struct list *lsps, struct stream *stream)
+{
+ struct listnode *node;
+ struct isis_lsp *lsp;
+ u_char value [255];
+ u_char *pos = value;
+ int retval;
+
+ for (node = listhead (lsps); node; nextnode (node)) {
+ lsp = getdata (node);
+ if (pos - value + LSP_ENTRIES_LEN > 255) {
+ retval = add_tlv (LSP_ENTRIES, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ *((u_int16_t*)pos) = lsp->lsp_header->rem_lifetime;
+ pos += 2;
+ memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
+ pos += ISIS_SYS_ID_LEN + 2;
+ *((u_int32_t*)pos) = lsp->lsp_header->seq_num;
+ pos += 4;
+ *((u_int16_t*)pos) = lsp->lsp_header->checksum;
+ pos += 2;
+ }
+
+ return add_tlv (LSP_ENTRIES, pos - value, value, stream);
+}
+
+int
+tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)
+{
+ struct listnode *node;
+ struct ipv4_reachability *reach;
+ u_char value [255];
+ u_char *pos = value;
+ int retval;
+
+ for (node = listhead (ipv4_reachs); node; nextnode (node)) {
+ reach = getdata (node);
+ if (pos - value + IPV4_REACH_LEN > 255) {
+ retval = add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ *pos = reach->metrics.metric_default;
+ pos ++;
+ *pos = reach->metrics.metric_delay;
+ pos ++;
+ *pos = reach->metrics.metric_expense;
+ pos ++;
+ *pos = reach->metrics.metric_error;
+ pos ++;
+ *(u_int32_t*)pos = reach->prefix.s_addr;
+ pos += IPV4_MAX_BYTELEN;
+ *(u_int32_t*)pos = reach->mask.s_addr;
+ pos += IPV4_MAX_BYTELEN;
+ }
+
+
+ return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
+}
+
+#ifdef HAVE_IPV6
+int
+tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream)
+{
+ struct listnode *node;
+ struct prefix_ipv6 *ipv6;
+ u_char value[255];
+ u_char *pos = value;
+ int retval;
+
+ for (node = listhead (ipv6_addrs); node; nextnode (node)) {
+ ipv6 = getdata (node);
+ if (pos - value + IPV6_MAX_BYTELEN > 255) {
+ retval = add_tlv (IPV6_ADDR, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
+ pos += IPV6_MAX_BYTELEN;
+ }
+
+ return add_tlv (IPV6_ADDR, pos - value, value, stream);
+}
+
+int
+tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream)
+{
+ struct listnode *node;
+ struct ipv6_reachability *ip6reach;
+ u_char value[255];
+ u_char *pos = value;
+ int retval, prefix_octets;
+
+ for (node = listhead (ipv6_reachs); node; nextnode (node)) {
+ ip6reach = getdata (node);
+ if (pos - value + IPV6_MAX_BYTELEN + 6 > 255) {
+ retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
+ if (retval != ISIS_OK)
+ return retval;
+ pos = value;
+ }
+ *(uint32_t*)pos = ip6reach->metric;
+ pos += 4;
+ *pos = ip6reach->control_info;
+ pos++;
+ prefix_octets = ((ip6reach->prefix_len + 7) / 8);
+ *pos = ip6reach->prefix_len;
+ pos++;
+ memcpy (pos, ip6reach->prefix, prefix_octets);
+ pos += prefix_octets;
+ }
+
+ return add_tlv (IPV6_REACHABILITY, pos - value, value, stream);
+}
+#endif /* HAVE_IPV6 */
+
+int
+tlv_add_padding (struct stream *stream)
+{
+ unsigned long putp, endp;
+ int fullpads, i, left;
+
+ /*
+ * How many times can we add full padding ?
+ */
+ fullpads = (STREAM_SIZE(stream) - stream_get_endp (stream)) / 257;
+ for (i = 0; i < fullpads; i ++) {
+ if (!stream_putc (stream, (u_char)PADDING)) /* TAG */
+ goto err;
+ if (!stream_putc (stream, (u_char)255)) /* LENGHT */
+ goto err;
+ endp = stream_get_endp (stream);
+ putp = stream_get_putp (stream);
+ if (putp != endp)
+ zlog_warn ("tvl_add_padding endp %ld while putp %ld", endp, putp);
+ stream_set_putp (stream, putp + 255); /* VALUE */
+ stream->endp = stream->putp;
+ }
+
+ left = STREAM_SIZE(stream) - stream_get_putp (stream);
+
+ if (left < 2)
+ return ISIS_OK;
+
+ if (left == 2) {
+ stream_putc (stream, PADDING);
+ stream_putc (stream, 0);
+ return ISIS_OK;
+ }
+
+ stream_putc (stream, PADDING);
+ stream_putc (stream, left - 2);
+ stream_set_putp (stream, stream_get_putp (stream) + left - 2);
+ stream->endp = stream->putp;
+
+ return ISIS_OK;
+
+ err:
+ zlog_warn ("tlv_add_padding(): no room for tlv");
+ return ISIS_WARNING;
+}
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
new file mode 100644
index 00000000..79c0c46f
--- /dev/null
+++ b/isisd/isis_tlv.h
@@ -0,0 +1,268 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_tlv.h
+ * IS-IS TLV related routines
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_TLV_H
+#define _ZEBRA_ISIS_TLV_H
+
+/*
+ * Structures found in TLV's.
+ * this header is fully complient with
+ * draft-ietf-isis-wg-tlv-codepoints-02.txt
+ 1. TLV Codepoints reserved
+ ____________________________________________________
+ Name Value IIH LSP SNP Status
+ ____________________________________________________
+
+ Area Addresses 1 y y n ISO 10589
+ IIS Neighbors 2 n y n ISO 10589
+ ES Neighbors 3 n y n ISO 10589
+ Part. DIS 4 n y n ISO 10589
+ Prefix Neighbors 5 n y n ISO 10589
+ IIS Neighbors 6 y n n ISO 10589
+ Padding 8 y n n ISO 10589
+ LSP Entries 9 n n y ISO 10589
+ Authentication 10 y y y ISO 10589
+ Opt. Checksum 12 y n y IETF-draft
+ LSPBufferSize 14 n y n ISO 10589 Rev 2 Draft
+ TE IIS Neigh. 22 n y n IETF-draft
+ DECnet Phase IV 42 y n n DEC (ancient)
+ IP Int. Reach 128 n y n RFC 1195
+ Prot. Supported 129 y y n RFC 1195
+ IP Ext. Address 130 n y n RFC 1195
+ IDRPI 131 n y y RFC 1195
+ IP Intf. Address 132 y y n RFC 1195
+ Illegal 133 n n n RFC 1195 (not used)
+ Router ID 134 n y n IETF-draft
+ TE IP. Reach 135 n y n IETF-draft
+ Dynamic Name 137 n y n RFC 2763
+ Nortel Proprietary 176 n y n
+ Nortel Proprietary 177 n y n
+ Restart TLV 211 y n n IETF-draft
+ MT-ISN 222 n y n IETF-draft
+ M-Topologies 229 y y n IETF-draft
+ IPv6 Intf. Addr. 232 y y n IETF-draft
+ MT IP. Reach 235 n y n IETF-draft
+ IPv6 IP. Reach 236 n y n IETF-draft
+ MT IPv6 IP. Reach 237 n y n IETF-draft
+ P2P Adjacency State 240 y n n IETF-draft
+
+ */
+
+#define AREA_ADDRESSES 1
+#define IS_NEIGHBOURS 2
+#define ES_NEIGHBOURS 3
+#define PARTITION_DESIG_LEVEL2_IS 4
+#define PREFIX_NEIGHBOURS 5
+#define LAN_NEIGHBOURS 6
+#define PADDING 8
+#define LSP_ENTRIES 9
+#define AUTH_INFO 10
+#define CHECKSUM 12
+#define TE_IS_NEIGHBOURS 22
+#define IPV4_INT_REACHABILITY 128
+#define IPV4_EXT_REACHABILITY 130
+#define PROTOCOLS_SUPPORTED 129
+#define IDRP_INFO 131
+#define IPV4_ADDR 132
+#define TE_ROUTER_ID 134
+#define TE_IPV4_REACHABILITY 135
+#define DYNAMIC_HOSTNAME 137
+#define IPV6_REACHABILITY 236
+#define IPV6_ADDR 232
+#define WAY3_HELLO 240
+
+#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
+
+/* struct for neighbor */
+struct is_neigh{
+ struct metric metrics;
+ u_char neigh_id[ISIS_SYS_ID_LEN + 1];
+};
+
+/* struct for te is neighbor */
+struct te_is_neigh{
+ u_char neigh_id[ISIS_SYS_ID_LEN + 1];
+ u_char te_metric[3];
+ u_char sub_tlvs_length;
+};
+
+/* struct for es neighbors */
+struct es_neigh{
+ struct metric metrics;
+ /* approximate position of first, we use the
+ * length ((uchar*)metric-1) to know all */
+ u_char first_es_neigh[ISIS_SYS_ID_LEN];
+
+};
+
+struct partition_desig_level2_is{
+ struct list *isis_system_ids;
+};
+
+/* struct for lan neighbors */
+struct lan_neigh{
+ u_char LAN_addr[6];
+};
+
+/* struct for LSP entry */
+struct lsp_entry {
+ u_int16_t rem_lifetime;
+ u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ u_int32_t seq_num;
+ u_int16_t checksum;
+} __attribute__((packed));
+
+/* struct for checksum */
+struct checksum {
+ u_int16_t checksum;
+};
+
+/* ipv4 reachability */
+struct ipv4_reachability {
+ struct metric metrics;
+ struct in_addr prefix;
+ struct in_addr mask;
+};
+
+/* te router id */
+struct te_router_id {
+ struct in_addr id;
+};
+
+/* te ipv4 reachability */
+struct te_ipv4_reachability {
+ u_int32_t te_metric;
+ u_char control;
+ u_char prefix_start; /* since this is variable length by nature it only */
+}; /* points to an approximate location */
+
+
+
+struct idrp_info {
+ u_char len;
+ u_char *value;
+};
+
+#ifdef HAVE_IPV6
+struct ipv6_reachability {
+ u_int32_t metric;
+ u_char control_info;
+ u_char prefix_len;
+ u_char prefix[16];
+};
+#endif /* HAVE_IPV6 */
+
+/* bits in control_info */
+#define CTRL_INFO_DIRECTION 0x80
+#define DIRECTION_UP 0
+#define DIRECTION_DOWN 1
+#define CTRL_INFO_DISTRIBUTION 0x40
+#define DISTRIBUTION_INTERNAL 0
+#define DISTRIBUTION_EXTERNAL 1
+#define CTRL_INFO_SUBTLVS 0x20
+
+/*
+ * Pointer to each tlv type, filled by parse_tlvs()
+ */
+struct tlvs {
+ struct list *area_addrs;
+ struct list *is_neighs;
+ struct list *te_is_neighs;
+ struct list *es_neighs;
+ struct list *lsp_entries;
+ struct list *prefix_neighs;
+ struct list *lan_neighs;
+ struct checksum *checksum;
+ struct nlpids *nlpids;
+ struct list *ipv4_addrs;
+ struct list *ipv4_int_reachs;
+ struct list *ipv4_ext_reachs;
+ struct list *te_ipv4_reachs;
+ struct hostname *hostname;
+ struct te_router_id *router_id;
+#ifdef HAVE_IPV6
+ struct list *ipv6_addrs;
+ struct list *ipv6_reachs;
+#endif
+ struct isis_passwd auth_info;
+};
+
+/*
+ * Own definitions - used to bitmask found and expected
+ */
+
+#define TLVFLAG_AREA_ADDRS (1<<0)
+#define TLVFLAG_IS_NEIGHS (1<<1)
+#define TLVFLAG_ES_NEIGHS (1<<2)
+#define TLVFLAG_PARTITION_DESIG_LEVEL2_IS (1<<3)
+#define TLVFLAG_PREFIX_NEIGHS (1<<4)
+#define TLVFLAG_LAN_NEIGHS (1<<5)
+#define TLVFLAG_LSP_ENTRIES (1<<6)
+#define TLVFLAG_PADDING (1<<7)
+#define TLVFLAG_AUTH_INFO (1<<8)
+#define TLVFLAG_IPV4_INT_REACHABILITY (1<<9)
+#define TLVFLAG_NLPID (1<<10)
+#define TLVFLAG_IPV4_EXT_REACHABILITY (1<<11)
+#define TLVFLAG_IPV4_ADDR (1<<12)
+#define TLVFLAG_DYN_HOSTNAME (1<<13)
+#define TLVFLAG_IPV6_ADDR (1<<14)
+#define TLVFLAG_IPV6_REACHABILITY (1<<15)
+#define TLVFLAG_TE_IS_NEIGHS (1<<16)
+#define TLVFLAG_TE_IPV4_REACHABILITY (1<<17)
+#define TLVFLAG_3WAY_HELLO (1<<18)
+#define TLVFLAG_TE_ROUTER_ID (1<<19)
+#define TLVFLAG_CHECKSUM (1<<20)
+
+void init_tlvs (struct tlvs *tlvs, uint32_t expected);
+void free_tlvs (struct tlvs *tlvs);
+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 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_lan_neighs (struct list *lan_neighs, struct stream *stream);
+int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
+int tlv_add_checksum (struct checksum *checksum,
+ struct stream *stream);
+int tlv_add_authinfo (char auth_type, char authlen, char *auth_value,
+ struct stream *stream);
+int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream);
+int tlv_add_dynamic_hostname (struct hostname *hostname,struct stream *stream);
+int tlv_add_lsp_entries (struct list *lsps, struct stream *stream);
+int tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream);
+#ifdef HAVE_IPV6
+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_padding (struct stream *stream);
+
+#endif /* _ZEBRA_ISIS_TLV_H */
+
+
+
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
new file mode 100644
index 00000000..d9179f91
--- /dev/null
+++ b/isisd/isis_zebra.c
@@ -0,0 +1,592 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_zebra.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>
+
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "log.h"
+#include "if.h"
+#include "network.h"
+#include "prefix.h"
+#include "zclient.h"
+#include "stream.h"
+#include "linklist.h"
+
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_route.h"
+#include "isisd/isis_zebra.h"
+
+struct zclient *zclient = NULL;
+
+extern struct thread_master *master;
+
+int
+isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_add_read (zclient->ibuf);
+
+
+ zlog_info ("Zebra I/F add: %s index %d flags %ld metric %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+ if (if_is_up (ifp))
+ isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
+
+ return 0;
+}
+
+int
+isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
+{
+ struct interface *ifp;
+ struct stream *s;
+
+ s = zclient->ibuf;
+ ifp = zebra_interface_state_read (s);
+
+ if (!ifp)
+ return 0;
+
+ if (if_is_up (ifp))
+ zlog_warn ("Zebra: got delete of %s, but interface is still up",
+ ifp->name);
+
+ zlog_info ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d",
+ ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+ if_delete (ifp);
+
+ isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
+
+ return 0;
+}
+
+struct interface *
+zebra_interface_if_lookup (struct stream *s)
+{
+ struct interface *ifp;
+ u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+ /* Read interface name. */
+ stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+ /* Lookup this by interface index. */
+ ifp = if_lookup_by_name (ifname_tmp);
+
+ /* If such interface does not exist, indicate an error */
+ if (!ifp)
+ return NULL;
+
+ return ifp;
+}
+
+void
+zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
+{
+ /* Read interface's index. */
+ ifp->ifindex = stream_getl (s);
+
+ /* Read interface's value. */
+ ifp->flags = stream_getl (s);
+ ifp->metric = stream_getl (s);
+ ifp->mtu = stream_getl (s);
+ ifp->bandwidth = stream_getl (s);
+}
+
+int
+isis_zebra_if_state_up (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_if_lookup (zclient->ibuf);
+
+ if (!ifp)
+ return 0;
+
+ if (if_is_up (ifp)) {
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+ isis_circuit_update_params (circuit_scan_by_ifp (ifp), ifp);
+ return 0;
+ }
+
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+ isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
+
+ return 0;
+}
+
+
+int
+isis_zebra_if_state_down (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_if_lookup (zclient->ibuf);
+
+ if (ifp == NULL)
+ return 0;
+
+ if (if_is_up (ifp)) {
+ zebra_interface_if_set_value (zclient->ibuf, ifp);
+ isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
+ }
+
+ return 0;
+}
+
+int
+isis_zebra_if_address_add (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct connected *c;
+ struct prefix *p;
+ u_char buf[BUFSIZ];
+
+ c = zebra_interface_address_add_read (zclient->ibuf);
+
+ if (c == NULL)
+ return 0;
+
+ p = c->address;
+
+ prefix2str (p, buf, BUFSIZ);
+#ifdef EXTREME_DEBUG
+ if (p->family == AF_INET)
+ zlog_info ("connected IP address %s", buf);
+#ifdef HAVE_IPV6
+ if (p->family == AF_INET6)
+ zlog_info ("connected IPv6 address %s", buf);
+#endif /* HAVE_IPV6 */
+#endif /* EXTREME_DEBUG */
+ isis_circuit_add_addr (circuit_scan_by_ifp (c->ifp), c);
+
+ return 0;
+}
+
+int
+isis_zebra_if_address_del (int command, struct zclient *client,
+ zebra_size_t length)
+{
+ struct connected *c;
+ struct interface *ifp;
+
+ c = zebra_interface_address_delete_read (zclient->ibuf);
+
+ if (c == NULL)
+ return 0;
+
+ ifp = c->ifp;
+
+ connected_free (c);
+
+ isis_circuit_del_addr (circuit_scan_by_ifp (ifp), c);
+
+ return 0;
+}
+
+void
+isis_zebra_route_add_ipv4 (struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ u_char message, flags;
+ int psize;
+ struct stream *stream;
+ struct isis_nexthop *nexthop;
+ struct listnode *node;
+
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ return;
+
+ if (zclient->redist[ZEBRA_ROUTE_ISIS]) {
+ message = 0;
+ flags = 0;
+
+ SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (message, ZAPI_MESSAGE_METRIC);
+ SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
+
+ stream = zclient->obuf;
+ stream_reset (stream);
+ /* Length place holder. */
+ stream_putw (stream, 0);
+ /* command */
+ stream_putc (stream, ZEBRA_IPV4_ROUTE_ADD);
+ /* type */
+ stream_putc (stream, ZEBRA_ROUTE_ISIS);
+ /* flags */
+ stream_putc (stream, flags);
+ /* message */
+ stream_putc (stream, message);
+ /* prefix information */
+ psize = PSIZE (prefix->prefixlen);
+ stream_putc (stream, prefix->prefixlen);
+ stream_write (stream, (u_char *)&prefix->u.prefix4, psize);
+
+ stream_putc (stream, listcount (route_info->nexthops));
+
+ /* Nexthop, ifindex, distance and metric information */
+ for (node = listhead (route_info->nexthops); node; nextnode (node)) {
+ nexthop = getdata (node);
+ /* FIXME: can it be ? */
+ if (nexthop->ip.s_addr != INADDR_ANY) {
+ stream_putc (stream, ZEBRA_NEXTHOP_IPV4);
+ stream_put_in_addr (stream, &nexthop->ip);
+ } else {
+ stream_putc (stream, ZEBRA_NEXTHOP_IFINDEX);
+ stream_putl (stream, nexthop->ifindex);
+ }
+ }
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+ stream_putc (stream, route_info->depth);
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+ stream_putl (stream, route_info->cost);
+
+ stream_putw_at (stream, 0, stream_get_endp (stream));
+ writen (zclient->sock, stream->data, stream_get_endp (stream));
+ }
+}
+
+void
+isis_zebra_route_del_ipv4 (struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ struct zapi_ipv4 api;
+ struct prefix_ipv4 prefix4;
+
+ if (zclient->redist[ZEBRA_ROUTE_ISIS]) {
+ api.type = ZEBRA_ROUTE_ISIS;
+ api.flags = 0;
+ api.message = 0;
+ prefix4.family = AF_INET;
+ prefix4.prefixlen = prefix->prefixlen;
+ prefix4.prefix = prefix->u.prefix4;
+ zapi_ipv4_delete (zclient, &prefix4, &api);
+ }
+
+ return;
+}
+
+#ifdef HAVE_IPV6
+void
+isis_zebra_route_add_ipv6 (struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ struct zapi_ipv6 api;
+ struct in6_addr **nexthop_list;
+ unsigned int *ifindex_list;
+ struct isis_nexthop6 *nexthop6;
+ int i, size;
+ struct listnode *node;
+ struct prefix_ipv6 prefix6;
+
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ return;
+
+ api.type = ZEBRA_ROUTE_ISIS;
+ api.flags = 0;
+ api.message = 0;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+ SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = route_info->cost;
+#if 0
+ SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = route_info->depth;
+#endif
+ api.nexthop_num = listcount (route_info->nexthops6);
+ api.ifindex_num = listcount (route_info->nexthops6);
+
+ /* allocate memory for nexthop_list */
+ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6);
+ nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size);
+ if (!nexthop_list) {
+ zlog_err ("isis_zebra_add_route_ipv6: out of memory!");
+ return;
+ }
+
+ /* allocate memory for ifindex_list */
+ size = sizeof (unsigned int) * listcount (route_info->nexthops6);
+ ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size);
+ if (!ifindex_list) {
+ zlog_err ("isis_zebra_add_route_ipv6: out of memory!");
+ XFREE (MTYPE_ISIS_TMP, nexthop_list);
+ return;
+ }
+
+ /* for each nexthop */
+ i = 0;
+ for (node = listhead (route_info->nexthops6); node; nextnode (node)) {
+ nexthop6 = getdata (node);
+
+ if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) &&
+ !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) {
+ api.nexthop_num--;
+ api.ifindex_num--;
+ continue;
+ }
+
+ nexthop_list[i] = &nexthop6->ip6;
+ ifindex_list[i] = nexthop6->ifindex;
+ i++;
+ }
+
+ api.nexthop = nexthop_list;
+ api.ifindex = ifindex_list;
+
+ if (api.nexthop_num && api.ifindex_num) {
+ prefix6.family = AF_INET6;
+ prefix6.prefixlen = prefix->prefixlen;
+ memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr));
+ zapi_ipv6_add (zclient, &prefix6, &api);
+ SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ }
+
+ XFREE (MTYPE_ISIS_TMP, nexthop_list);
+ XFREE (MTYPE_ISIS_TMP, ifindex_list);
+
+ return;
+}
+
+void
+isis_zebra_route_del_ipv6 (struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ struct zapi_ipv6 api;
+ struct in6_addr **nexthop_list;
+ unsigned int *ifindex_list;
+ struct isis_nexthop6 *nexthop6;
+ int i, size;
+ struct listnode *node;
+ struct prefix_ipv6 prefix6;
+
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ return;
+
+ api.type = ZEBRA_ROUTE_ISIS;
+ api.flags = 0;
+ api.message = 0;
+ SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+ api.nexthop_num = listcount (route_info->nexthops6);
+ api.ifindex_num = listcount (route_info->nexthops6);
+
+ /* allocate memory for nexthop_list */
+ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6);
+ nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size);
+ if (!nexthop_list) {
+ zlog_err ("isis_zebra_route_del_ipv6: out of memory!");
+ return;
+ }
+
+ /* allocate memory for ifindex_list */
+ size = sizeof (unsigned int) * listcount (route_info->nexthops6);
+ ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size);
+ if (!ifindex_list) {
+ zlog_err ("isis_zebra_route_del_ipv6: out of memory!");
+ XFREE (MTYPE_ISIS_TMP, nexthop_list);
+ return;
+ }
+
+ /* for each nexthop */
+ i = 0;
+ for (node = listhead (route_info->nexthops6); node; nextnode (node)) {
+ nexthop6 = getdata (node);
+
+ if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) &&
+ !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) {
+ api.nexthop_num--;
+ api.ifindex_num--;
+ continue;
+ }
+
+ nexthop_list[i] = &nexthop6->ip6;
+ ifindex_list[i] = nexthop6->ifindex;
+ i++;
+ }
+
+ api.nexthop = nexthop_list;
+ api.ifindex = ifindex_list;
+
+ if (api.nexthop_num && api.ifindex_num) {
+ prefix6.family = AF_INET6;
+ prefix6.prefixlen = prefix->prefixlen;
+ memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr));
+ zapi_ipv6_delete (zclient, &prefix6, &api);
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ }
+
+ XFREE (MTYPE_ISIS_TMP, nexthop_list);
+ XFREE (MTYPE_ISIS_TMP, ifindex_list);
+}
+
+
+#endif /* HAVE_IPV6 */
+
+
+
+void
+isis_zebra_route_update (struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ if (zclient->sock < 0)
+ return;
+
+ if (!zclient->redist[ZEBRA_ROUTE_ISIS])
+ return;
+
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
+ if (prefix->family == AF_INET)
+ isis_zebra_route_add_ipv4 (prefix, route_info);
+#ifdef HAVE_IPV6
+ else if (prefix->family == AF_INET6)
+ isis_zebra_route_add_ipv6 (prefix, route_info);
+#endif /* HAVE_IPV6 */
+ } else {
+ if (prefix->family == AF_INET)
+ isis_zebra_route_del_ipv4 (prefix, route_info);
+#ifdef HAVE_IPV6
+ else if (prefix->family == AF_INET6)
+ isis_zebra_route_del_ipv6 (prefix, route_info);
+#endif /* HAVE_IPV6 */
+ }
+ return;
+}
+
+
+int
+isis_zebra_read_ipv4 (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct stream *stream;
+ struct zapi_ipv4 api;
+ struct prefix_ipv4 p;
+ unsigned long ifindex;
+ struct in_addr nexthop;
+
+ stream = zclient->ibuf;
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ ifindex = 0;
+
+ api.type = stream_getc (stream);
+ api.flags = stream_getc (stream);
+ api.message = stream_getc (stream);
+
+ p.family = AF_INET;
+ p.prefixlen = stream_getc (stream);
+ stream_get (&p.prefix, stream, PSIZE (p.prefixlen));
+
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
+ api.nexthop_num = stream_getc (stream);
+ nexthop.s_addr = stream_get_ipv4 (stream);
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
+ api.ifindex_num = stream_getc (stream);
+ ifindex = stream_getl (stream);
+ }
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+ api.distance = stream_getc (stream);
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+ api.metric = stream_getl (stream);
+ else
+ api.metric = 0;
+
+ if (command == ZEBRA_IPV4_ROUTE_ADD) {
+ zlog_info ("IPv4 Route add from Z");
+ }
+
+ return 0;
+}
+
+
+int
+isis_zebra_read_ipv6 (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+
+ return 0;
+}
+
+#define ISIS_TYPE_IS_REDISTRIBUTED(T) \
+T == ZEBRA_ROUTE_MAX ? zclient->default_information : zclient->redist[type]
+
+int
+isis_distribute_list_update (int routetype)
+{
+ return 0;
+}
+
+int
+isis_redistribute_default_set(int routetype, int metric_type, int metric_value)
+{
+ return 0;
+}
+
+
+void
+isis_zebra_init ()
+{
+
+ zclient = zclient_new ();
+ zclient_init (zclient, ZEBRA_ROUTE_ISIS);
+ zclient->interface_add = isis_zebra_if_add;
+ zclient->interface_delete = isis_zebra_if_del;
+ zclient->interface_up = isis_zebra_if_state_up;
+ zclient->interface_down = isis_zebra_if_state_down;
+ zclient->interface_address_add = isis_zebra_if_address_add;
+ zclient->interface_address_delete = isis_zebra_if_address_del;
+ zclient->ipv4_route_add = isis_zebra_read_ipv4;
+ zclient->ipv4_route_delete = isis_zebra_read_ipv4;
+#ifdef HAVE_IPV6
+ zclient->ipv6_route_add = isis_zebra_read_ipv6;
+ zclient->ipv6_route_delete = isis_zebra_read_ipv6;
+#endif /* HAVE_IPV6 */
+
+ return;
+}
+
+void
+isis_zebra_finish ()
+{
+
+ zclient_stop (zclient);
+ zclient_free (zclient);
+ zclient = (struct zclient *) NULL;
+
+ return;
+}
+
+
+
+
+
+
+
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
new file mode 100644
index 00000000..fabf7200
--- /dev/null
+++ b/isisd/isis_zebra.h
@@ -0,0 +1,33 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_zebra.h
+ *
+ * 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.
+ */
+#ifndef _ZEBRA_ISIS_ZEBRA_H
+#define _ZEBRA_ISIS_ZEBRA_H
+
+extern struct zclient *zclient;
+
+void isis_zebra_init (void);
+void isis_zebra_finish (void);
+void isis_zebra_route_update (struct prefix *prefix,
+ struct isis_route_info *route_info);
+int isis_distribute_list_update (int routetype);
+
+#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
new file mode 100644
index 00000000..8794a12c
--- /dev/null
+++ b/isisd/isisd.c
@@ -0,0 +1,1989 @@
+/*
+ * IS-IS Rout(e)ing protocol - isisd.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 <string.h>
+#include <zebra.h>
+#include <net/ethernet.h>
+
+#include "thread.h"
+#include "vty.h"
+#include "command.h"
+#include "log.h"
+#include "memory.h"
+#include "linklist.h"
+#include "if.h"
+#include "hash.h"
+#include "stream.h"
+#include "prefix.h"
+#include "table.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_dynhn.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_route.h"
+#include "isisd/isis_zebra.h"
+#include "isisd/isis_events.h"
+
+#ifdef TOPOLOGY_GENERATE
+#include "spgrid.h"
+u_char DEFAULT_TOPOLOGY_BASEIS[6] = {0xFE, 0xED, 0xFE, 0xED, 0x00, 0x00};
+#endif /* TOPOLOGY_GENERATE */
+
+
+struct isis *isis = NULL;
+struct thread_master *master;
+
+
+void
+isis_new (unsigned long process_id)
+{
+
+ isis = XMALLOC (MTYPE_ISIS, sizeof(struct isis));
+ bzero (isis, sizeof (struct isis));
+ /*
+ * Default values
+ */
+ isis->max_area_addrs = 3;
+
+ isis->process_id = process_id;
+ isis->area_list = list_new ();
+ isis->init_circ_list = list_new ();
+ isis->uptime = time (NULL);
+ isis->nexthops = list_new ();
+#ifdef HAVE_IPV6
+ isis->nexthops6 = list_new ();
+#endif /* HAVE_IPV6 */
+ /*
+ * uncomment the next line for full debugs
+ */
+ /* isis->debugs = 0xFFFF; */
+}
+
+struct isis_area *
+isis_area_create ()
+{
+
+ struct isis_area *area;
+
+ area = XMALLOC (MTYPE_ISIS_AREA, sizeof (struct isis_area));
+ memset (area, 0, sizeof (struct isis_area));
+
+ /*
+ * The first instance is level-1-2 rest are level-1, unless otherwise
+ * configured
+ */
+ if (listcount (isis->area_list) > 0)
+ area->is_type = IS_LEVEL_1;
+ else
+ area->is_type = IS_LEVEL_1_AND_2;
+ /*
+ * intialize the databases
+ */
+ area->lspdb[0] = lsp_db_init ();
+ area->lspdb[1] = lsp_db_init ();
+
+ spftree_area_init (area);
+ area->route_table = route_table_init ();
+#ifdef HAVE_IPV6
+ area->route_table6 = route_table_init ();
+#endif /* HAVE_IPV6 */
+ area->circuit_list = list_new ();
+ area->area_addrs = list_new ();
+ area->t_tick = thread_add_timer (master, lsp_tick, area, 1);
+ area->flags.maxindex = -1;
+ /*
+ * Default values
+ */
+ area->max_lsp_lifetime[0] = MAX_AGE; /* 1200 */
+ area->max_lsp_lifetime[1] = MAX_AGE; /* 1200 */
+ area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
+ area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
+ area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900 */
+ area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900 */
+ area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
+ area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
+ area->dynhostname = 1;
+ area->lsp_frag_threshold = 90;
+#ifdef TOPOLOGY_GENERATE
+ memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
+#endif /* TOPOLOGY_GENERATE */
+
+ /* FIXME: Think of a better way... */
+ area->min_bcast_mtu = 1497;
+
+ return area;
+}
+
+struct isis_area *
+isis_area_lookup (char *area_tag)
+{
+ struct isis_area *area;
+ struct listnode *node;
+
+ LIST_LOOP (isis->area_list, area, node)
+ if ((area->area_tag == NULL && area_tag == NULL) ||
+ (area->area_tag && area_tag && strcmp (area->area_tag, area_tag) == 0))
+ return area;
+
+ return NULL;
+}
+
+int
+isis_area_get (struct vty *vty, char *area_tag)
+{
+
+ struct isis_area *area;
+
+ area = isis_area_lookup (area_tag);
+
+ if (area) {
+ vty->node = ISIS_NODE;
+ vty->index = area;
+ return CMD_SUCCESS;
+ }
+
+ area = isis_area_create ();
+ area->area_tag = strdup (area_tag);
+ listnode_add (isis->area_list, area);
+
+ zlog_info ("new IS-IS area instance %s", area->area_tag);
+
+ vty->node = ISIS_NODE;
+ vty->index = area;
+
+ return CMD_SUCCESS;
+}
+
+int
+isis_area_destroy (struct vty *vty, char *area_tag)
+{
+
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ area = isis_area_lookup (area_tag);
+
+ if (area == NULL) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (area->circuit_list) {
+ node = listhead (area->circuit_list);
+ while (node) {
+ circuit = getdata (node);
+ nextnode (node);
+ isis_circuit_del (circuit);
+ }
+ list_delete (area->circuit_list);
+ }
+ listnode_delete (isis->area_list, area);
+ if (area->t_tick)
+ thread_cancel (area->t_tick);
+ if (area->t_remove_aged)
+ thread_cancel (area->t_remove_aged);
+ if (area->t_lsp_refresh[0])
+ thread_cancel (area->t_lsp_refresh[0]);
+ if (area->t_lsp_refresh[1])
+ thread_cancel (area->t_lsp_refresh[1]);
+
+ XFREE (MTYPE_ISIS_AREA, area);
+
+ return CMD_SUCCESS;
+}
+
+int
+area_net_title (struct vty *vty , char *net_title)
+{
+
+ struct isis_area *area;
+ struct area_addr *addr;
+ struct area_addr *addrp;
+ struct listnode *node;
+
+ u_char buff[255];
+ area = vty->index;
+
+ if (!area) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* We check that we are not over the maximal number of addresses */
+ if (listcount (area->area_addrs) >= isis->max_area_addrs) {
+ vty_out (vty, "Maximum of area addresses (%d) already reached %s",
+ isis->max_area_addrs, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ addr = XMALLOC (MTYPE_ISIS_AREA_ADDR, sizeof (struct area_addr));
+ addr->addr_len = dotformat2buff (buff, net_title);
+ memcpy (addr->area_addr, buff, addr->addr_len);
+#ifdef EXTREME_DEBUG
+ zlog_info ("added area address %s for area %s (address length %d)",
+ net_title, area->area_tag, addr->addr_len);
+#endif /* EXTREME_DEBUG */
+ if (addr->addr_len < 8 || addr->addr_len > 20) {
+ zlog_warn ("area address must be at least 8..20 octets long (%d)",
+ addr->addr_len);
+ XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+ return CMD_WARNING;
+ }
+
+ if (isis->sysid_set == 0) {
+ /*
+ * First area address - get the SystemID for this router
+ */
+ memcpy (isis->sysid, GETSYSID(addr, ISIS_SYS_ID_LEN), ISIS_SYS_ID_LEN);
+ isis->sysid_set = 1;
+ zlog_info ("Router has SystemID %s", sysid_print (isis->sysid));
+ } else {
+ /*
+ * Check that the SystemID portions match
+ */
+ if (memcmp (isis->sysid, GETSYSID(addr, ISIS_SYS_ID_LEN),
+ ISIS_SYS_ID_LEN)) {
+ vty_out (vty, "System ID must not change when defining additional area"
+ " addresses%s", VTY_NEWLINE);
+ XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+ return CMD_WARNING;
+ }
+
+ /* now we see that we don't already have this address */
+ LIST_LOOP (area->area_addrs, addrp, node) {
+ if ((addrp->addr_len+ ISIS_SYS_ID_LEN + 1) == (addr->addr_len)) {
+ if (!memcmp (addrp->area_addr, addr->area_addr,addr->addr_len)) {
+ XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+ return CMD_SUCCESS; /* silent fail */
+ }
+ }
+ }
+
+ }
+ /*
+ * Forget the systemID part of the address
+ */
+ addr->addr_len -= (ISIS_SYS_ID_LEN + 1);
+ listnode_add (area->area_addrs, addr);
+
+ /* only now we can safely generate our LSPs for this area */
+ if (listcount(area->area_addrs) > 0) {
+ lsp_l1_generate (area);
+ lsp_l2_generate (area);
+ }
+
+ return CMD_SUCCESS;
+}
+
+int
+area_clear_net_title (struct vty *vty, char *net_title)
+{
+ struct isis_area *area;
+ struct area_addr addr, *addrp = NULL;
+ struct listnode *node;
+ u_char buff[255];
+
+ area = vty->index;
+ if (!area) {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ addr.addr_len = dotformat2buff (buff, net_title);
+ if (addr.addr_len < 8 || addr.addr_len > 20) {
+ vty_out (vty, "Unsupported area address length %d, should be 8...20 %s",
+ addr.addr_len, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memcpy(addr.area_addr, buff, (int)addr.addr_len);
+
+ LIST_LOOP (area->area_addrs, addrp, node)
+ if (addrp->addr_len == addr.addr_len &&
+ !memcmp (addrp->area_addr, addr.area_addr, addr.addr_len))
+ break;
+
+ if (!addrp) {
+ vty_out (vty, "No area address %s for area %s %s", net_title,
+ area->area_tag, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ listnode_delete (area->area_addrs, addrp);
+
+ return CMD_SUCCESS;
+}
+
+
+/*
+ * 'show clns neighbors' command
+ */
+
+int
+show_clns_neigh (struct vty *vty, char detail)
+{
+ struct listnode *node_area, *node_circ;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct list *db;
+ int i;
+
+ if (!isis) {
+ vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ for (node_area = listhead (isis->area_list); node_area;
+ nextnode (node_area)) {
+ area = getdata (node_area);
+ vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE);
+
+ if (detail==ISIS_UI_LEVEL_BRIEF)
+ vty_out (vty, " System Id Interface L State "
+ "Holdtime SNPA%s", VTY_NEWLINE);
+
+ for (node_circ = listhead (area->circuit_list); node_circ;
+ nextnode (node_circ)) {
+ circuit = getdata (node_circ);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ for (i = 0; i < 2; i++) {
+ db = circuit->u.bc.adjdb[i];
+ if (db && db->count) {
+ if (detail == ISIS_UI_LEVEL_BRIEF)
+ isis_adjdb_iterate (db, (void (*) (struct isis_adjacency *,
+ void *))
+ isis_adj_print_vty, vty);
+ if (detail == ISIS_UI_LEVEL_DETAIL)
+ isis_adjdb_iterate (db, (void (*) (struct isis_adjacency *,
+ void *))
+ isis_adj_print_vty_detail, vty);
+ if (detail == ISIS_UI_LEVEL_EXTENSIVE)
+ isis_adjdb_iterate (db, (void (*) (struct isis_adjacency *,
+ void *))
+ isis_adj_print_vty_extensive, vty);
+ }
+ }
+ } else if (circuit->circ_type == CIRCUIT_T_P2P &&
+ circuit->u.p2p.neighbor) {
+ if (detail==ISIS_UI_LEVEL_BRIEF)
+ isis_adj_p2p_print_vty (circuit->u.p2p.neighbor, vty);
+ if (detail==ISIS_UI_LEVEL_DETAIL)
+ isis_adj_p2p_print_vty_detail (circuit->u.p2p.neighbor, vty);
+ if (detail==ISIS_UI_LEVEL_EXTENSIVE)
+ isis_adj_p2p_print_vty_extensive (circuit->u.p2p.neighbor, vty);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_clns_neighbors,
+ show_clns_neighbors_cmd,
+ "show clns neighbors",
+ SHOW_STR
+ "clns network information\n"
+ "CLNS neighbor adjacencies\n")
+{
+ return show_clns_neigh(vty, ISIS_UI_LEVEL_BRIEF);
+}
+
+ALIAS (show_clns_neighbors,
+ show_isis_neighbors_cmd,
+ "show isis neighbors",
+ SHOW_STR
+ "IS-IS network information\n"
+ "IS-IS neighbor adjacencies\n")
+
+DEFUN (show_clns_neighbors_detail,
+ show_clns_neighbors_detail_cmd,
+ "show clns neighbors detail",
+ SHOW_STR
+ "clns network information\n"
+ "CLNS neighbor adjacencies\n"
+ "show detailed information\n")
+{
+ return show_clns_neigh(vty, ISIS_UI_LEVEL_DETAIL);
+}
+
+ALIAS (show_clns_neighbors_detail,
+ show_isis_neighbors_detail_cmd,
+ "show isis neighbors detail",
+ SHOW_STR
+ "IS-IS network information\n"
+ "IS-IS neighbor adjacencies\n"
+ "show detailed information\n")
+
+/*
+ * 'isis debug', 'show debugging'
+ */
+
+void
+print_debug (struct vty *vty, int flags, int onoff)
+{
+ char onoffs[4];
+ if (onoff)
+ strcpy (onoffs,"on");
+ else
+ strcpy (onoffs,"off");
+
+ if (flags & DEBUG_ADJ_PACKETS)
+ vty_out (vty,"IS-IS Adjacency related packets debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_CHECKSUM_ERRORS)
+ vty_out (vty,"IS-IS checksum errors debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_LOCAL_UPDATES)
+ vty_out (vty,"IS-IS local updates debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_PROTOCOL_ERRORS)
+ vty_out (vty,"IS-IS protocol errors debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_SNP_PACKETS)
+ vty_out (vty,"IS-IS CSNP/PSNP packets debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_SPF_EVENTS)
+ vty_out (vty,"IS-IS SPF events debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_SPF_STATS)
+ vty_out (vty,"IS-IS SPF Timing and Statistics Data debugging is %s%s",
+ onoffs, VTY_NEWLINE);
+ if (flags & DEBUG_SPF_TRIGGERS)
+ vty_out (vty,"IS-IS SPF triggering events debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_UPDATE_PACKETS)
+ vty_out (vty,"IS-IS Update related packet debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_RTE_EVENTS)
+ vty_out (vty,"IS-IS Route related debuggin is %s%s", onoffs,
+ VTY_NEWLINE);
+ if (flags & DEBUG_EVENTS)
+ vty_out (vty,"IS-IS Event debugging is %s%s", onoffs,
+ VTY_NEWLINE);
+
+}
+
+DEFUN (show_debugging,
+ show_debugging_cmd,
+ "show debugging",
+ SHOW_STR
+ "State of each debugging option\n")
+{
+ vty_out (vty,"IS-IS:%s", VTY_NEWLINE);
+ print_debug (vty, isis->debugs, 1);
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_adj,
+ debug_isis_adj_cmd,
+ "debug isis adj-packets",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Adjacency related packets\n"
+ )
+{
+ isis->debugs |= DEBUG_ADJ_PACKETS;
+ print_debug (vty,DEBUG_ADJ_PACKETS,1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_adj,
+ no_debug_isis_adj_cmd,
+ "no debug isis adj-packets",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Adjacency related packets\n"
+ )
+{
+
+ isis->debugs &= ~DEBUG_ADJ_PACKETS;
+ print_debug (vty, DEBUG_ADJ_PACKETS, 0);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_isis_csum,
+ debug_isis_csum_cmd,
+ "debug isis checksum-errors",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS LSP checksum errors\n"
+ )
+{
+ isis->debugs |= DEBUG_CHECKSUM_ERRORS;
+ print_debug (vty, DEBUG_CHECKSUM_ERRORS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_csum,
+ no_debug_isis_csum_cmd,
+ "no debug isis checksum-errors",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS LSP checksum errors\n"
+ )
+{
+ isis->debugs &= ~DEBUG_CHECKSUM_ERRORS;
+ print_debug (vty, DEBUG_CHECKSUM_ERRORS, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_lupd,
+ debug_isis_lupd_cmd,
+ "debug isis local-updates",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS local update packets\n"
+ )
+{
+ isis->debugs |= DEBUG_LOCAL_UPDATES;
+ print_debug (vty, DEBUG_LOCAL_UPDATES, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_lupd,
+ no_debug_isis_lupd_cmd,
+ "no debug isis local-updates",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS local update packets\n"
+ )
+{
+ isis->debugs &= ~DEBUG_LOCAL_UPDATES;
+ print_debug (vty, DEBUG_LOCAL_UPDATES , 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_err,
+ debug_isis_err_cmd,
+ "debug isis protocol-errors",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS LSP protocol errors\n"
+ )
+{
+ isis->debugs |= DEBUG_PROTOCOL_ERRORS;
+ print_debug (vty, DEBUG_PROTOCOL_ERRORS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_err,
+ no_debug_isis_err_cmd,
+ "no debug isis protocol-errors",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS LSP protocol errors\n"
+ )
+{
+ isis->debugs &= ~DEBUG_PROTOCOL_ERRORS;
+ print_debug (vty, DEBUG_PROTOCOL_ERRORS, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_snp,
+ debug_isis_snp_cmd,
+ "debug isis snp-packets",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS CSNP/PSNP packets\n"
+ )
+{
+ isis->debugs |= DEBUG_SNP_PACKETS;
+ print_debug (vty, DEBUG_SNP_PACKETS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_snp,
+ no_debug_isis_snp_cmd,
+ "no debug isis snp-packets",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS CSNP/PSNP packets\n"
+ )
+{
+ isis->debugs &= ~DEBUG_SNP_PACKETS ;
+ print_debug (vty, DEBUG_SNP_PACKETS, 0);
+
+ return CMD_SUCCESS;
+}
+
+
+
+DEFUN (debug_isis_upd,
+ debug_isis_upd_cmd,
+ "debug isis update-packets",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Update related packets\n"
+ )
+{
+ isis->debugs |= DEBUG_UPDATE_PACKETS;
+ print_debug (vty, DEBUG_UPDATE_PACKETS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_upd,
+ no_debug_isis_upd_cmd,
+ "no debug isis update-packets",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Update related packets\n"
+ )
+{
+ isis->debugs &= ~DEBUG_UPDATE_PACKETS;
+ print_debug (vty, DEBUG_UPDATE_PACKETS, 0);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_isis_spfevents,
+ debug_isis_spfevents_cmd,
+ "debug isis spf-events",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Shortest Path First Events\n"
+ )
+{
+ isis->debugs |= DEBUG_SPF_EVENTS;
+ print_debug (vty, DEBUG_SPF_EVENTS , 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_spfevents,
+ no_debug_isis_spfevents_cmd,
+ "no debug isis spf-events",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Shortest Path First Events\n"
+ )
+{
+ isis->debugs &= ~DEBUG_SPF_EVENTS;
+ print_debug (vty, DEBUG_SPF_EVENTS , 0);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (debug_isis_spfstats,
+ debug_isis_spfstats_cmd,
+ "debug isis spf-statistics ",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS SPF Timing and Statistic Data\n"
+ )
+{
+ isis->debugs |= DEBUG_SPF_STATS;
+ print_debug (vty, DEBUG_SPF_STATS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_spfstats,
+ no_debug_isis_spfstats_cmd,
+ "no debug isis spf-statistics",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS SPF Timing and Statistic Data\n"
+ )
+{
+ isis->debugs &= ~DEBUG_SPF_STATS;
+ print_debug (vty, DEBUG_SPF_STATS, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_spftrigg,
+ debug_isis_spftrigg_cmd,
+ "debug isis spf-triggers",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS SPF triggering events\n"
+ )
+{
+ isis->debugs |= DEBUG_SPF_TRIGGERS;
+ print_debug (vty, DEBUG_SPF_TRIGGERS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_spftrigg,
+ no_debug_isis_spftrigg_cmd,
+ "no debug isis spf-triggers",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS SPF triggering events\n"
+ )
+{
+ isis->debugs &= ~DEBUG_SPF_TRIGGERS;
+ print_debug (vty, DEBUG_SPF_TRIGGERS, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_rtevents,
+ debug_isis_rtevents_cmd,
+ "debug isis route-events",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Route related events\n"
+ )
+{
+ isis->debugs |= DEBUG_RTE_EVENTS;
+ print_debug (vty, DEBUG_RTE_EVENTS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_rtevents,
+ no_debug_isis_rtevents_cmd,
+ "no debug isis route-events",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Route related events\n"
+ )
+{
+ isis->debugs &= ~DEBUG_RTE_EVENTS;
+ print_debug (vty, DEBUG_RTE_EVENTS, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (debug_isis_events,
+ debug_isis_events_cmd,
+ "debug isis events",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Events\n"
+ )
+{
+ isis->debugs |= DEBUG_EVENTS;
+ print_debug (vty, DEBUG_EVENTS, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_events,
+ no_debug_isis_events_cmd,
+ "no debug isis events",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS Events\n"
+ )
+{
+ isis->debugs &= ~DEBUG_EVENTS;
+ print_debug (vty, DEBUG_EVENTS, 0);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_hostname,
+ show_hostname_cmd,
+ "show isis hostname",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS Dynamic hostname mapping\n")
+{
+ dynhn_print_all (vty);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_database,
+ show_database_cmd,
+ "show isis database",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS link state database\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+ int level,lsp_count;
+
+ if (isis->area_list->count == 0)
+ return CMD_SUCCESS;
+
+ for (node = listhead (isis->area_list); node; nextnode (node)) {
+ area = getdata (node);
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+ for (level=0;level<ISIS_LEVELS;level++) {
+ if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) {
+ vty_out (vty,"IS-IS Level-%d link-state database:%s", level+1,
+ VTY_NEWLINE);
+
+ lsp_count = lsp_print_all (vty, area->lspdb[level],
+ ISIS_UI_LEVEL_BRIEF,
+ area->dynhostname);
+
+ vty_out (vty,"%s %u LSPs%s%s",
+ VTY_NEWLINE,
+ lsp_count,
+ VTY_NEWLINE,
+ VTY_NEWLINE);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_database_detail,
+ show_database_detail_cmd,
+ "show isis database detail",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS link state database\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+ int level, lsp_count;
+
+ if (isis->area_list->count == 0)
+ return CMD_SUCCESS;
+
+ for (node = listhead (isis->area_list); node; nextnode (node)) {
+ area = getdata (node);
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+ for (level=0;level<ISIS_LEVELS;level++) {
+ if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) {
+ vty_out (vty,"IS-IS Level-%d Link State Database:%s", level+1,
+ VTY_NEWLINE);
+
+ lsp_count = lsp_print_all (vty, area->lspdb[level],
+ ISIS_UI_LEVEL_DETAIL,
+ area->dynhostname);
+
+ vty_out (vty,"%s %u LSPs%s%s",
+ VTY_NEWLINE,
+ lsp_count,
+ VTY_NEWLINE,
+ VTY_NEWLINE);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * 'router isis' command
+ */
+DEFUN (router_isis,
+ router_isis_cmd,
+ "router isis WORD",
+ ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag")
+{
+
+ return isis_area_get (vty, argv[0]);
+
+}
+
+/*
+ *'no router isis' command
+ */
+DEFUN (no_router_isis,
+ no_router_isis_cmd,
+ "no router isis WORD",
+ "no\n"
+ ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag")
+
+{
+ return isis_area_destroy (vty, argv[0]);
+}
+
+/*
+ * 'net' command
+ */
+DEFUN (net,
+ net_cmd,
+ "net WORD",
+ "A Network Entity Title for this process (OSI only)\n"
+ "XX.XXXX. ... .XXX.XX Network entity title (NET)\n" )
+{
+ return area_net_title (vty, argv[0]);
+}
+
+
+/*
+ * 'no net' command
+ */
+DEFUN (no_net,
+ no_net_cmd,
+ "no net WORD",
+ NO_STR
+ "A Network Entity Title for this process (OSI only)\n"
+ "XX.XXXX. ... .XXX.XX Network entity title (NET)\n" )
+{
+ return area_clear_net_title (vty, argv[0]);
+}
+
+DEFUN (area_passwd,
+ area_passwd_cmd,
+ "area-password WORD",
+ "Configure the authentication password for an area\n"
+ "Area password\n" )
+{
+ struct isis_area *area;
+ int len;
+
+ area = vty->index;
+
+ if (!area) {
+ vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ len = strlen (argv[0]);
+ if (len > 254) {
+ vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ area->area_passwd.len = (u_char)len;
+ area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
+ strncpy (area->area_passwd.passwd, argv[0], 255);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_area_passwd,
+ no_area_passwd_cmd,
+ "no area-password",
+ NO_STR
+ "Configure the authentication password for an area\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+
+ if (!area) {
+ vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memset (&area->area_passwd, 0, sizeof (struct isis_passwd));
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (domain_passwd,
+ domain_passwd_cmd,
+ "domain-password WORD",
+ "Set the authentication password for a routing domain\n"
+ "Routing domain password\n" )
+{
+ struct isis_area *area;
+ int len;
+
+ area = vty->index;
+
+ if (!area) {
+ vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ len = strlen (argv[0]);
+ if (len > 254) {
+ vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ area->domain_passwd.len = (u_char)len;
+ area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
+ strncpy (area->domain_passwd.passwd, argv[0], 255);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (no_domain_passwd,
+ no_domain_passwd_cmd,
+ "no domain-password WORD",
+ NO_STR
+ "Set the authentication password for a routing domain\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+
+ if (!area) {
+ vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memset (&area->domain_passwd, 0, sizeof (struct isis_passwd));
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (is_type,
+ is_type_cmd,
+ "is-type (level-1|level-1-2|level-2-only)",
+ "IS Level for this routing process (OSI only)\n"
+ "Act as a station router only\n"
+ "Act as both a station router and an area router\n"
+ "Act as an area router only\n")
+{
+ struct isis_area *area;
+ int type;
+
+ area = vty->index;
+
+ if (!area) {
+ vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ type = string2circuit_t (argv[0]);
+ if (!type) {
+ vty_out (vty, "Unknown IS level %s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ isis_event_system_type_change (area, type);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_is_type,
+ no_is_type_cmd,
+ "no is-type (level-1|level-1-2|level-2-only)",
+ NO_STR
+ "IS Level for this routing process (OSI only)\n"
+ "Act as a station router only\n"
+ "Act as both a station router and an area router\n"
+ "Act as an area router only\n")
+{
+
+ struct isis_area *area;
+ int type;
+
+ area = vty->index;
+ assert (area);
+
+ /*
+ * Put the is-type back to default. Which is level-1-2 on first
+ * circuit for the area level-1 for the rest
+ */
+ if (getdata (listhead (isis->area_list)) == area )
+ type = IS_LEVEL_1_AND_2;
+ else
+ type = IS_LEVEL_1;
+
+ isis_event_system_type_change (area, type);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (lsp_gen_interval,
+ lsp_gen_interval_cmd,
+ "lsp-gen-interval <1-120>",
+ "Minimum interval between regenerating same LSP\n"
+ "Minimum interval in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+ area->lsp_gen_interval[0] = interval;
+ area->lsp_gen_interval[1] = interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_lsp_gen_interval,
+ no_lsp_gen_interval_cmd,
+ "no lsp-gen-interval",
+ NO_STR
+ "Minimum interval between regenerating same LSP\n"
+ )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
+ area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_lsp_gen_interval,
+ no_lsp_gen_interval_arg_cmd,
+ "no lsp-gen-interval <1-120>",
+ NO_STR
+ "Minimum interval between regenerating same LSP\n"
+ "Minimum interval in seconds\n"
+ )
+
+DEFUN (lsp_gen_interval_l1,
+ lsp_gen_interval_l1_cmd,
+ "lsp-gen-interval level-1 <1-120>",
+ "Minimum interval between regenerating same LSP\n"
+ "Set interval for level 1 only\n"
+ "Minimum interval in seconds\n"
+ )
+{
+ struct isis_area *area;
+ uint16_t interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+ area->lsp_gen_interval[0] = interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_lsp_gen_interval_l1,
+ no_lsp_gen_interval_l1_cmd,
+ "no lsp-gen-interval level-1",
+ NO_STR
+ "Minimum interval between regenerating same LSP\n"
+ "Set interval for level 1 only\n"
+
+ )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_lsp_gen_interval_l1,
+ no_lsp_gen_interval_l1_arg_cmd,
+ "no lsp-gen-interval level-1 <1-120>",
+ NO_STR
+ "Minimum interval between regenerating same LSP\n"
+ "Set interval for level 1 only\n"
+ "Minimum interval in seconds\n"
+ )
+
+
+DEFUN (lsp_gen_interval_l2,
+ lsp_gen_interval_l2_cmd,
+ "lsp-gen-interval level-2 <1-120>",
+ "Minimum interval between regenerating same LSP\n"
+ "Set interval for level 2 only\n"
+ "Minimum interval in seconds\n"
+ )
+{
+ struct isis_area *area;
+ int interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+ area->lsp_gen_interval[1] = interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_lsp_gen_interval_l2,
+ no_lsp_gen_interval_l2_cmd,
+ "no lsp-gen-interval level-2",
+ NO_STR
+ "Minimum interval between regenerating same LSP\n"
+ "Set interval for level 2 only\n"
+ )
+{
+ struct isis_area *area;
+ int interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+ area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_lsp_gen_interval_l2,
+ no_lsp_gen_interval_l2_arg_cmd,
+ "no lsp-gen-interval level-2 <1-120>",
+ NO_STR
+ "Minimum interval between regenerating same LSP\n"
+ "Set interval for level 2 only\n"
+ "Minimum interval in seconds\n"
+ )
+
+
+DEFUN (metric_style,
+ metric_style_cmd,
+ "metric-style (narrow|wide)",
+ "Use old-style (ISO 10589) or new-style packet formats\n"
+ "Use old style of TLVs with narrow metric\n"
+ "Use new style of TLVs to carry wider metric\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+ if (!strcmp(argv[0],"wide"))
+ area->newmetric = 1;
+ else
+ area->newmetric = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_metric_style,
+ no_metric_style_cmd,
+ "no metric-style (narrow|wide)",
+ NO_STR
+ "Use old-style (ISO 10589) or new-style packet formats\n"
+ "Use old style of TLVs with narrow metric\n"
+ "Use new style of TLVs to carry wider metric\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ if (!strcmp(argv[0],"wide"))
+ area->newmetric = 0;
+ else
+ area->newmetric = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (dynamic_hostname,
+ dynamic_hostname_cmd,
+ "hostname dynamic",
+ "Dynamic hostname for IS-IS\n"
+ "Dynamic hostname\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->dynhostname = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_dynamic_hostname,
+ no_dynamic_hostname_cmd,
+ "no hostname dynamic",
+ NO_STR
+ "Dynamic hostname for IS-IS\n"
+ "Dynamic hostname\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->dynhostname = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (spf_interval,
+ spf_interval_cmd,
+ "spf-interval <1-120>",
+ "Minimum interval between SPF calculations"
+ "Minimum interval between consecutive SPFs in seconds\n")
+{
+ struct isis_area *area;
+ u_int16_t interval;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ area->min_spf_interval[0] = interval;
+ area->min_spf_interval[1] = interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_spf_interval,
+ no_spf_interval_cmd,
+ "no spf-interval",
+ NO_STR
+ "Minimum interval between SPF calculations\n"
+ )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+
+ area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
+ area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_spf_interval,
+ no_spf_interval_arg_cmd,
+ "no spf-interval <1-120>",
+ NO_STR
+ "Minimum interval between SPF calculations\n"
+ "Minimum interval between consecutive SPFs in seconds\n"
+ )
+
+DEFUN (spf_interval_l1,
+ spf_interval_l1_cmd,
+ "spf-interval level-1 <1-120>",
+ "Minimum interval between SPF calculations\n"
+ "Set interval for level 1 only\n"
+ "Minimum interval between consecutive SPFs in seconds\n")
+{
+ struct isis_area *area;
+ u_int16_t interval;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ area->min_spf_interval[0] = interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_spf_interval_l1,
+ no_spf_interval_l1_cmd,
+ "no spf-interval level-1",
+ NO_STR
+ "Minimum interval between SPF calculations\n"
+ "Set interval for level 1 only\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+
+ area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_spf_interval,
+ no_spf_interval_l1_arg_cmd,
+ "no spf-interval level-1 <1-120>",
+ NO_STR
+ "Minimum interval between SPF calculations\n"
+ "Set interval for level 1 only\n"
+ "Minimum interval between consecutive SPFs in seconds\n")
+
+DEFUN (spf_interval_l2,
+ spf_interval_l2_cmd,
+ "spf-interval level-2 <1-120>",
+ "Minimum interval between SPF calculations\n"
+ "Set interval for level 2 only\n"
+ "Minimum interval between consecutive SPFs in seconds\n")
+{
+ struct isis_area *area;
+ u_int16_t interval;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ area->min_spf_interval[1] = interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_spf_interval_l2,
+ no_spf_interval_l2_cmd,
+ "no spf-interval level-2",
+ NO_STR
+ "Minimum interval between SPF calculations\n"
+ "Set interval for level 2 only\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+
+ area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_spf_interval,
+ no_spf_interval_l2_arg_cmd,
+ "no spf-interval level-2 <1-120>",
+ NO_STR
+ "Minimum interval between SPF calculations\n"
+ "Set interval for level 2 only\n"
+ "Minimum interval between consecutive SPFs in seconds\n")
+
+
+#ifdef TOPOLOGY_GENERATE
+DEFUN (topology_generate_grid,
+ topology_generate_grid_cmd,
+ "topology generate grid <1-100> <1-100> <1-65000> [param] [param] "
+ "[param]",
+ "Topology for IS-IS\n"
+ "Topology for IS-IS\n"
+ "Topology grid for IS-IS\n"
+ "X parameter of the grid\n"
+ "Y parameter of the grid\n"
+ "Random seed\n"
+ "Optional param 1\n"
+ "Optional param 2\n"
+ "Optional param 3\n"
+ "Topology\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ if (!spgrid_check_params (vty, argc, argv)) {
+ if (area->topology)
+ list_delete (area->topology);
+ area->topology = list_new();
+ memcpy(area->top_params,vty->buf,200);
+ gen_spgrid_topology (vty, area->topology);
+ remove_topology_lsps (area);
+ generate_topology_lsps (area);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_isis_topology,
+ show_isis_topology_cmd,
+ "show isis topology",
+ SHOW_STR
+ "clns network information\n"
+ "CLNS neighbor adjacencies\n")
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct listnode *node2;
+ struct arc *arc;
+ LIST_LOOP (isis->area_list, area, node) {
+ if (area->topology) {
+ vty_out (vty, "Topology for isis area:%s%s",area->area_tag, VTY_NEWLINE);
+ LIST_LOOP (area->topology, arc, node2) {
+ vty_out (vty, "a %ld %ld %ld%s",arc->from_node, arc->to_node,
+ arc->distance, VTY_NEWLINE);
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/*
+ * 'topology base-is' command
+ */
+DEFUN (topology_baseis ,
+ topology_baseis_cmd,
+ "topology base-is WORD",
+ "Topology for IS-IS\n"
+ "Topology for IS-IS\n"
+ "A Network IS Base for this topology"
+ "XX.XXXX.XXXX.XX Network entity title (NET)\n" )
+{
+ struct isis_area *area;
+ u_char buff[ISIS_SYS_ID_LEN];
+
+ area = vty->index;
+ assert (area);
+
+ if (sysid2buff (buff, argv[0])) {
+ sysid2buff (area->topology_baseis, argv[0]);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * 'no net' command
+ */
+DEFUN (no_topology_baseis,
+ no_topology_baseis_cmd,
+ "no topology base-is WORD",
+ NO_STR
+ "A Network Entity Title for this process (OSI only)"
+ "XX.XXXX. ... .XXX.XX Network entity title (NET)\n" )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ memcpy(area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
+ return CMD_SUCCESS;
+}
+
+#endif /* TOPOLOGY_GENERATE */
+
+DEFUN (lsp_lifetime,
+ lsp_lifetime_cmd,
+ "lsp-lifetime <380-65535>",
+ "Maximum LSP lifetime\n"
+ "LSP lifetime in seconds\n"
+ )
+{
+ struct isis_area *area;
+ uint16_t interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+
+ if (interval < ISIS_MIN_LSP_LIFETIME) {
+ vty_out (vty, "LSP lifetime (%us) below %us%s",
+ interval,
+ ISIS_MIN_LSP_LIFETIME,
+ VTY_NEWLINE);
+
+ return CMD_WARNING;
+ }
+
+
+ area->max_lsp_lifetime[0] = interval;
+ area->max_lsp_lifetime[1] = interval;
+ area->lsp_refresh[0] = interval-300;
+ area->lsp_refresh[1] = interval-300;
+
+ if (area->t_lsp_refresh[0]) {
+ thread_cancel (area->t_lsp_refresh[0]);
+ thread_execute (master, lsp_refresh_l1, area, 0);
+ }
+
+ if (area->t_lsp_refresh[1]) {
+ thread_cancel (area->t_lsp_refresh[1]);
+ thread_execute (master, lsp_refresh_l2, area, 0);
+ }
+
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_lsp_lifetime,
+ no_lsp_lifetime_cmd,
+ "no lsp-lifetime",
+ NO_STR
+ "LSP lifetime in seconds\n"
+ )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */
+ area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */
+ area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */
+ area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_lsp_lifetime,
+ no_lsp_lifetime_arg_cmd,
+ "no lsp-lifetime <380-65535>",
+ NO_STR
+ "Maximum LSP lifetime\n"
+ "LSP lifetime in seconds\n"
+ )
+
+DEFUN (lsp_lifetime_l1,
+ lsp_lifetime_l1_cmd,
+ "lsp-lifetime level-1 <380-65535>",
+ "Maximum LSP lifetime for Level 1 only\n"
+ "LSP lifetime for Level 1 only in seconds\n"
+ )
+{
+ struct isis_area *area;
+ uint16_t interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+
+ if (interval < ISIS_MIN_LSP_LIFETIME) {
+ vty_out (vty, "Level-1 LSP lifetime (%us) below %us%s",
+ interval,
+ ISIS_MIN_LSP_LIFETIME,
+ VTY_NEWLINE);
+
+ return CMD_WARNING;
+ }
+
+
+ area->max_lsp_lifetime[0] = interval;
+ area->lsp_refresh[0] = interval-300;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_lsp_lifetime_l1,
+ no_lsp_lifetime_l1_cmd,
+ "no lsp-lifetime level-1",
+ NO_STR
+ "LSP lifetime for Level 1 only in seconds\n"
+ )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */
+ area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_lsp_lifetime_l1,
+ no_lsp_lifetime_l1_arg_cmd,
+ "no lsp-lifetime level-1 <380-65535>",
+ NO_STR
+ "Maximum LSP lifetime for Level 1 only\n"
+ "LSP lifetime for Level 1 only in seconds\n"
+ )
+
+DEFUN (lsp_lifetime_l2,
+ lsp_lifetime_l2_cmd,
+ "lsp-lifetime level-2 <380-65535>",
+ "Maximum LSP lifetime for Level 2 only\n"
+ "LSP lifetime for Level 2 only in seconds\n"
+ )
+{
+ struct isis_area *area;
+ uint16_t interval;
+
+ area = vty->index;
+ assert (area);
+
+ interval = atoi (argv[0]);
+
+ if (interval < ISIS_MIN_LSP_LIFETIME) {
+ vty_out (vty, "Level-2 LSP lifetime (%us) below %us%s",
+ interval,
+ ISIS_MIN_LSP_LIFETIME,
+ VTY_NEWLINE);
+
+ return CMD_WARNING;
+ }
+
+
+ area->max_lsp_lifetime[1] = interval;
+ area->lsp_refresh[1] = interval - 300;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_lsp_lifetime_l2,
+ no_lsp_lifetime_l2_cmd,
+ "no lsp-lifetime level-2",
+ NO_STR
+ "LSP lifetime for Level 2 only in seconds\n"
+ )
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */
+ area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_lsp_lifetime_l2,
+ no_lsp_lifetime_l2_arg_cmd,
+ "no lsp-lifetime level-2 <380-65535>",
+ NO_STR
+ "Maximum LSP lifetime for Level 2 only\n"
+ "LSP lifetime for Level 2 only in seconds\n"
+ )
+
+
+
+
+/* IS-IS configuration write function */
+int
+isis_config_write (struct vty *vty)
+{
+ int write = 0;
+
+ if (isis != NULL) {
+ struct isis_area *area;
+ struct listnode *node;
+ struct listnode *node2;
+
+ LIST_LOOP (isis->area_list, area, node) {
+ /* ISIS - Area name */
+ vty_out (vty, "router isis %s%s",area->area_tag, VTY_NEWLINE);
+ write++;
+ /* ISIS - Net */
+ if (listcount (area->area_addrs) > 0) {
+ struct area_addr *area_addr;
+ LIST_LOOP (area->area_addrs, area_addr, node2) {
+ vty_out (vty, " net %s%s",
+ isonet_print (area_addr->area_addr,
+ area_addr->addr_len + ISIS_SYS_ID_LEN + 1),
+ VTY_NEWLINE);
+ write ++;
+ }
+ }
+ /* ISIS - Dynamic hostname - Defaults to true so only display if false*/
+ if (!area->dynhostname) {
+ vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE);
+ write ++;
+ }
+ /* ISIS - Metric-Style - when true displays wide */
+ if (area->newmetric) {
+ vty_out (vty, " metric-style wide%s", VTY_NEWLINE);
+ write ++;
+ }
+ /* ISIS - Area is-type (level-1-2 is default) */
+ if (area->is_type == IS_LEVEL_1) {
+ vty_out (vty, " is-type level-1%s", VTY_NEWLINE);
+ write ++;
+ } else {if (area->is_type == IS_LEVEL_2) {
+ vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE);
+ write ++;
+ }}
+ /* ISIS - Lsp generation interval */
+ if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1]) {
+ if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT) {
+ vty_out (vty, " lsp-gen-interval %d%s", area->lsp_gen_interval[0],
+ VTY_NEWLINE);
+ write ++;
+ }} else {
+ if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT) {
+ vty_out (vty, " lsp-gen-interval level-1 %d%s",
+ area->lsp_gen_interval[0], VTY_NEWLINE);
+ write ++;
+ }
+ if (area->lsp_gen_interval[1] != LSP_GEN_INTERVAL_DEFAULT) {
+ vty_out (vty, " lsp-gen-interval level-2 %d%s",
+ area->lsp_gen_interval[1], VTY_NEWLINE);
+ write ++;
+ }
+ }
+ /* ISIS - LSP lifetime */
+ if (area->max_lsp_lifetime[0] == area->max_lsp_lifetime[1]) {
+ if (area->max_lsp_lifetime[0] != MAX_AGE) {
+ vty_out (vty, " lsp-lifetime %u%s", area->max_lsp_lifetime[0],
+ VTY_NEWLINE);
+ write ++;
+ }} else {
+ if (area->max_lsp_lifetime[0] != MAX_AGE) {
+ vty_out (vty, " lsp-lifetime level-1 %u%s", area->max_lsp_lifetime[0],
+ VTY_NEWLINE);
+ write ++;
+ }
+ if (area->max_lsp_lifetime[1] != MAX_AGE) {
+ vty_out (vty, " lsp-lifetime level-2 %u%s", area->max_lsp_lifetime[1],
+ VTY_NEWLINE);
+ write ++;
+ }
+ }
+ #ifdef TOPOLOGY_GENERATE
+ /* seems we save the whole command line here */
+ if (area->top_params) {
+ vty_out (vty, " %s%s",area->top_params, VTY_NEWLINE);
+ write ++;
+ }
+
+ if (memcmp(area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS,
+ ISIS_SYS_ID_LEN)) {
+ vty_out (vty, " topology base_is %s%s",
+ sysid_print (area->topology_baseis), VTY_NEWLINE);
+ write ++;
+ }
+
+ #endif /* TOPOLOGY_GENERATE */
+ }
+ }
+
+ return write;
+}
+
+struct cmd_node isis_node =
+{
+ ISIS_NODE,
+ "%s(config_router)# ",
+ 1
+};
+
+void
+isis_init ()
+{
+
+ /* Install IS-IS top node */
+ install_node (&isis_node, isis_config_write);
+
+ install_element (VIEW_NODE, &show_clns_neighbors_cmd);
+ install_element (VIEW_NODE, &show_isis_neighbors_cmd);
+ install_element (VIEW_NODE, &show_clns_neighbors_detail_cmd);
+ install_element (VIEW_NODE, &show_isis_neighbors_detail_cmd);
+
+ install_element (VIEW_NODE, &show_hostname_cmd);
+ install_element (VIEW_NODE, &show_database_cmd);
+ install_element (VIEW_NODE, &show_database_detail_cmd);
+
+ install_element (ENABLE_NODE, &show_clns_neighbors_cmd);
+ install_element (ENABLE_NODE, &show_isis_neighbors_cmd);
+ install_element (ENABLE_NODE, &show_clns_neighbors_detail_cmd);
+ install_element (ENABLE_NODE, &show_isis_neighbors_detail_cmd);
+
+ install_element (ENABLE_NODE, &show_hostname_cmd);
+ install_element (ENABLE_NODE, &show_database_cmd);
+ install_element (ENABLE_NODE, &show_database_detail_cmd);
+ install_element (ENABLE_NODE, &show_debugging_cmd);
+
+ install_element (ENABLE_NODE, &debug_isis_adj_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_adj_cmd);
+ install_element (ENABLE_NODE, &debug_isis_csum_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_csum_cmd);
+ install_element (ENABLE_NODE, &debug_isis_lupd_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_lupd_cmd);
+ install_element (ENABLE_NODE, &debug_isis_err_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_err_cmd);
+ install_element (ENABLE_NODE, &debug_isis_snp_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_snp_cmd);
+ install_element (ENABLE_NODE, &debug_isis_upd_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_upd_cmd);
+ install_element (ENABLE_NODE, &debug_isis_spfevents_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_spfevents_cmd);
+ install_element (ENABLE_NODE, &debug_isis_spfstats_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_spfstats_cmd);
+ install_element (ENABLE_NODE, &debug_isis_spftrigg_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_spftrigg_cmd);
+ install_element (ENABLE_NODE, &debug_isis_rtevents_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd);
+ install_element (ENABLE_NODE, &debug_isis_events_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_events_cmd);
+
+ install_element (CONFIG_NODE, &router_isis_cmd);
+ install_element (CONFIG_NODE, &no_router_isis_cmd);
+
+ install_default (ISIS_NODE);
+
+ install_element (ISIS_NODE, &net_cmd);
+ install_element (ISIS_NODE, &no_net_cmd);
+
+ install_element (ISIS_NODE, &is_type_cmd);
+ install_element (ISIS_NODE, &no_is_type_cmd);
+
+ install_element (ISIS_NODE, &area_passwd_cmd);
+ install_element (ISIS_NODE, &no_area_passwd_cmd);
+
+ install_element (ISIS_NODE, &domain_passwd_cmd);
+ install_element (ISIS_NODE, &no_domain_passwd_cmd);
+
+ install_element (ISIS_NODE, &lsp_gen_interval_cmd);
+ install_element (ISIS_NODE, &no_lsp_gen_interval_cmd);
+ install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd);
+ install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd);
+ install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd);
+ install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd);
+ install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd);
+ install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd);
+ install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd);
+
+ install_element (ISIS_NODE, &spf_interval_cmd);
+ install_element (ISIS_NODE, &no_spf_interval_cmd);
+ install_element (ISIS_NODE, &no_spf_interval_arg_cmd);
+ install_element (ISIS_NODE, &spf_interval_l1_cmd);
+ install_element (ISIS_NODE, &no_spf_interval_l1_cmd);
+ install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd);
+ install_element (ISIS_NODE, &spf_interval_l2_cmd);
+ install_element (ISIS_NODE, &no_spf_interval_l2_cmd);
+ install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd);
+
+ install_element (ISIS_NODE, &lsp_lifetime_cmd);
+ install_element (ISIS_NODE, &no_lsp_lifetime_cmd);
+ install_element (ISIS_NODE, &no_lsp_lifetime_arg_cmd);
+ install_element (ISIS_NODE, &lsp_lifetime_l1_cmd);
+ install_element (ISIS_NODE, &no_lsp_lifetime_l1_cmd);
+ install_element (ISIS_NODE, &no_lsp_lifetime_l1_arg_cmd);
+ install_element (ISIS_NODE, &lsp_lifetime_l2_cmd);
+ install_element (ISIS_NODE, &no_lsp_lifetime_l2_cmd);
+ install_element (ISIS_NODE, &no_lsp_lifetime_l2_arg_cmd);
+
+ install_element (ISIS_NODE, &dynamic_hostname_cmd);
+ install_element (ISIS_NODE, &no_dynamic_hostname_cmd);
+
+ install_element (ISIS_NODE, &metric_style_cmd);
+ install_element (ISIS_NODE, &no_metric_style_cmd);
+#ifdef TOPOLOGY_GENERATE
+ install_element (ISIS_NODE, &topology_generate_grid_cmd);
+ install_element (ISIS_NODE, &topology_baseis_cmd);
+ install_element (ISIS_NODE, &no_topology_baseis_cmd);
+ install_element (VIEW_NODE, &show_isis_topology_cmd);
+ install_element (ENABLE_NODE, &show_isis_topology_cmd);
+#endif /* TOPOLOGY_GENERATE */
+
+ isis_new(0);
+ isis_circuit_init ();
+ isis_zebra_init ();
+ isis_spf_cmds_init ();
+}
+
+
+
+
+
+
diff --git a/isisd/isisd.conf.sample b/isisd/isisd.conf.sample
new file mode 100644
index 00000000..9e08778e
--- /dev/null
+++ b/isisd/isisd.conf.sample
@@ -0,0 +1,39 @@
+! -*- isis -*-
+!
+! ISISd sample configuration file
+!
+!
+!
+hostname isisd
+password foo
+enable password foo
+!log stdout
+log file /tmp/isisd.log
+!
+!
+!
+router isis DEAD
+ net 47.0023.0000.0003.0300.0100.0102.0304.0506.00
+! is-type level-1
+
+! -- set the lifetime either for level-1, level-2 or both
+! lsp-lifetime level-1 65535
+! lsp-lifetime level-2 65535
+! lsp-lifetime 65535
+
+interface eth0
+ ip router isis DEAD
+ ip address 10.101.43.194
+ isis hello-interval 10000
+! isis lsp-interval 1000
+
+! -- optional
+! isis circuit-type level-1
+! isis password lallaa level-1
+! isis metric 1 level-1
+! isis csnp-interval 5 level-1
+! isis retransmit-interval 10
+! isis retransmit-throttle-interval
+! isis hello-multiplier 2 level-1
+!
+!
diff --git a/isisd/isisd.h b/isisd/isisd.h
new file mode 100644
index 00000000..67bf8d63
--- /dev/null
+++ b/isisd/isisd.h
@@ -0,0 +1,147 @@
+/*
+ * IS-IS Rout(e)ing protocol - isisd.h
+ *
+ * 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.
+ */
+
+#ifndef ISISD_H
+#define ISISD_H
+
+#define ISISD_VERSION "0.0.7"
+#define ISIS_VTYSH_PATH "/tmp/.isisd"
+
+/* uncomment if you are a developer in bug hunt */
+/* #define EXTREME_DEBUG */
+/* #define EXTREME_TLV_DEBUG */
+
+/* If you want topology stuff compiled in */
+/* #define TOPOLOGY_GENERATE */
+
+struct rmap{
+ char *name;
+ struct route_map *map;
+};
+
+struct isis
+{
+ u_long process_id;
+ int sysid_set;
+ u_char sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */
+ struct list *area_list; /* list of IS-IS areas */
+ struct list *init_circ_list;
+ struct list *nexthops; /* IPv4 next hops from this IS */
+#ifdef HAVE_IPV6
+ struct list *nexthops6; /* IPv6 next hops from this IS */
+#endif /* HAVE_IPV6 */
+ u_char max_area_addrs; /* maximumAreaAdresses */
+ struct area_addr *man_area_addrs; /* manualAreaAddresses */
+ u_int32_t debugs; /* bitmap for debug */
+ time_t uptime; /* when did we start */
+
+ /* Redistributed external information. */
+ struct route_table *external_info[ZEBRA_ROUTE_MAX + 1];
+ /* Redistribute metric info. */
+ struct {
+ int type; /* Internal or External */
+ int value; /* metric value */
+ } dmetric [ZEBRA_ROUTE_MAX + 1];
+
+ struct {
+ char *name;
+ struct route_map *map;
+ } rmap [ZEBRA_ROUTE_MAX + 1];
+#ifdef HAVE_IPV6
+ struct {
+ struct {
+ char *name;
+ struct route_map *map;
+ } rmap [ZEBRA_ROUTE_MAX + 1];
+ } inet6_afmode;
+#endif
+};
+
+struct isis_area
+{
+ struct isis *isis; /* back pointer */
+ dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */
+ struct isis_spftree *spftree[ISIS_LEVELS]; /* The v4 SPTs */
+ struct route_table *route_table; /* IPv4 routes */
+#ifdef HAVE_IPV6
+ struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v4 SPTs */
+ struct route_table *route_table6; /* IPv6 routes */
+#endif
+ int min_bcast_mtu;
+ struct list *circuit_list; /* IS-IS circuits */
+ struct flags flags;
+ struct thread *t_tick; /* LSP walker */
+ struct thread *t_remove_aged;
+ int lsp_regenerate_pending[ISIS_LEVELS];
+ struct thread *t_lsp_refresh[ISIS_LEVELS];
+
+ /*
+ * Configurables
+ */
+ struct isis_passwd area_passwd;
+ struct isis_passwd domain_passwd;
+ /* do we support dynamic hostnames? */
+ char dynhostname;
+ /* do we support new style metrics? */
+ char newmetric;
+ /* identifies the routing instance */
+ char *area_tag;
+ /* area addresses for this area */
+ struct list *area_addrs;
+ u_int16_t max_lsp_lifetime[ISIS_LEVELS];
+ char is_type; /* level-1 level-1-2 or level-2-only */
+ u_int16_t lsp_refresh[ISIS_LEVELS];
+ /* minimum time allowed before lsp retransmission */
+ u_int16_t lsp_gen_interval[ISIS_LEVELS];
+ /* min interval between between consequtive SPFs */
+ u_int16_t min_spf_interval[ISIS_LEVELS];
+ /* the percentage of LSP mtu size used, before generating a new frag */
+ int lsp_frag_threshold;
+ int ip_circuits;
+#ifdef HAVE_IPV6
+ int ipv6_circuits;
+#endif /* HAVE_IPV6 */
+ /* Counters */
+ u_int32_t circuit_state_changes;
+#ifdef TOPOLOGY_GENERATE
+ struct list *topology;
+ char topology_baseis[ISIS_SYS_ID_LEN]; /* is for the first is emulated */
+ char top_params[200]; /* FIXME: what is reasonable? */
+#endif /* TOPOLOGY_GENERATE */
+};
+
+void isis_init(void);
+struct isis_area *isis_area_lookup (char *);
+
+#define DEBUG_ADJ_PACKETS (1<<0)
+#define DEBUG_CHECKSUM_ERRORS (1<<1)
+#define DEBUG_LOCAL_UPDATES (1<<2)
+#define DEBUG_PROTOCOL_ERRORS (1<<3)
+#define DEBUG_SNP_PACKETS (1<<4)
+#define DEBUG_UPDATE_PACKETS (1<<5)
+#define DEBUG_SPF_EVENTS (1<<6)
+#define DEBUG_SPF_STATS (1<<7)
+#define DEBUG_SPF_TRIGGERS (1<<8)
+#define DEBUG_RTE_EVENTS (1<<9)
+#define DEBUG_EVENTS (1<<10)
+
+#endif /* ISISD_H */
diff --git a/isisd/iso_checksum.c b/isisd/iso_checksum.c
new file mode 100644
index 00000000..d0bb8a75
--- /dev/null
+++ b/isisd/iso_checksum.c
@@ -0,0 +1,192 @@
+/*
+ * IS-IS Rout(e)ing protocol - iso_checksum.c
+ * ISO checksum related routines
+ *
+ * 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 "iso_checksum.h"
+
+/*
+ * Calculations of the OSI checksum.
+ * ISO/IEC 8473 defines the sum as
+ *
+ * L
+ * sum a (mod 255) = 0
+ * 1 i
+ *
+ * L
+ * sum (L-i+1)a (mod 255) = 0
+ * 1 i
+ *
+ */
+
+/*
+ * Verifies that the checksum is correct.
+ * Return 0 on correct and 1 on invalid checksum.
+ * Based on Annex C.4 of ISO/IEC 8473
+ * FIXME: Check for overflow
+ */
+
+int
+iso_csum_verify (u_char *buffer, int len, uint16_t *csum)
+{
+ u_int8_t *p;
+ u_int32_t c0;
+ u_int32_t c1;
+ u_int16_t checksum;
+ int i;
+
+ p = buffer;
+ checksum = 0;
+ c0 = *csum & 0xff00;
+ c1 = *csum & 0x00ff;
+
+ /*
+ * If both are zero return correct
+ */
+ if (c0 == 0 && c1 == 0)
+ return 0;
+
+ /*
+ * If either, but not both are zero return incorrect
+ */
+ if (c0 == 0 || c1 == 0)
+ return 1;
+
+ /*
+ * Otherwise initialize to zero and calculate...
+ */
+ c0 = 0;
+ c1 = 0;
+
+ for (i = 0; i < len; i++) {
+ c0 = c0 + *(p++);
+ c1 += c0;
+ }
+
+ c0 = c0 % 255;
+ c1 = c1 % 255;
+
+ if ( c0 == 0 && c1 == 0)
+ 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
+ * we will not overflow until about length of 6000,
+ * which is the answer to (255+255n)*n/2 > 2^32
+ * so if we have a length of over 5000 we will return zero (for now)
+ */
+#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;
+
+ checksum = 0;
+
+ /*
+ * Zero the csum in the packet.
+ */
+ csum = (u_int16_t*)(buffer + n);
+ *(csum) = checksum;
+
+ /* for the limitation of our implementation */
+ if (len > 5000) {
+ return 0;
+ }
+
+ p = buffer;
+ c0 = 0;
+ c1 = 0;
+
+ for (i = 0; i < len; i++) {
+ c0 = c0 + *(p++);
+ c1 += c0;
+ }
+
+ c0 = c0 % 255;
+ c1 = c1 % 255;
+
+ mul = (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 = 255;
+
+ x &= 0x00FF;
+
+ checksum = ((y << 8) | x);
+
+#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;
+}
+
+
+int
+iso_csum_modify (u_char *buffer, int len, uint16_t *csum)
+{
+
+ return 0;
+}
+
+
diff --git a/isisd/iso_checksum.h b/isisd/iso_checksum.h
new file mode 100644
index 00000000..cf600a86
--- /dev/null
+++ b/isisd/iso_checksum.h
@@ -0,0 +1,29 @@
+/*
+ * IS-IS Rout(e)ing protocol - iso_checksum.c
+ * ISO checksum related routines
+ *
+ * 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.
+ */
+#ifndef _ZEBRA_ISO_CSUM_H
+#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 --git a/isisd/modified/Makefile.am b/isisd/modified/Makefile.am
new file mode 100644
index 00000000..65ba16bf
--- /dev/null
+++ b/isisd/modified/Makefile.am
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in.
+
+SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @ISISD@ \
+ @VTYSH@ doc
+
+EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \
+ vtysh/Makefile.am update-autotools
+
+dist-hook:
+ mkdir $(distdir)/tools
+ cp -p $(srcdir)/tools/*.pl $(distdir)/tools
+ cp -p $(srcdir)/tools/*.el $(distdir)/tools
+ cp -p $(srcdir)/tools/*.cgi $(distdir)/tools
+ mkdir $(distdir)/init
+ mkdir $(distdir)/init/redhat
+ cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat
+ cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat
diff --git a/isisd/modified/Makefile.in b/isisd/modified/Makefile.in
new file mode 100644
index 00000000..6e136178
--- /dev/null
+++ b/isisd/modified/Makefile.in
@@ -0,0 +1,462 @@
+# Makefile.in generated by automake 1.6.2 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+
+EXEEXT = @EXEEXT@
+OBJEXT = @OBJEXT@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+AMTAR = @AMTAR@
+AR = @AR@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CPP = @CPP@
+CURSES = @CURSES@
+DEPDIR = @DEPDIR@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+INCLUDES = @INCLUDES@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+ISISD = @ISISD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LIBPAM = @LIBPAM@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @ISISD@ \
+ @VTYSH@ doc
+
+
+EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \
+ vtysh/Makefile.am update-autotools
+
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+DIST_SOURCES =
+
+RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
+ uninstall-info-recursive all-recursive install-data-recursive \
+ install-exec-recursive installdirs-recursive install-recursive \
+ uninstall-recursive check-recursive installcheck-recursive
+DIST_COMMON = README AUTHORS COPYING COPYING.LIB ChangeLog INSTALL \
+ Makefile.am Makefile.in NEWS TODO acconfig.h aclocal.m4 \
+ config.guess config.h.in config.sub configure configure.in \
+ depcomp install-sh missing mkinstalldirs
+DIST_SUBDIRS = $(SUBDIRS)
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)
+
+$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+$(ACLOCAL_M4): configure.in
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+
+$(srcdir)/config.h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h
+ cd $(top_srcdir) && $(AUTOHEADER)
+ touch $(srcdir)/config.h.in
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = .
+distdir = $(PACKAGE)-$(VERSION)
+
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+
+GZIP_ENV = --best
+distcleancheck_listfiles = find . -type f -print
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ $(mkinstalldirs) $(distdir)/vtysh
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" \
+ distdir=../$(distdir)/$$subdir \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="${top_distdir}" distdir="$(distdir)" \
+ dist-hook
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ $(am__remove_distdir)
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf -
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/=inst && pwd` \
+ && cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && (test `find $$dc_install_base -type f -print | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ find $$dc_install_base -type f -print ; \
+ exit 1; } >&2 ) \
+ && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \
+ && rm -f $(distdir).tar.gz \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @echo "$(distdir).tar.gz is ready for distribution" | \
+ sed 'h;s/./=/g;p;x;p;x'
+distcleancheck: distclean
+ if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf autom4te.cache
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \
+ clean-generic clean-recursive dist dist-all dist-gzip distcheck \
+ distclean distclean-generic distclean-hdr distclean-recursive \
+ distclean-tags distcleancheck distdir dvi dvi-am dvi-recursive \
+ info info-am info-recursive install install-am install-data \
+ install-data-am install-data-recursive install-exec \
+ install-exec-am install-exec-recursive install-info \
+ install-info-am install-info-recursive install-man \
+ install-recursive install-strip installcheck installcheck-am \
+ installdirs installdirs-am installdirs-recursive \
+ maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-generic \
+ mostlyclean-recursive tags tags-recursive uninstall \
+ uninstall-am uninstall-info-am uninstall-info-recursive \
+ uninstall-recursive
+
+
+dist-hook:
+ mkdir $(distdir)/tools
+ cp -p $(srcdir)/tools/*.pl $(distdir)/tools
+ cp -p $(srcdir)/tools/*.el $(distdir)/tools
+ cp -p $(srcdir)/tools/*.cgi $(distdir)/tools
+ mkdir $(distdir)/init
+ mkdir $(distdir)/init/redhat
+ cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat
+ cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/isisd/modified/README b/isisd/modified/README
new file mode 100644
index 00000000..0b299532
--- /dev/null
+++ b/isisd/modified/README
@@ -0,0 +1,4 @@
+cp config.h.in acconfig.h configure.in Makefile.am Makefile.in configure ../../
+cp command.h command.c memory.c memory.h log.h log.c vty.c ../../lib/
+cp thread.h thread.c zebra.h ../../lib
+cp rib.c ../../zebra/
diff --git a/isisd/modified/acconfig.h b/isisd/modified/acconfig.h
new file mode 100644
index 00000000..002666ba
--- /dev/null
+++ b/isisd/modified/acconfig.h
@@ -0,0 +1,162 @@
+/* accconfig.h -- `autoheader' will generate config.h.in for zebra.
+ Copyright (C) 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> */
+
+/* Version of GNU Zebra */
+#undef VERSION
+
+/* Solaris on x86. */
+#undef SOLARIS_X86
+
+/* Package name of GNU Zebra */
+#undef PACKAGE
+
+/* Define if host is GNU/Linux */
+#undef GNU_LINUX
+
+/* Define if you have the AF_ROUTE socket. */
+#undef HAVE_AF_ROUTE
+
+/* Define if you have the inet_aton function. */
+#undef HAVE_INET_ATON
+
+/* Define if you have the inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define if you have the inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define if you have the setproctitle function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define if you have ipv6 stack. */
+#undef HAVE_IPV6
+
+/* Define if you wish to support ipv6 router advertisment. */
+/* #undef HAVE_RTADV */
+
+/* whether system has GNU regex */
+#undef HAVE_GNU_REGEX
+
+/* whether system has SNMP library */
+#undef HAVE_SNMP
+
+/* whether sockaddr has a sa_len field */
+#undef HAVE_SA_LEN
+
+/* whether sockaddr_in has a sin_len field */
+#undef HAVE_SIN_LEN
+
+/* whether sockaddr_un has a sun_len field */
+#undef HAVE_SUN_LEN
+
+/* whether sockaddr_in6 has a sin6_scope_id field */
+#undef HAVE_SIN6_SCOPE_ID
+
+/* Define if there is socklen_t. */
+#undef HAVE_SOCKLEN_T
+
+/* Define if there is sockaddr_dl structure. */
+#undef HAVE_SOCKADDR_DL
+
+/* Define if there is ifaliasreq structure. */
+#undef HAVE_IFALIASREQ
+
+/* Define if there is in6_aliasreq structure. */
+#undef HAVE_IN6_ALIASREQ
+
+/* Define if there is rt_addrinfo structure. */
+#undef HAVE_RT_ADDRINFO
+
+/* Define if there is in_pktinfo structure. */
+#undef HAVE_INPKTINFO
+
+/* Define if you have the getrusage function. */
+#undef HAVE_RUSAGE
+
+/* Define if /proc/net/dev exists. */
+#undef HAVE_PROC_NET_DEV
+
+/* Define if /proc/net/if_inet6 exists. */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define if NET_RT_IFLIST exists in sys/socket.h. */
+#undef HAVE_NET_RT_IFLIST
+
+/* Define if you have INRIA ipv6 stack. */
+#undef INRIA_IPV6
+
+/* Define if you have KAME project ipv6 stack. */
+#undef KAME
+
+/* Define if you have Linux ipv6 stack. */
+#undef LINUX_IPV6
+
+/* Define if you have NRL ipv6 stack. */
+#undef NRL
+
+/* Define if you have BSDI NRL IPv6 stack. */
+#undef BSDI_NRL
+
+/* Define if one-vty option is specified. */
+#undef VTYSH
+
+/* Define if interface aliases don't have distinct indeces */
+#undef HAVE_BROKEN_ALIASES
+
+/* Define if disable-bgp-announce option is specified. */
+#undef DISABLE_BGP_ANNOUNCE
+
+/* PAM support */
+#undef USE_PAM
+
+/* TCP/IP communication between zebra and protocol daemon. */
+#undef HAVE_TCP_ZEBRA
+
+/* The OSPF NSSA option (RFC1587). */
+#undef HAVE_NSSA
+
+/* The OSPF Opaque LSA option (RFC2370). */
+#undef HAVE_OPAQUE_LSA
+
+/* Traffic Engineering Extension to OSPF
+ (draft-katz-yeung-ospf-traffic-06.txt). */
+#undef HAVE_OSPF_TE
+
+/* Linux netlink. */
+#undef HAVE_NETLINK
+
+/* PATHS */
+#undef PATH_ZEBRA_PID
+#undef PATH_RIPD_PID
+#undef PATH_RIPNGD_PID
+#undef PATH_BGPD_PID
+#undef PATH_OSPFD_PID
+#undef PATH_OSPF6D_PID
+#undef PATH_ISISD_PID
+
+/* Define if Solaris */
+#undef SUNOS_5
+
+/* Define if FreeBSD 3.2 */
+#undef FREEBSD_32
+
+/* Define if OpenBSD */
+#undef OPEN_BSD
+
+#ifdef HAVE_IPV6
+#ifdef KAME
+#ifndef INET6
+#define INET6
+#endif /* INET6 */
+#endif /* KAME */
+#endif /* HAVE_IPV6 */
+
+#ifdef SUNOS_5
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+typedef unsigned short u_int8_t;
+#endif /* SUNOS_5 */
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
diff --git a/isisd/modified/command.c b/isisd/modified/command.c
new file mode 100644
index 00000000..5c18fd94
--- /dev/null
+++ b/isisd/modified/command.c
@@ -0,0 +1,2983 @@
+/* Command interpreter routine for virtual terminal [aka TeletYpe]
+ Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; either version 2, or (at your
+option) any later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "log.h"
+#include "version.h"
+
+/* Command vector which includes some level of command lists. Normally
+ each daemon maintains each own cmdvec. */
+vector cmdvec;
+
+/* Host information structure. */
+struct host host;
+
+/* Default motd string. */
+char *default_motd =
+"\r\n\
+Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\
+Copyright 1996-2002 Kunihiro Ishiguro.\r\n\
+\r\n";
+
+/* Standard command node structures. */
+struct cmd_node auth_node =
+{
+ AUTH_NODE,
+ "Password: ",
+};
+
+struct cmd_node view_node =
+{
+ VIEW_NODE,
+ "%s> ",
+};
+
+struct cmd_node auth_enable_node =
+{
+ AUTH_ENABLE_NODE,
+ "Password: ",
+};
+
+struct cmd_node enable_node =
+{
+ ENABLE_NODE,
+ "%s# ",
+};
+
+struct cmd_node config_node =
+{
+ CONFIG_NODE,
+ "%s(config)# ",
+ 1
+};
+
+/* Utility function to concatenate argv argument into a single string
+ with inserting ' ' character between each argument. */
+char *
+argv_concat (char **argv, int argc, int shift)
+{
+ int i;
+ int len;
+ int index;
+ char *str;
+
+ str = NULL;
+ index = 0;
+
+ for (i = shift; i < argc; i++)
+ {
+ len = strlen (argv[i]);
+
+ if (i == shift)
+ {
+ str = XSTRDUP (MTYPE_TMP, argv[i]);
+ index = len;
+ }
+ else
+ {
+ str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
+ str[index++] = ' ';
+ memcpy (str + index, argv[i], len);
+ index += len;
+ str[index] = '\0';
+ }
+ }
+ return str;
+}
+
+/* Install top node of command vector. */
+void
+install_node (struct cmd_node *node,
+ int (*func) (struct vty *))
+{
+ vector_set_index (cmdvec, node->node, node);
+ node->func = func;
+ node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
+}
+
+/* Compare two command's string. Used in sort_node (). */
+int
+cmp_node (const void *p, const void *q)
+{
+ struct cmd_element *a = *(struct cmd_element **)p;
+ struct cmd_element *b = *(struct cmd_element **)q;
+
+ return strcmp (a->string, b->string);
+}
+
+int
+cmp_desc (const void *p, const void *q)
+{
+ struct desc *a = *(struct desc **)p;
+ struct desc *b = *(struct desc **)q;
+
+ return strcmp (a->cmd, b->cmd);
+}
+
+/* Sort each node's command element according to command string. */
+void
+sort_node ()
+{
+ int i, j;
+ struct cmd_node *cnode;
+ vector descvec;
+ struct cmd_element *cmd_element;
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((cnode = vector_slot (cmdvec, i)) != NULL)
+ {
+ vector cmd_vector = cnode->cmd_vector;
+ qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
+
+ for (j = 0; j < vector_max (cmd_vector); j++)
+ if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+ {
+ descvec = vector_slot (cmd_element->strvec,
+ vector_max (cmd_element->strvec) - 1);
+ qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
+ }
+ }
+}
+
+/* Breaking up string into each command piece. I assume given
+ character is separated by a space character. Return value is a
+ vector which includes char ** data element. */
+vector
+cmd_make_strvec (char *string)
+{
+ char *cp, *start, *token;
+ int strlen;
+ vector strvec;
+
+ if (string == NULL)
+ return NULL;
+
+ cp = string;
+
+ /* Skip white spaces. */
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ /* Return if there is only white spaces */
+ if (*cp == '\0')
+ return NULL;
+
+ if (*cp == '!' || *cp == '#')
+ return NULL;
+
+ /* Prepare return vector. */
+ strvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Copy each command piece and set into vector. */
+ while (1)
+ {
+ start = cp;
+ while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
+ *cp != '\0')
+ cp++;
+ strlen = cp - start;
+ token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+ memcpy (token, start, strlen);
+ *(token + strlen) = '\0';
+ vector_set (strvec, token);
+
+ while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
+ *cp != '\0')
+ cp++;
+
+ if (*cp == '\0')
+ return strvec;
+ }
+}
+
+/* Free allocated string vector. */
+void
+cmd_free_strvec (vector v)
+{
+ int i;
+ char *cp;
+
+ if (!v)
+ return;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((cp = vector_slot (v, i)) != NULL)
+ XFREE (MTYPE_STRVEC, cp);
+
+ vector_free (v);
+}
+
+/* Fetch next description. Used in cmd_make_descvec(). */
+char *
+cmd_desc_str (char **string)
+{
+ char *cp, *start, *token;
+ int strlen;
+
+ cp = *string;
+
+ if (cp == NULL)
+ return NULL;
+
+ /* Skip white spaces. */
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ /* Return if there is only white spaces */
+ if (*cp == '\0')
+ return NULL;
+
+ start = cp;
+
+ while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
+ cp++;
+
+ strlen = cp - start;
+ token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+ memcpy (token, start, strlen);
+ *(token + strlen) = '\0';
+
+ *string = cp;
+
+ return token;
+}
+
+/* New string vector. */
+vector
+cmd_make_descvec (char *string, char *descstr)
+{
+ int multiple = 0;
+ char *sp;
+ char *token;
+ int len;
+ char *cp;
+ char *dp;
+ vector allvec;
+ vector strvec = NULL;
+ struct desc *desc;
+
+ cp = string;
+ dp = descstr;
+
+ if (cp == NULL)
+ return NULL;
+
+ allvec = vector_init (VECTOR_MIN_SIZE);
+
+ while (1)
+ {
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ if (*cp == '(')
+ {
+ multiple = 1;
+ cp++;
+ }
+ if (*cp == ')')
+ {
+ multiple = 0;
+ cp++;
+ }
+ if (*cp == '|')
+ {
+ if (! multiple)
+ {
+ fprintf (stderr, "Command parse error!: %s\n", string);
+ exit (1);
+ }
+ cp++;
+ }
+
+ while (isspace ((int) *cp) && *cp != '\0')
+ cp++;
+
+ if (*cp == '(')
+ {
+ multiple = 1;
+ cp++;
+ }
+
+ if (*cp == '\0')
+ return allvec;
+
+ sp = cp;
+
+ while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
+ cp++;
+
+ len = cp - sp;
+
+ token = XMALLOC (MTYPE_STRVEC, len + 1);
+ memcpy (token, sp, len);
+ *(token + len) = '\0';
+
+ desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
+ desc->cmd = token;
+ desc->str = cmd_desc_str (&dp);
+
+ if (multiple)
+ {
+ if (multiple == 1)
+ {
+ strvec = vector_init (VECTOR_MIN_SIZE);
+ vector_set (allvec, strvec);
+ }
+ multiple++;
+ }
+ else
+ {
+ strvec = vector_init (VECTOR_MIN_SIZE);
+ vector_set (allvec, strvec);
+ }
+ vector_set (strvec, desc);
+ }
+}
+
+/* Count mandantory string vector size. This is to determine inputed
+ command has enough command length. */
+int
+cmd_cmdsize (vector strvec)
+{
+ int i;
+ char *str;
+ int size = 0;
+ vector descvec;
+
+ for (i = 0; i < vector_max (strvec); i++)
+ {
+ descvec = vector_slot (strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+
+ str = desc->cmd;
+
+ if (str == NULL || CMD_OPTION (str))
+ return size;
+ else
+ size++;
+ }
+ else
+ size++;
+ }
+ return size;
+}
+
+/* Return prompt character of specified node. */
+char *
+cmd_prompt (enum node_type node)
+{
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, node);
+ return cnode->prompt;
+}
+
+/* Install a command into a node. */
+void
+install_element (enum node_type ntype, struct cmd_element *cmd)
+{
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, ntype);
+
+ if (cnode == NULL)
+ {
+ fprintf (stderr, "Command node %d doesn't exist, please check it\n",
+ ntype);
+ exit (1);
+ }
+
+ vector_set (cnode->cmd_vector, cmd);
+
+ cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
+ cmd->cmdsize = cmd_cmdsize (cmd->strvec);
+}
+
+static unsigned char itoa64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+to64(char *s, long v, int n)
+{
+ while (--n >= 0)
+ {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+char *zencrypt (char *passwd)
+{
+ char salt[6];
+ struct timeval tv;
+ char *crypt (const char *, const char *);
+
+ gettimeofday(&tv,0);
+
+ to64(&salt[0], random(), 3);
+ to64(&salt[3], tv.tv_usec, 3);
+ salt[5] = '\0';
+
+ return crypt (passwd, salt);
+}
+
+/* This function write configuration of this host. */
+int
+config_write_host (struct vty *vty)
+{
+ if (host.name)
+ vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
+
+ if (host.encrypt)
+ {
+ if (host.password_encrypt)
+ vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
+ if (host.enable_encrypt)
+ vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
+ }
+ else
+ {
+ if (host.password)
+ vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
+ if (host.enable)
+ vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
+ }
+
+ if (host.logfile)
+ vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
+
+ if (host.log_stdout)
+ vty_out (vty, "log stdout%s", VTY_NEWLINE);
+
+ if (host.log_syslog)
+ vty_out (vty, "log syslog%s", VTY_NEWLINE);
+
+ if (zlog_default->maskpri != LOG_DEBUG)
+ vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
+
+ if (zlog_default->record_priority == 1)
+ vty_out (vty, "log record-priority%s", VTY_NEWLINE);
+
+ if (host.advanced)
+ vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
+
+ if (host.encrypt)
+ vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
+
+ if (host.lines >= 0)
+ vty_out (vty, "service terminal-length %d%s", host.lines,
+ VTY_NEWLINE);
+
+ if (! host.motd)
+ vty_out (vty, "no banner motd%s", VTY_NEWLINE);
+
+ return 1;
+}
+
+/* Utility function for getting command vector. */
+vector
+cmd_node_vector (vector v, enum node_type ntype)
+{
+ struct cmd_node *cnode = vector_slot (v, ntype);
+ return cnode->cmd_vector;
+}
+
+/* Filter command vector by symbol */
+int
+cmd_filter_by_symbol (char *command, char *symbol)
+{
+ int i, lim;
+
+ if (strcmp (symbol, "IPV4_ADDRESS") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ if (strcmp (symbol, "STRING") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ if (strcmp (symbol, "IFNAME") == 0)
+ {
+ i = 0;
+ lim = strlen (command);
+ while (i < lim)
+ {
+ if (! isalnum ((int) command[i]))
+ return 1;
+ i++;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/* Completion match types. */
+enum match_type
+{
+ no_match,
+ extend_match,
+ ipv4_prefix_match,
+ ipv4_match,
+ ipv6_prefix_match,
+ ipv6_match,
+ range_match,
+ vararg_match,
+ partly_match,
+ exact_match
+};
+
+enum match_type
+cmd_ipv4_match (char *str)
+{
+ char *sp;
+ int dots = 0, nums = 0;
+ char buf[4];
+
+ if (str == NULL)
+ return partly_match;
+
+ for (;;)
+ {
+ memset (buf, 0, sizeof (buf));
+ sp = str;
+ while (*str != '\0')
+ {
+ if (*str == '.')
+ {
+ if (dots >= 3)
+ return no_match;
+
+ if (*(str + 1) == '.')
+ return no_match;
+
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ dots++;
+ break;
+ }
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (str - sp > 3)
+ return no_match;
+
+ strncpy (buf, sp, str - sp);
+ if (atoi (buf) > 255)
+ return no_match;
+
+ nums++;
+
+ if (*str == '\0')
+ break;
+
+ str++;
+ }
+
+ if (nums < 4)
+ return partly_match;
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv4_prefix_match (char *str)
+{
+ char *sp;
+ int dots = 0;
+ char buf[4];
+
+ if (str == NULL)
+ return partly_match;
+
+ for (;;)
+ {
+ memset (buf, 0, sizeof (buf));
+ sp = str;
+ while (*str != '\0' && *str != '/')
+ {
+ if (*str == '.')
+ {
+ if (dots == 3)
+ return no_match;
+
+ if (*(str + 1) == '.' || *(str + 1) == '/')
+ return no_match;
+
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ dots++;
+ break;
+ }
+
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (str - sp > 3)
+ return no_match;
+
+ strncpy (buf, sp, str - sp);
+ if (atoi (buf) > 255)
+ return no_match;
+
+ if (dots == 3)
+ {
+ if (*str == '/')
+ {
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ str++;
+ break;
+ }
+ else if (*str == '\0')
+ return partly_match;
+ }
+
+ if (*str == '\0')
+ return partly_match;
+
+ str++;
+ }
+
+ sp = str;
+ while (*str != '\0')
+ {
+ if (!isdigit ((int) *str))
+ return no_match;
+
+ str++;
+ }
+
+ if (atoi (sp) > 32)
+ return no_match;
+
+ return exact_match;
+}
+
+#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
+#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
+#define STATE_START 1
+#define STATE_COLON 2
+#define STATE_DOUBLE 3
+#define STATE_ADDR 4
+#define STATE_DOT 5
+#define STATE_SLASH 6
+#define STATE_MASK 7
+
+enum match_type
+cmd_ipv6_match (char *str)
+{
+ int state = STATE_START;
+ int colons = 0, nums = 0, double_colon = 0;
+ char *sp = NULL;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_ADDR_STR) != strlen (str))
+ return no_match;
+
+ while (*str != '\0')
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (*str == ':')
+ {
+ if (*(str + 1) != ':' && *(str + 1) != '\0')
+ return no_match;
+ colons--;
+ state = STATE_COLON;
+ }
+ else
+ {
+ sp = str;
+ state = STATE_ADDR;
+ }
+
+ continue;
+ case STATE_COLON:
+ colons++;
+ if (*(str + 1) == ':')
+ state = STATE_DOUBLE;
+ else
+ {
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+ break;
+ case STATE_DOUBLE:
+ if (double_colon)
+ return no_match;
+
+ if (*(str + 1) == ':')
+ return no_match;
+ else
+ {
+ if (*(str + 1) != '\0')
+ colons++;
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+
+ double_colon++;
+ nums++;
+ break;
+ case STATE_ADDR:
+ if (*(str + 1) == ':' || *(str + 1) == '\0')
+ {
+ if (str - sp > 3)
+ return no_match;
+
+ nums++;
+ state = STATE_COLON;
+ }
+ if (*(str + 1) == '.')
+ state = STATE_DOT;
+ break;
+ case STATE_DOT:
+ state = STATE_ADDR;
+ break;
+ default:
+ break;
+ }
+
+ if (nums > 8)
+ return no_match;
+
+ if (colons > 7)
+ return no_match;
+
+ str++;
+ }
+
+#if 0
+ if (nums < 11)
+ return partly_match;
+#endif /* 0 */
+
+ return exact_match;
+}
+
+enum match_type
+cmd_ipv6_prefix_match (char *str)
+{
+ int state = STATE_START;
+ int colons = 0, nums = 0, double_colon = 0;
+ int mask;
+ char *sp = NULL;
+ char *endptr = NULL;
+
+ if (str == NULL)
+ return partly_match;
+
+ if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
+ return no_match;
+
+ while (*str != '\0' && state != STATE_MASK)
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (*str == ':')
+ {
+ if (*(str + 1) != ':' && *(str + 1) != '\0')
+ return no_match;
+ colons--;
+ state = STATE_COLON;
+ }
+ else
+ {
+ sp = str;
+ state = STATE_ADDR;
+ }
+
+ continue;
+ case STATE_COLON:
+ colons++;
+ if (*(str + 1) == '/')
+ return no_match;
+ else if (*(str + 1) == ':')
+ state = STATE_DOUBLE;
+ else
+ {
+ sp = str + 1;
+ state = STATE_ADDR;
+ }
+ break;
+ case STATE_DOUBLE:
+ if (double_colon)
+ return no_match;
+
+ if (*(str + 1) == ':')
+ return no_match;
+ else
+ {
+ if (*(str + 1) != '\0' && *(str + 1) != '/')
+ colons++;
+ sp = str + 1;
+
+ if (*(str + 1) == '/')
+ state = STATE_SLASH;
+ else
+ state = STATE_ADDR;
+ }
+
+ double_colon++;
+ nums += 1;
+ break;
+ case STATE_ADDR:
+ if (*(str + 1) == ':' || *(str + 1) == '.'
+ || *(str + 1) == '\0' || *(str + 1) == '/')
+ {
+ if (str - sp > 3)
+ return no_match;
+
+ for (; sp <= str; sp++)
+ if (*sp == '/')
+ return no_match;
+
+ nums++;
+
+ if (*(str + 1) == ':')
+ state = STATE_COLON;
+ else if (*(str + 1) == '.')
+ state = STATE_DOT;
+ else if (*(str + 1) == '/')
+ state = STATE_SLASH;
+ }
+ break;
+ case STATE_DOT:
+ state = STATE_ADDR;
+ break;
+ case STATE_SLASH:
+ if (*(str + 1) == '\0')
+ return partly_match;
+
+ state = STATE_MASK;
+ break;
+ default:
+ break;
+ }
+
+ if (nums > 11)
+ return no_match;
+
+ if (colons > 7)
+ return no_match;
+
+ str++;
+ }
+
+ if (state < STATE_MASK)
+ return partly_match;
+
+ mask = strtol (str, &endptr, 10);
+ if (*endptr != '\0')
+ return no_match;
+
+ if (mask < 0 || mask > 128)
+ return no_match;
+
+/* I don't know why mask < 13 makes command match partly.
+ Forgive me to make this comments. I Want to set static default route
+ because of lack of function to originate default in ospf6d; sorry
+ yasu
+ if (mask < 13)
+ return partly_match;
+*/
+
+ return exact_match;
+}
+
+#define DECIMAL_STRLEN_MAX 10
+
+int
+cmd_range_match (char *range, char *str)
+{
+ char *p;
+ char buf[DECIMAL_STRLEN_MAX + 1];
+ char *endptr = NULL;
+ unsigned long min, max, val;
+
+ if (str == NULL)
+ return 1;
+
+ val = strtoul (str, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ range++;
+ p = strchr (range, '-');
+ if (p == NULL)
+ return 0;
+ if (p - range > DECIMAL_STRLEN_MAX)
+ return 0;
+ strncpy (buf, range, p - range);
+ buf[p - range] = '\0';
+ min = strtoul (buf, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ range = p + 1;
+ p = strchr (range, '>');
+ if (p == NULL)
+ return 0;
+ if (p - range > DECIMAL_STRLEN_MAX)
+ return 0;
+ strncpy (buf, range, p - range);
+ buf[p - range] = '\0';
+ max = strtoul (buf, &endptr, 10);
+ if (*endptr != '\0')
+ return 0;
+
+ if (val < min || val > max)
+ return 0;
+
+ return 1;
+}
+
+/* Make completion match and return match type flag. */
+enum match_type
+cmd_filter_by_completion (char *command, vector v, int index)
+{
+ int i;
+ char *str;
+ struct cmd_element *cmd_element;
+ enum match_type match_type;
+ vector descvec;
+ struct desc *desc;
+
+ match_type = no_match;
+
+ /* If command and cmd_element string does not match set NULL to vector */
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ if (index >= vector_max (cmd_element->strvec))
+ vector_slot (v, i) = NULL;
+ else
+ {
+ int j;
+ int matched = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ {
+ if (match_type < vararg_match)
+ match_type = vararg_match;
+ matched++;
+ }
+ else if (CMD_RANGE (str))
+ {
+ if (cmd_range_match (str, command))
+ {
+ if (match_type < range_match)
+ match_type = range_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV6 (str))
+ {
+ if (cmd_ipv6_match (command))
+ {
+ if (match_type < ipv6_match)
+ match_type = ipv6_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV6_PREFIX (str))
+ {
+ if (cmd_ipv6_prefix_match (command))
+ {
+ if (match_type < ipv6_prefix_match)
+ match_type = ipv6_prefix_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV4 (str))
+ {
+ if (cmd_ipv4_match (command))
+ {
+ if (match_type < ipv4_match)
+ match_type = ipv4_match;
+
+ matched++;
+ }
+ }
+ else if (CMD_IPV4_PREFIX (str))
+ {
+ if (cmd_ipv4_prefix_match (command))
+ {
+ if (match_type < ipv4_prefix_match)
+ match_type = ipv4_prefix_match;
+ matched++;
+ }
+ }
+ else
+ /* Check is this point's argument optional ? */
+ if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ {
+ if (match_type < extend_match)
+ match_type = extend_match;
+ matched++;
+ }
+ else if (strncmp (command, str, strlen (command)) == 0)
+ {
+ if (strcmp (command, str) == 0)
+ match_type = exact_match;
+ else
+ {
+ if (match_type < partly_match)
+ match_type = partly_match;
+ }
+ matched++;
+ }
+ }
+ if (! matched)
+ vector_slot (v, i) = NULL;
+ }
+ }
+ return match_type;
+}
+
+/* Filter vector by command character with index. */
+enum match_type
+cmd_filter_by_string (char *command, vector v, int index)
+{
+ int i;
+ char *str;
+ struct cmd_element *cmd_element;
+ enum match_type match_type;
+ vector descvec;
+ struct desc *desc;
+
+ match_type = no_match;
+
+ /* If command and cmd_element string does not match set NULL to vector */
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ /* If given index is bigger than max string vector of command,
+ set NULL*/
+ if (index >= vector_max (cmd_element->strvec))
+ vector_slot (v, i) = NULL;
+ else
+ {
+ int j;
+ int matched = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ {
+ if (match_type < vararg_match)
+ match_type = vararg_match;
+ matched++;
+ }
+ else if (CMD_RANGE (str))
+ {
+ if (cmd_range_match (str, command))
+ {
+ if (match_type < range_match)
+ match_type = range_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV6 (str))
+ {
+ if (cmd_ipv6_match (command) == exact_match)
+ {
+ if (match_type < ipv6_match)
+ match_type = ipv6_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV6_PREFIX (str))
+ {
+ if (cmd_ipv6_prefix_match (command) == exact_match)
+ {
+ if (match_type < ipv6_prefix_match)
+ match_type = ipv6_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV4 (str))
+ {
+ if (cmd_ipv4_match (command) == exact_match)
+ {
+ if (match_type < ipv4_match)
+ match_type = ipv4_match;
+ matched++;
+ }
+ }
+ else if (CMD_IPV4_PREFIX (str))
+ {
+ if (cmd_ipv4_prefix_match (command) == exact_match)
+ {
+ if (match_type < ipv4_prefix_match)
+ match_type = ipv4_prefix_match;
+ matched++;
+ }
+ }
+ else if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ {
+ if (match_type < extend_match)
+ match_type = extend_match;
+ matched++;
+ }
+ else
+ {
+ if (strcmp (command, str) == 0)
+ {
+ match_type = exact_match;
+ matched++;
+ }
+ }
+ }
+ if (! matched)
+ vector_slot (v, i) = NULL;
+ }
+ }
+ return match_type;
+}
+
+/* Check ambiguous match */
+int
+is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
+{
+ int i;
+ int j;
+ char *str = NULL;
+ struct cmd_element *cmd_element;
+ char *matched = NULL;
+ vector descvec;
+ struct desc *desc;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((cmd_element = vector_slot (v, i)) != NULL)
+ {
+ int match = 0;
+
+ descvec = vector_slot (cmd_element->strvec, index);
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ enum match_type ret;
+
+ desc = vector_slot (descvec, j);
+ str = desc->cmd;
+
+ switch (type)
+ {
+ case exact_match:
+ if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
+ && strcmp (command, str) == 0)
+ match++;
+ break;
+ case partly_match:
+ if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
+ && strncmp (command, str, strlen (command)) == 0)
+ {
+ if (matched && strcmp (matched, str) != 0)
+ return 1; /* There is ambiguous match. */
+ else
+ matched = str;
+ match++;
+ }
+ break;
+ case range_match:
+ if (cmd_range_match (str, command))
+ {
+ if (matched && strcmp (matched, str) != 0)
+ return 1;
+ else
+ matched = str;
+ match++;
+ }
+ break;
+ case ipv6_match:
+ if (CMD_IPV6 (str))
+ match++;
+ break;
+ case ipv6_prefix_match:
+ if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
+ {
+ if (ret == partly_match)
+ return 2; /* There is incomplete match. */
+
+ match++;
+ }
+ break;
+ case ipv4_match:
+ if (CMD_IPV4 (str))
+ match++;
+ break;
+ case ipv4_prefix_match:
+ if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
+ {
+ if (ret == partly_match)
+ return 2; /* There is incomplete match. */
+
+ match++;
+ }
+ break;
+ case extend_match:
+ if (CMD_OPTION (str) || CMD_VARIABLE (str))
+ match++;
+ break;
+ case no_match:
+ default:
+ break;
+ }
+ }
+ if (! match)
+ vector_slot (v, i) = NULL;
+ }
+ return 0;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+char *
+cmd_entry_function (char *src, char *dst)
+{
+ /* Skip variable arguments. */
+ if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
+ CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
+ return NULL;
+
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ /* Matched with input string. */
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+
+ return NULL;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+/* This version will return the dst string always if it is
+ CMD_VARIABLE for '?' key processing */
+char *
+cmd_entry_function_desc (char *src, char *dst)
+{
+ if (CMD_VARARG (dst))
+ return dst;
+
+ if (CMD_RANGE (dst))
+ {
+ if (cmd_range_match (dst, src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV6 (dst))
+ {
+ if (cmd_ipv6_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV6_PREFIX (dst))
+ {
+ if (cmd_ipv6_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV4 (dst))
+ {
+ if (cmd_ipv4_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ if (CMD_IPV4_PREFIX (dst))
+ {
+ if (cmd_ipv4_prefix_match (src))
+ return dst;
+ else
+ return NULL;
+ }
+
+ /* Optional or variable commands always match on '?' */
+ if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
+ return dst;
+
+ /* In case of 'command \t', given src is NULL string. */
+ if (src == NULL)
+ return dst;
+
+ if (strncmp (src, dst, strlen (src)) == 0)
+ return dst;
+ else
+ return NULL;
+}
+
+/* Check same string element existence. If it isn't there return
+ 1. */
+int
+cmd_unique_string (vector v, char *str)
+{
+ int i;
+ char *match;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((match = vector_slot (v, i)) != NULL)
+ if (strcmp (match, str) == 0)
+ return 0;
+ return 1;
+}
+
+/* Compare string to description vector. If there is same string
+ return 1 else return 0. */
+int
+desc_unique_string (vector v, char *str)
+{
+ int i;
+ struct desc *desc;
+
+ for (i = 0; i < vector_max (v); i++)
+ if ((desc = vector_slot (v, i)) != NULL)
+ if (strcmp (desc->cmd, str) == 0)
+ return 1;
+ return 0;
+}
+
+/* '?' describe command support. */
+vector
+cmd_describe_command (vector vline, struct vty *vty, int *status)
+{
+ int i;
+ vector cmd_vector;
+#define INIT_MATCHVEC_SIZE 10
+ vector matchvec;
+ struct cmd_element *cmd_element;
+ int index;
+ static struct desc desc_cr = { "<cr>", "" };
+
+ /* Set index. */
+ index = vector_max (vline) - 1;
+
+ /* Make copy vector of current node's command vector. */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ /* Prepare match vector */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+ /* Filter commands. */
+ for (i = 0; i < index; i++)
+ {
+ enum match_type match;
+ char *command;
+ int ret;
+
+ command = vector_slot (vline, i);
+
+ match = cmd_filter_by_completion (command, cmd_vector, i);
+
+ if (match == vararg_match)
+ {
+ struct cmd_element *cmd_element;
+ vector descvec;
+ int j, k;
+
+ for (j = 0; j < vector_max (cmd_vector); j++)
+ if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+ {
+ descvec = vector_slot (cmd_element->strvec,
+ vector_max (cmd_element->strvec) - 1);
+ for (k = 0; k < vector_max (descvec); k++)
+ {
+ struct desc *desc = vector_slot (descvec, k);
+ vector_set (matchvec, desc);
+ }
+ }
+
+ vector_set (matchvec, &desc_cr);
+
+ vector_free (cmd_vector);
+
+ return matchvec;
+ }
+
+ if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_AMBIGUOUS;
+ return NULL;
+ }
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+ }
+
+ /* Prepare match vector */
+ /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
+
+ /* Make description vector. */
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+ {
+ char *string = NULL;
+ vector strvec = cmd_element->strvec;
+
+ if (index > vector_max (strvec))
+ vector_slot (cmd_vector, i) = NULL;
+ else
+ {
+ /* Check is command is completed. */
+ if (index == vector_max (strvec))
+ {
+ string = "<cr>";
+ if (! desc_unique_string (matchvec, string))
+ vector_set (matchvec, &desc_cr);
+ }
+ else
+ {
+ int j;
+ vector descvec = vector_slot (strvec, index);
+ struct desc *desc;
+
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+ string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd);
+ if (string)
+ {
+ /* Uniqueness check */
+ if (! desc_unique_string (matchvec, string))
+ vector_set (matchvec, desc);
+ }
+ }
+ }
+ }
+ }
+ vector_free (cmd_vector);
+
+ if (vector_slot (matchvec, 0) == NULL)
+ {
+ vector_free (matchvec);
+ *status= CMD_ERR_NO_MATCH;
+ }
+ else
+ *status = CMD_SUCCESS;
+
+ return matchvec;
+}
+
+/* Check LCD of matched command. */
+int
+cmd_lcd (char **matched)
+{
+ int i;
+ int j;
+ int lcd = -1;
+ char *s1, *s2;
+ char c1, c2;
+
+ if (matched[0] == NULL || matched[1] == NULL)
+ return 0;
+
+ for (i = 1; matched[i] != NULL; i++)
+ {
+ s1 = matched[i - 1];
+ s2 = matched[i];
+
+ for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
+ if (c1 != c2)
+ break;
+
+ if (lcd < 0)
+ lcd = j;
+ else
+ {
+ if (lcd > j)
+ lcd = j;
+ }
+ }
+ return lcd;
+}
+
+/* Command line completion support. */
+char **
+cmd_complete_command (vector vline, struct vty *vty, int *status)
+{
+ int i;
+ vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+#define INIT_MATCHVEC_SIZE 10
+ vector matchvec;
+ struct cmd_element *cmd_element;
+ int index = vector_max (vline) - 1;
+ char **match_str;
+ struct desc *desc;
+ vector descvec;
+ char *command;
+ int lcd;
+
+ /* First, filter by preceeding command string */
+ for (i = 0; i < index; i++)
+ {
+ enum match_type match;
+ int ret;
+
+ command = vector_slot (vline, i);
+
+ /* First try completion match, if there is exactly match return 1 */
+ match = cmd_filter_by_completion (command, cmd_vector, i);
+
+ /* If there is exact match then filter ambiguous match else check
+ ambiguousness. */
+ if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_AMBIGUOUS;
+ return NULL;
+ }
+ /*
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+ */
+ }
+
+ /* Prepare match vector. */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+ /* Now we got into completion */
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+ {
+ char *string;
+ vector strvec = cmd_element->strvec;
+
+ /* Check field length */
+ if (index >= vector_max (strvec))
+ vector_slot (cmd_vector, i) = NULL;
+ else
+ {
+ int j;
+
+ descvec = vector_slot (strvec, index);
+ for (j = 0; j < vector_max (descvec); j++)
+ {
+ desc = vector_slot (descvec, j);
+
+ if ((string = cmd_entry_function (vector_slot (vline, index),
+ desc->cmd)))
+ if (cmd_unique_string (matchvec, string))
+ vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
+ }
+ }
+ }
+
+ /* We don't need cmd_vector any more. */
+ vector_free (cmd_vector);
+
+ /* No matched command */
+ if (vector_slot (matchvec, 0) == NULL)
+ {
+ vector_free (matchvec);
+
+ /* In case of 'command \t' pattern. Do you need '?' command at
+ the end of the line. */
+ if (vector_slot (vline, index) == '\0')
+ *status = CMD_ERR_NOTHING_TODO;
+ else
+ *status = CMD_ERR_NO_MATCH;
+ return NULL;
+ }
+
+ /* Only one matched */
+ if (vector_slot (matchvec, 1) == NULL)
+ {
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+ *status = CMD_COMPLETE_FULL_MATCH;
+ return match_str;
+ }
+ /* Make it sure last element is NULL. */
+ vector_set (matchvec, NULL);
+
+ /* Check LCD of matched strings. */
+ if (vector_slot (vline, index) != NULL)
+ {
+ lcd = cmd_lcd ((char **) matchvec->index);
+
+ if (lcd)
+ {
+ int len = strlen (vector_slot (vline, index));
+
+ if (len < lcd)
+ {
+ char *lcdstr;
+
+ lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
+ memcpy (lcdstr, matchvec->index[0], lcd);
+ lcdstr[lcd] = '\0';
+
+ /* match_str = (char **) &lcdstr; */
+
+ /* Free matchvec. */
+ for (i = 0; i < vector_max (matchvec); i++)
+ {
+ if (vector_slot (matchvec, i))
+ XFREE (MTYPE_TMP, vector_slot (matchvec, i));
+ }
+ vector_free (matchvec);
+
+ /* Make new matchvec. */
+ matchvec = vector_init (INIT_MATCHVEC_SIZE);
+ vector_set (matchvec, lcdstr);
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+
+ *status = CMD_COMPLETE_MATCH;
+ return match_str;
+ }
+ }
+ }
+
+ match_str = (char **) matchvec->index;
+ vector_only_wrapper_free (matchvec);
+ *status = CMD_COMPLETE_LIST_MATCH;
+ return match_str;
+}
+
+/* Execute command by argument vline vector. */
+int
+cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd)
+{
+ int i;
+ int index;
+ vector cmd_vector;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ int argc;
+ char *argv[CMD_ARGC_MAX];
+ enum match_type match = 0;
+ int varflag;
+ char *command;
+
+ /* Make copy of command elements. */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ for (index = 0; index < vector_max (vline); index++)
+ {
+ int ret;
+
+ command = vector_slot (vline, index);
+
+ match = cmd_filter_by_completion (command, cmd_vector, index);
+
+ if (match == vararg_match)
+ break;
+
+ ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+
+ if (ret == 1)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ else if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_NO_MATCH;
+ }
+ }
+
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
+
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if (vector_slot (cmd_vector,i) != NULL)
+ {
+ cmd_element = vector_slot (cmd_vector,i);
+
+ if (match == vararg_match || index >= cmd_element->cmdsize)
+ {
+ matched_element = cmd_element;
+#if 0
+ printf ("DEBUG: %s\n", cmd_element->string);
+#endif
+ matched_count++;
+ }
+ else
+ {
+ incomplete_count++;
+ }
+ }
+
+ /* Finish of using cmd_vector. */
+ vector_free (cmd_vector);
+
+ /* To execute command, matched_count must be 1.*/
+ if (matched_count == 0)
+ {
+ if (incomplete_count)
+ return CMD_ERR_INCOMPLETE;
+ else
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (matched_count > 1)
+ return CMD_ERR_AMBIGUOUS;
+
+ /* Argument treatment */
+ varflag = 0;
+ argc = 0;
+
+ for (i = 0; i < vector_max (vline); i++)
+ {
+ if (varflag)
+ argv[argc++] = vector_slot (vline, i);
+ else
+ {
+ vector descvec = vector_slot (matched_element->strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+ char *str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ varflag = 1;
+
+ if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+ argv[argc++] = vector_slot (vline, i);
+ }
+ else
+ argv[argc++] = vector_slot (vline, i);
+ }
+
+ if (argc >= CMD_ARGC_MAX)
+ return CMD_ERR_EXEED_ARGC_MAX;
+ }
+
+ /* For vtysh execution. */
+ if (cmd)
+ *cmd = matched_element;
+
+ if (matched_element->daemon)
+ return CMD_SUCCESS_DAEMON;
+
+ /* Execute matched command. */
+ return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Execute command by argument readline. */
+int
+cmd_execute_command_strict (vector vline, struct vty *vty,
+ struct cmd_element **cmd)
+{
+ int i;
+ int index;
+ vector cmd_vector;
+ struct cmd_element *cmd_element;
+ struct cmd_element *matched_element;
+ unsigned int matched_count, incomplete_count;
+ int argc;
+ char *argv[CMD_ARGC_MAX];
+ int varflag;
+ enum match_type match = 0;
+ char *command;
+
+ /* Make copy of command element */
+ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+ for (index = 0; index < vector_max (vline); index++)
+ {
+ int ret;
+
+ command = vector_slot (vline, index);
+
+ match = cmd_filter_by_string (vector_slot (vline, index),
+ cmd_vector, index);
+
+ /* If command meets '.VARARG' then finish matching. */
+ if (match == vararg_match)
+ break;
+
+ ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+ if (ret == 1)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if (ret == 2)
+ {
+ vector_free (cmd_vector);
+ return CMD_ERR_NO_MATCH;
+ }
+ }
+
+ /* Check matched count. */
+ matched_element = NULL;
+ matched_count = 0;
+ incomplete_count = 0;
+ for (i = 0; i < vector_max (cmd_vector); i++)
+ if (vector_slot (cmd_vector,i) != NULL)
+ {
+ cmd_element = vector_slot (cmd_vector,i);
+
+ if (match == vararg_match || index >= cmd_element->cmdsize)
+ {
+ matched_element = cmd_element;
+ matched_count++;
+ }
+ else
+ incomplete_count++;
+ }
+
+ /* Finish of using cmd_vector. */
+ vector_free (cmd_vector);
+
+ /* To execute command, matched_count must be 1.*/
+ if (matched_count == 0)
+ {
+ if (incomplete_count)
+ return CMD_ERR_INCOMPLETE;
+ else
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (matched_count > 1)
+ return CMD_ERR_AMBIGUOUS;
+
+ /* Argument treatment */
+ varflag = 0;
+ argc = 0;
+
+ for (i = 0; i < vector_max (vline); i++)
+ {
+ if (varflag)
+ argv[argc++] = vector_slot (vline, i);
+ else
+ {
+ vector descvec = vector_slot (matched_element->strvec, i);
+
+ if (vector_max (descvec) == 1)
+ {
+ struct desc *desc = vector_slot (descvec, 0);
+ char *str = desc->cmd;
+
+ if (CMD_VARARG (str))
+ varflag = 1;
+
+ if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+ argv[argc++] = vector_slot (vline, i);
+ }
+ else
+ argv[argc++] = vector_slot (vline, i);
+ }
+
+ if (argc >= CMD_ARGC_MAX)
+ return CMD_ERR_EXEED_ARGC_MAX;
+ }
+
+ /* For vtysh execution. */
+ if (cmd)
+ *cmd = matched_element;
+
+ if (matched_element->daemon)
+ return CMD_SUCCESS_DAEMON;
+
+ /* Now execute matched command */
+ return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Configration make from file. */
+int
+config_from_file (struct vty *vty, FILE *fp)
+{
+ int ret;
+ vector vline;
+
+ while (fgets (vty->buf, VTY_BUFSIZ, fp))
+ {
+ vline = cmd_make_strvec (vty->buf);
+
+ /* In case of comment line */
+ if (vline == NULL)
+ continue;
+ /* Execute configuration command : this is strict match */
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+
+ /* Try again with setting node to CONFIG_NODE */
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ {
+ if (vty->node == KEYCHAIN_KEY_NODE)
+ {
+ vty->node = KEYCHAIN_NODE;
+
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ {
+ vty->node = CONFIG_NODE;
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+ }
+ else
+ {
+ vty->node = CONFIG_NODE;
+ ret = cmd_execute_command_strict (vline, vty, NULL);
+ }
+ }
+
+ cmd_free_strvec (vline);
+
+ if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+ return ret;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Configration from terminal */
+DEFUN (config_terminal,
+ config_terminal_cmd,
+ "configure terminal",
+ "Configuration from vty interface\n"
+ "Configuration terminal\n")
+{
+ if (vty_config_lock (vty))
+ vty->node = CONFIG_NODE;
+ else
+ {
+ vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Enable command */
+DEFUN (enable,
+ config_enable_cmd,
+ "enable",
+ "Turn on privileged mode command\n")
+{
+ /* If enable password is NULL, change to ENABLE_NODE */
+ if ((host.enable == NULL && host.enable_encrypt == NULL) ||
+ vty->type == VTY_SHELL_SERV)
+ vty->node = ENABLE_NODE;
+ else
+ vty->node = AUTH_ENABLE_NODE;
+
+ return CMD_SUCCESS;
+}
+
+/* Disable command */
+DEFUN (disable,
+ config_disable_cmd,
+ "disable",
+ "Turn off privileged mode command\n")
+{
+ if (vty->node == ENABLE_NODE)
+ vty->node = VIEW_NODE;
+ return CMD_SUCCESS;
+}
+
+/* Down vty node level. */
+DEFUN (config_exit,
+ config_exit_cmd,
+ "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ if (vty_shell (vty))
+ exit (0);
+ else
+ vty->status = VTY_CLOSE;
+ break;
+ case CONFIG_NODE:
+ vty->node = ENABLE_NODE;
+ vty_config_unlock (vty);
+ break;
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case BGP_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case ISIS_NODE:
+ case KEYCHAIN_NODE:
+ case MASC_NODE:
+ case RMAP_NODE:
+ case VTY_NODE:
+ vty->node = CONFIG_NODE;
+ break;
+ case BGP_VPNV4_NODE:
+ case BGP_IPV4_NODE:
+ case BGP_IPV4M_NODE:
+ case BGP_IPV6_NODE:
+ vty->node = BGP_NODE;
+ break;
+ case KEYCHAIN_KEY_NODE:
+ vty->node = KEYCHAIN_NODE;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+/* quit is alias of exit. */
+ALIAS (config_exit,
+ config_quit_cmd,
+ "quit",
+ "Exit current mode and down to previous mode\n")
+
+/* End of configuration. */
+DEFUN (config_end,
+ config_end_cmd,
+ "end",
+ "End current mode and change to enable mode.")
+{
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ /* Nothing to do. */
+ break;
+ case CONFIG_NODE:
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case BGP_NODE:
+ case BGP_VPNV4_NODE:
+ case BGP_IPV4_NODE:
+ case BGP_IPV4M_NODE:
+ case BGP_IPV6_NODE:
+ case RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case ISIS_NODE:
+ case KEYCHAIN_NODE:
+ case KEYCHAIN_KEY_NODE:
+ case MASC_NODE:
+ case VTY_NODE:
+ vty_config_unlock (vty);
+ vty->node = ENABLE_NODE;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+/* Show version. */
+DEFUN (show_version,
+ show_version_cmd,
+ "show version",
+ SHOW_STR
+ "Displays zebra version\n")
+{
+ vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
+ host_name,
+ VTY_NEWLINE);
+ vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_help,
+ config_help_cmd,
+ "help",
+ "Description of the interactive help system\n")
+{
+ vty_out (vty,
+ "Zebra VTY provides advanced help feature. When you need help,%s\
+anytime at the command line please press '?'.%s\
+%s\
+If nothing matches, the help list will be empty and you must backup%s\
+ until entering a '?' shows the available options.%s\
+Two styles of help are provided:%s\
+1. Full help is available when you are ready to enter a%s\
+command argument (e.g. 'show ?') and describes each possible%s\
+argument.%s\
+2. Partial help is provided when an abbreviated argument is entered%s\
+ and you want to know what arguments match the input%s\
+ (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_list,
+ config_list_cmd,
+ "list",
+ "Print command list\n")
+{
+ int i;
+ struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
+ struct cmd_element *cmd;
+
+ for (i = 0; i < vector_max (cnode->cmd_vector); i++)
+ if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
+ vty_out (vty, " %s%s", cmd->string,
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Write current configuration into file. */
+DEFUN (config_write_file,
+ config_write_file_cmd,
+ "write file",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to configuration file\n")
+{
+ int i;
+ int fd;
+ struct cmd_node *node;
+ char *config_file;
+ char *config_file_tmp = NULL;
+ char *config_file_sav = NULL;
+ struct vty *file_vty;
+
+ /* Check and see if we are operating under vtysh configuration */
+ if (host.config == NULL)
+ {
+ vty_out (vty, "Can't save to configuration file, using vtysh.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Get filename. */
+ config_file = host.config;
+
+ config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
+ strcpy (config_file_sav, config_file);
+ strcat (config_file_sav, CONF_BACKUP_EXT);
+
+
+ config_file_tmp = malloc (strlen (config_file) + 8);
+ sprintf (config_file_tmp, "%s.XXXXXX", config_file);
+
+ /* Open file to configuration write. */
+ fd = mkstemp (config_file_tmp);
+ if (fd < 0)
+ {
+ vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
+ VTY_NEWLINE);
+ free (config_file_tmp);
+ free (config_file_sav);
+ return CMD_WARNING;
+ }
+
+ /* Make vty for configuration file. */
+ file_vty = vty_new ();
+ file_vty->fd = fd;
+ file_vty->type = VTY_FILE;
+
+ /* Config file header print. */
+ vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
+ vty_time_print (file_vty, 1);
+ vty_out (file_vty, "!\n");
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (file_vty))
+ vty_out (file_vty, "!\n");
+ }
+ vty_close (file_vty);
+
+ if (unlink (config_file_sav) != 0)
+ if (errno != ENOENT)
+ {
+ vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ if (link (config_file, config_file_sav) != 0)
+ {
+ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ sync ();
+ if (unlink (config_file) != 0)
+ {
+ vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ if (link (config_file_tmp, config_file) != 0)
+ {
+ vty_out (vty, "Can't save configuration file %s.%s", config_file,
+ VTY_NEWLINE);
+ free (config_file_sav);
+ free (config_file_tmp);
+ unlink (config_file_tmp);
+ return CMD_WARNING;
+ }
+ unlink (config_file_tmp);
+ sync ();
+
+ free (config_file_sav);
+ free (config_file_tmp);
+ vty_out (vty, "Configuration saved to %s%s", config_file,
+ VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_write_file,
+ config_write_cmd,
+ "write",
+ "Write running configuration to memory, network, or terminal\n")
+
+ALIAS (config_write_file,
+ config_write_memory_cmd,
+ "write memory",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write configuration to the file (same as write file)\n")
+
+ALIAS (config_write_file,
+ copy_runningconfig_startupconfig_cmd,
+ "copy running-config startup-config",
+ "Copy configuration\n"
+ "Copy running config to... \n"
+ "Copy running config to startup config (same as write file)\n")
+
+/* Write current configuration into the terminal. */
+DEFUN (config_write_terminal,
+ config_write_terminal_cmd,
+ "write terminal",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write to terminal\n")
+{
+ int i;
+ struct cmd_node *node;
+
+ if (vty->type == VTY_SHELL_SERV)
+ {
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ }
+ else
+ {
+ vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+ VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ for (i = 0; i < vector_max (cmdvec); i++)
+ if ((node = vector_slot (cmdvec, i)) && node->func)
+ {
+ if ((*node->func) (vty))
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "end%s",VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+/* Write current configuration into the terminal. */
+ALIAS (config_write_terminal,
+ show_running_config_cmd,
+ "show running-config",
+ SHOW_STR
+ "running configuration\n")
+
+/* Write startup configuration into the terminal. */
+DEFUN (show_startup_config,
+ show_startup_config_cmd,
+ "show startup-config",
+ SHOW_STR
+ "Contentes of startup configuration\n")
+{
+ char buf[BUFSIZ];
+ FILE *confp;
+
+ confp = fopen (host.config, "r");
+ if (confp == NULL)
+ {
+ vty_out (vty, "Can't open configuration file [%s]%s",
+ host.config, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ while (fgets (buf, BUFSIZ, confp))
+ {
+ char *cp = buf;
+
+ while (*cp != '\r' && *cp != '\n' && *cp != '\0')
+ cp++;
+ *cp = '\0';
+
+ vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+ }
+
+ fclose (confp);
+
+ return CMD_SUCCESS;
+}
+
+/* Hostname configuration */
+DEFUN (config_hostname,
+ hostname_cmd,
+ "hostname WORD",
+ "Set system's network name\n"
+ "This system's network name\n")
+{
+ if (!isalpha((int) *argv[0]))
+ {
+ vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.name)
+ XFREE (0, host.name);
+
+ host.name = strdup (argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_no_hostname,
+ no_hostname_cmd,
+ "no hostname [HOSTNAME]",
+ NO_STR
+ "Reset system's network name\n"
+ "Host name of this router\n")
+{
+ if (host.name)
+ XFREE (0, host.name);
+ host.name = NULL;
+ return CMD_SUCCESS;
+}
+
+/* VTY interface password set. */
+DEFUN (config_password, password_cmd,
+ "password (8|) WORD",
+ "Assign the terminal connection password\n"
+ "Specifies a HIDDEN password will follow\n"
+ "dummy string \n"
+ "The HIDDEN line password string\n")
+{
+ /* Argument check. */
+ if (argc == 0)
+ {
+ vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (argc == 2)
+ {
+ if (*argv[0] == '8')
+ {
+ if (host.password)
+ XFREE (0, host.password);
+ host.password = NULL;
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (!isalnum ((int) *argv[0]))
+ {
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.password)
+ XFREE (0, host.password);
+ host.password = NULL;
+
+ if (host.encrypt)
+ {
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+ }
+ else
+ host.password = XSTRDUP (0, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_password, password_text_cmd,
+ "password LINE",
+ "Assign the terminal connection password\n"
+ "The UNENCRYPTED (cleartext) line password\n")
+
+/* VTY enable password set. */
+DEFUN (config_enable_password, enable_password_cmd,
+ "enable password (8|) WORD",
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n"
+ "Specifies a HIDDEN password will follow\n"
+ "dummy string \n"
+ "The HIDDEN 'enable' password string\n")
+{
+ /* Argument check. */
+ if (argc == 0)
+ {
+ vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Crypt type is specified. */
+ if (argc == 2)
+ {
+ if (*argv[0] == '8')
+ {
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, argv[1]);
+
+ return CMD_SUCCESS;
+ }
+ else
+ {
+ vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (!isalnum ((int) *argv[0]))
+ {
+ vty_out (vty,
+ "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ /* Plain password input. */
+ if (host.encrypt)
+ {
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+ }
+ else
+ host.enable = XSTRDUP (0, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (config_enable_password,
+ enable_password_text_cmd,
+ "enable password LINE",
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n"
+ "The UNENCRYPTED (cleartext) 'enable' password\n")
+
+/* VTY enable password delete. */
+DEFUN (no_config_enable_password, no_enable_password_cmd,
+ "no enable password",
+ NO_STR
+ "Modify enable password parameters\n"
+ "Assign the privileged level password\n")
+{
+ if (host.enable)
+ XFREE (0, host.enable);
+ host.enable = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_password_encrypt,
+ service_password_encrypt_cmd,
+ "service password-encryption",
+ "Set up miscellaneous service\n"
+ "Enable encrypted passwords\n")
+{
+ if (host.encrypt)
+ return CMD_SUCCESS;
+
+ host.encrypt = 1;
+
+ if (host.password)
+ {
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
+ }
+ if (host.enable)
+ {
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_password_encrypt,
+ no_service_password_encrypt_cmd,
+ "no service password-encryption",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Enable encrypted passwords\n")
+{
+ if (! host.encrypt)
+ return CMD_SUCCESS;
+
+ host.encrypt = 0;
+
+ if (host.password_encrypt)
+ XFREE (0, host.password_encrypt);
+ host.password_encrypt = NULL;
+
+ if (host.enable_encrypt)
+ XFREE (0, host.enable_encrypt);
+ host.enable_encrypt = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_length, config_terminal_length_cmd,
+ "terminal length <0-512>",
+ "Set terminal line parameters\n"
+ "Set number of lines on a screen\n"
+ "Number of lines on screen (0 for no pausing)\n")
+{
+ int lines;
+ char *endptr = NULL;
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+ {
+ vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty->lines = lines;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
+ "terminal no length",
+ "Set terminal line parameters\n"
+ NO_STR
+ "Set number of lines on a screen\n")
+{
+ vty->lines = -1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_terminal_length, service_terminal_length_cmd,
+ "service terminal-length <0-512>",
+ "Set up miscellaneous service\n"
+ "System wide terminal length configuration\n"
+ "Number of lines of VTY (0 means no line control)\n")
+{
+ int lines;
+ char *endptr = NULL;
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+ {
+ vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ host.lines = lines;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
+ "no service terminal-length [<0-512>]",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "System wide terminal length configuration\n"
+ "Number of lines of VTY (0 means no line control)\n")
+{
+ host.lines = -1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_stdout,
+ config_log_stdout_cmd,
+ "log stdout",
+ "Logging control\n"
+ "Logging goes to stdout\n")
+{
+ zlog_set_flag (NULL, ZLOG_STDOUT);
+ host.log_stdout = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_stdout,
+ no_config_log_stdout_cmd,
+ "no log stdout",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to stdout\n")
+{
+ zlog_reset_flag (NULL, ZLOG_STDOUT);
+ host.log_stdout = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_file,
+ config_log_file_cmd,
+ "log file FILENAME",
+ "Logging control\n"
+ "Logging to file\n"
+ "Logging filename\n")
+{
+ int ret;
+ char *cwd;
+ char *fullpath;
+
+ /* Path detection. */
+ if (! IS_DIRECTORY_SEP (*argv[0]))
+ {
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (argv[0]) + 2);
+ sprintf (fullpath, "%s/%s", cwd, argv[0]);
+ }
+ else
+ fullpath = argv[0];
+
+ ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
+
+ if (!ret)
+ {
+ vty_out (vty, "can't open logfile %s\n", argv[0]);
+ return CMD_WARNING;
+ }
+
+ if (host.logfile)
+ XFREE (MTYPE_TMP, host.logfile);
+
+ host.logfile = strdup (argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_file,
+ no_config_log_file_cmd,
+ "no log file [FILENAME]",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to file\n"
+ "Logging file name\n")
+{
+ zlog_reset_file (NULL);
+
+ if (host.logfile)
+ XFREE (MTYPE_TMP, host.logfile);
+
+ host.logfile = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_syslog,
+ config_log_syslog_cmd,
+ "log syslog",
+ "Logging control\n"
+ "Logging goes to syslog\n")
+{
+ zlog_set_flag (NULL, ZLOG_SYSLOG);
+ host.log_syslog = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_syslog,
+ no_config_log_syslog_cmd,
+ "no log syslog",
+ NO_STR
+ "Logging control\n"
+ "Cancel logging to syslog\n")
+{
+ zlog_reset_flag (NULL, ZLOG_SYSLOG);
+ host.log_syslog = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_trap,
+ config_log_trap_cmd,
+ "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
+ "Logging control\n"
+ "Limit logging to specifed level\n")
+{
+ int new_level ;
+
+ for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
+ {
+ if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
+ /* found new logging level */
+ {
+ zlog_default->maskpri = new_level;
+ return CMD_SUCCESS;
+ }
+ }
+ return CMD_ERR_NO_MATCH;
+}
+
+DEFUN (no_config_log_trap,
+ no_config_log_trap_cmd,
+ "no log trap",
+ NO_STR
+ "Logging control\n"
+ "Permit all logging information\n")
+{
+ zlog_default->maskpri = LOG_DEBUG;
+ return CMD_SUCCESS;
+}
+
+DEFUN (config_log_record_priority,
+ config_log_record_priority_cmd,
+ "log record-priority",
+ "Logging control\n"
+ "Log the priority of the message within the message\n")
+{
+ zlog_default->record_priority = 1 ;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_record_priority,
+ no_config_log_record_priority_cmd,
+ "no log record-priority",
+ NO_STR
+ "Logging control\n"
+ "Do not log the priority of the message within the message\n")
+{
+ zlog_default->record_priority = 0 ;
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (banner_motd_default,
+ banner_motd_default_cmd,
+ "banner motd default",
+ "Set banner string\n"
+ "Strings for motd\n"
+ "Default string\n")
+{
+ host.motd = default_motd;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_banner_motd,
+ no_banner_motd_cmd,
+ "no banner motd",
+ NO_STR
+ "Set banner string\n"
+ "Strings for motd\n")
+{
+ host.motd = NULL;
+ return CMD_SUCCESS;
+}
+
+/* Set config filename. Called from vty.c */
+void
+host_config_set (char *filename)
+{
+ host.config = strdup (filename);
+}
+
+void
+install_default (enum node_type node)
+{
+ install_element (node, &config_exit_cmd);
+ install_element (node, &config_quit_cmd);
+ install_element (node, &config_end_cmd);
+ install_element (node, &config_help_cmd);
+ install_element (node, &config_list_cmd);
+
+ install_element (node, &config_write_terminal_cmd);
+ install_element (node, &config_write_file_cmd);
+ install_element (node, &config_write_memory_cmd);
+ install_element (node, &config_write_cmd);
+}
+
+/* Initialize command interface. Install basic nodes and commands. */
+void
+cmd_init (int terminal)
+{
+ /* Allocate initial top vector of commands. */
+ cmdvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Default host value settings. */
+ host.name = NULL;
+ host.password = NULL;
+ host.enable = NULL;
+ host.logfile = NULL;
+ host.config = NULL;
+ host.lines = -1;
+ host.motd = default_motd;
+
+ /* Install top nodes. */
+ install_node (&view_node, NULL);
+ install_node (&enable_node, NULL);
+ install_node (&auth_node, NULL);
+ install_node (&auth_enable_node, NULL);
+ install_node (&config_node, config_write_host);
+
+ /* Each node's basic commands. */
+ install_element (VIEW_NODE, &show_version_cmd);
+ if (terminal)
+ {
+ install_element (VIEW_NODE, &config_list_cmd);
+ install_element (VIEW_NODE, &config_exit_cmd);
+ install_element (VIEW_NODE, &config_quit_cmd);
+ install_element (VIEW_NODE, &config_help_cmd);
+ install_element (VIEW_NODE, &config_enable_cmd);
+ install_element (VIEW_NODE, &config_terminal_length_cmd);
+ install_element (VIEW_NODE, &config_terminal_no_length_cmd);
+ }
+
+ if (terminal)
+ {
+ install_default (ENABLE_NODE);
+ install_element (ENABLE_NODE, &config_disable_cmd);
+ install_element (ENABLE_NODE, &config_terminal_cmd);
+ install_element (ENABLE_NODE, &show_running_config_cmd);
+ install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
+ }
+ install_element (ENABLE_NODE, &show_startup_config_cmd);
+ install_element (ENABLE_NODE, &show_version_cmd);
+ install_element (ENABLE_NODE, &config_terminal_length_cmd);
+ install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
+
+ if (terminal)
+ install_default (CONFIG_NODE);
+ install_element (CONFIG_NODE, &hostname_cmd);
+ install_element (CONFIG_NODE, &no_hostname_cmd);
+ install_element (CONFIG_NODE, &password_cmd);
+ install_element (CONFIG_NODE, &password_text_cmd);
+ install_element (CONFIG_NODE, &enable_password_cmd);
+ install_element (CONFIG_NODE, &enable_password_text_cmd);
+ install_element (CONFIG_NODE, &no_enable_password_cmd);
+ if (terminal)
+ {
+ install_element (CONFIG_NODE, &config_log_stdout_cmd);
+ install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
+ install_element (CONFIG_NODE, &config_log_file_cmd);
+ install_element (CONFIG_NODE, &no_config_log_file_cmd);
+ install_element (CONFIG_NODE, &config_log_syslog_cmd);
+ install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
+ install_element (CONFIG_NODE, &config_log_trap_cmd);
+ install_element (CONFIG_NODE, &no_config_log_trap_cmd);
+ install_element (CONFIG_NODE, &config_log_record_priority_cmd);
+ install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
+ install_element (CONFIG_NODE, &service_password_encrypt_cmd);
+ install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
+ install_element (CONFIG_NODE, &banner_motd_default_cmd);
+ install_element (CONFIG_NODE, &no_banner_motd_cmd);
+ install_element (CONFIG_NODE, &service_terminal_length_cmd);
+ install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
+ }
+
+ srand(time(NULL));
+}
diff --git a/isisd/modified/command.h b/isisd/modified/command.h
new file mode 100644
index 00000000..d407c5a9
--- /dev/null
+++ b/isisd/modified/command.h
@@ -0,0 +1,311 @@
+/*
+ * Zebra configuration command interface routine
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_COMMAND_H
+#define _ZEBRA_COMMAND_H
+
+#include "vector.h"
+#include "vty.h"
+
+/* Host configuration variable */
+struct host
+{
+ /* Host name of this router. */
+ char *name;
+
+ /* Password for vty interface. */
+ char *password;
+ char *password_encrypt;
+
+ /* Enable password */
+ char *enable;
+ char *enable_encrypt;
+
+ /* System wide terminal lines. */
+ int lines;
+
+ /* Log filename. */
+ char *logfile;
+
+ /* Log stdout. */
+ u_char log_stdout;
+
+ /* Log syslog. */
+ u_char log_syslog;
+
+ /* config file name of this host */
+ char *config;
+
+ /* Flags for services */
+ int advanced;
+ int encrypt;
+
+ /* Banner configuration. */
+ char *motd;
+};
+
+/* There are some command levels which called from command node. */
+enum node_type
+{
+ AUTH_NODE, /* Authentication mode of vty interface. */
+ VIEW_NODE, /* View node. Default mode of vty interface. */
+ AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
+ ENABLE_NODE, /* Enable node. */
+ CONFIG_NODE, /* Config node. Default mode of config file. */
+ DEBUG_NODE, /* Debug node. */
+ AAA_NODE, /* AAA node. */
+ KEYCHAIN_NODE, /* Key-chain node. */
+ KEYCHAIN_KEY_NODE, /* Key-chain key node. */
+ INTERFACE_NODE, /* Interface mode node. */
+ ZEBRA_NODE, /* zebra connection node. */
+ TABLE_NODE, /* rtm_table selection node. */
+ RIP_NODE, /* RIP protocol mode node. */
+ RIPNG_NODE, /* RIPng protocol mode node. */
+ BGP_NODE, /* BGP protocol mode which includes BGP4+ */
+ BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
+ BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
+ BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */
+ BGP_IPV6_NODE, /* BGP IPv6 address family */
+ OSPF_NODE, /* OSPF protocol mode */
+ OSPF6_NODE, /* OSPF protocol for IPv6 mode */
+ ISIS_NODE, /* IS-IS protocol mode */
+ MASC_NODE, /* MASC for multicast. */
+ IRDP_NODE, /* ICMP Router Discovery Protocol mode. */
+ IP_NODE, /* Static ip route node. */
+ ACCESS_NODE, /* Access list node. */
+ PREFIX_NODE, /* Prefix list node. */
+ ACCESS_IPV6_NODE, /* Access list node. */
+ PREFIX_IPV6_NODE, /* Prefix list node. */
+ AS_LIST_NODE, /* AS list node. */
+ COMMUNITY_LIST_NODE, /* Community list node. */
+ RMAP_NODE, /* Route map node. */
+ SMUX_NODE, /* SNMP configuration node. */
+ DUMP_NODE, /* Packet dump node. */
+ FORWARDING_NODE, /* IP forwarding node. */
+ VTY_NODE /* Vty node. */
+};
+
+/* Node which has some commands and prompt string and configuration
+ function pointer . */
+struct cmd_node
+{
+ /* Node index. */
+ enum node_type node;
+
+ /* Prompt character at vty interface. */
+ char *prompt;
+
+ /* Is this node's configuration goes to vtysh ? */
+ int vtysh;
+
+ /* Node's configuration write function */
+ int (*func) (struct vty *);
+
+ /* Vector of this node's command list. */
+ vector cmd_vector;
+};
+
+/* Structure of command element. */
+struct cmd_element
+{
+ char *string; /* Command specification by string. */
+ int (*func) (struct cmd_element *, struct vty *, int, char **);
+ char *doc; /* Documentation of this command. */
+ int daemon; /* Daemon to which this command belong. */
+ vector strvec; /* Pointing out each description vector. */
+ int cmdsize; /* Command index count. */
+ char *config; /* Configuration string */
+ vector subconfig; /* Sub configuration string */
+};
+
+/* Command description structure. */
+struct desc
+{
+ char *cmd; /* Command string. */
+ char *str; /* Command's description. */
+};
+
+/* Return value of the commands. */
+#define CMD_SUCCESS 0
+#define CMD_WARNING 1
+#define CMD_ERR_NO_MATCH 2
+#define CMD_ERR_AMBIGUOUS 3
+#define CMD_ERR_INCOMPLETE 4
+#define CMD_ERR_EXEED_ARGC_MAX 5
+#define CMD_ERR_NOTHING_TODO 6
+#define CMD_COMPLETE_FULL_MATCH 7
+#define CMD_COMPLETE_MATCH 8
+#define CMD_COMPLETE_LIST_MATCH 9
+#define CMD_SUCCESS_DAEMON 10
+
+/* Argc max counts. */
+#define CMD_ARGC_MAX 25
+
+/* Turn off these macros when uisng cpp with extract.pl */
+#ifndef VTYSH_EXTRACT_PL
+
+/* DEFUN for vty command interafce. Little bit hacky ;-). */
+#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
+ int funcname (struct cmd_element *, struct vty *, int, char **); \
+ struct cmd_element cmdname = \
+ { \
+ cmdstr, \
+ funcname, \
+ helpstr \
+ }; \
+ int funcname \
+ (struct cmd_element *self, struct vty *vty, int argc, char **argv)
+
+/* DEFUN_NOSH for commands that vtysh should ignore */
+#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN(funcname, cmdname, cmdstr, helpstr)
+
+/* DEFSH for vtysh. */
+#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
+ struct cmd_element cmdname = \
+ { \
+ cmdstr, \
+ NULL, \
+ helpstr, \
+ daemon \
+ }; \
+
+/* DEFUN + DEFSH */
+#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
+ int funcname (struct cmd_element *, struct vty *, int, char **); \
+ struct cmd_element cmdname = \
+ { \
+ cmdstr, \
+ funcname, \
+ helpstr, \
+ daemon \
+ }; \
+ int funcname \
+ (struct cmd_element *self, struct vty *vty, int argc, char **argv)
+
+/* ALIAS macro which define existing command's alias. */
+#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
+ struct cmd_element cmdname = \
+ { \
+ cmdstr, \
+ funcname, \
+ helpstr \
+ };
+
+#endif /* VTYSH_EXTRACT_PL */
+
+/* Some macroes */
+#define CMD_OPTION(S) ((S[0]) == '[')
+#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<'))
+#define CMD_VARARG(S) ((S[0]) == '.')
+#define CMD_RANGE(S) ((S[0] == '<'))
+
+#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0))
+#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0))
+#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0))
+#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0))
+
+/* Common descriptions. */
+#define SHOW_STR "Show running system information\n"
+#define IP_STR "IP information\n"
+#define IPV6_STR "IPv6 information\n"
+#define NO_STR "Negate a command or set its defaults\n"
+#define CLEAR_STR "Reset functions\n"
+#define RIP_STR "RIP information\n"
+#define BGP_STR "BGP information\n"
+#define OSPF_STR "OSPF information\n"
+#define NEIGHBOR_STR "Specify neighbor router\n"
+#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
+#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
+#define ROUTER_STR "Enable a routing process\n"
+#define AS_STR "AS number\n"
+#define MBGP_STR "MBGP information\n"
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+#define OUT_STR "Filter outgoing routing updates\n"
+#define IN_STR "Filter incoming routing updates\n"
+#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
+#define OSPF6_NUMBER_STR "Specify by number\n"
+#define INTERFACE_STR "Interface infomation\n"
+#define IFNAME_STR "Interface name(e.g. ep0)\n"
+#define IP6_STR "IPv6 Information\n"
+#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
+#define OSPF6_ROUTER_STR "Enable a routing process\n"
+#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
+#define SECONDS_STR "<1-65535> Seconds\n"
+#define ROUTE_STR "Routing Table\n"
+#define PREFIX_LIST_STR "Build a prefix list\n"
+#define OSPF6_DUMP_TYPE_LIST \
+"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
+#define ISIS_STR "IS-IS information\n"
+#define AREA_TAG_STR "[area tag]\n"
+
+#define CONF_BACKUP_EXT ".sav"
+
+/* IPv4 only machine should not accept IPv6 address for peer's IP
+ address. So we replace VTY command string like below. */
+#ifdef HAVE_IPV6
+#define NEIGHBOR_CMD "neighbor (A.B.C.D|X:X::X:X) "
+#define NO_NEIGHBOR_CMD "no neighbor (A.B.C.D|X:X::X:X) "
+#define NEIGHBOR_ADDR_STR "Neighbor address\nIPv6 address\n"
+#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+#else
+#define NEIGHBOR_CMD "neighbor A.B.C.D "
+#define NO_NEIGHBOR_CMD "no neighbor A.B.C.D "
+#define NEIGHBOR_ADDR_STR "Neighbor address\n"
+#define NEIGHBOR_CMD2 "neighbor (A.B.C.D|WORD) "
+#define NO_NEIGHBOR_CMD2 "no neighbor (A.B.C.D|WORD) "
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
+#endif /* HAVE_IPV6 */
+
+/* Prototypes. */
+void install_node (struct cmd_node *, int (*) (struct vty *));
+void install_default (enum node_type);
+void install_element (enum node_type, struct cmd_element *);
+void sort_node ();
+
+char *argv_concat (char **, int, int);
+vector cmd_make_strvec (char *);
+void cmd_free_strvec (vector);
+vector cmd_describe_command ();
+char **cmd_complete_command ();
+char *cmd_prompt (enum node_type);
+int config_from_file (struct vty *, FILE *);
+int cmd_execute_command (vector, struct vty *, struct cmd_element **);
+int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
+void config_replace_string (struct cmd_element *, char *, ...);
+void cmd_init (int);
+
+/* Export typical functions. */
+extern struct cmd_element config_end_cmd;
+extern struct cmd_element config_exit_cmd;
+extern struct cmd_element config_quit_cmd;
+extern struct cmd_element config_help_cmd;
+extern struct cmd_element config_list_cmd;
+int config_exit (struct cmd_element *, struct vty *, int, char **);
+int config_help (struct cmd_element *, struct vty *, int, char **);
+char *host_config_file ();
+void host_config_set (char *);
+
+#endif /* _ZEBRA_COMMAND_H */
diff --git a/isisd/modified/config.h.in b/isisd/modified/config.h.in
new file mode 100644
index 00000000..c06839ef
--- /dev/null
+++ b/isisd/modified/config.h.in
@@ -0,0 +1,368 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+/* accconfig.h -- `autoheader' will generate config.h.in for zebra.
+ Copyright (C) 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> */
+
+/* Version of GNU Zebra */
+#undef VERSION
+
+/* Solaris on x86. */
+#undef SOLARIS_X86
+
+/* Package name of GNU Zebra */
+#undef PACKAGE
+
+/* Define if host is GNU/Linux */
+#undef GNU_LINUX
+
+/* Define if you have the AF_ROUTE socket. */
+#undef HAVE_AF_ROUTE
+
+/* Define if you have the inet_aton function. */
+#undef HAVE_INET_ATON
+
+/* Define if you have the inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define if you have the inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define if you have the setproctitle function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define if you have ipv6 stack. */
+#undef HAVE_IPV6
+
+/* Define if you wish to support ipv6 router advertisment. */
+/* #undef HAVE_RTADV */
+
+/* whether system has GNU regex */
+#undef HAVE_GNU_REGEX
+
+/* whether system has SNMP library */
+#undef HAVE_SNMP
+
+/* whether sockaddr has a sa_len field */
+#undef HAVE_SA_LEN
+
+/* whether sockaddr_in has a sin_len field */
+#undef HAVE_SIN_LEN
+
+/* whether sockaddr_un has a sun_len field */
+#undef HAVE_SUN_LEN
+
+/* whether sockaddr_in6 has a sin6_scope_id field */
+#undef HAVE_SIN6_SCOPE_ID
+
+/* Define if there is socklen_t. */
+#undef HAVE_SOCKLEN_T
+
+/* Define if there is sockaddr_dl structure. */
+#undef HAVE_SOCKADDR_DL
+
+/* Define if there is ifaliasreq structure. */
+#undef HAVE_IFALIASREQ
+
+/* Define if there is in6_aliasreq structure. */
+#undef HAVE_IN6_ALIASREQ
+
+/* Define if there is rt_addrinfo structure. */
+#undef HAVE_RT_ADDRINFO
+
+/* Define if there is in_pktinfo structure. */
+#undef HAVE_INPKTINFO
+
+/* Define if you have the getrusage function. */
+#undef HAVE_RUSAGE
+
+/* Define if /proc/net/dev exists. */
+#undef HAVE_PROC_NET_DEV
+
+/* Define if /proc/net/if_inet6 exists. */
+#undef HAVE_PROC_NET_IF_INET6
+
+/* Define if NET_RT_IFLIST exists in sys/socket.h. */
+#undef HAVE_NET_RT_IFLIST
+
+/* Define if you have INRIA ipv6 stack. */
+#undef INRIA_IPV6
+
+/* Define if you have KAME project ipv6 stack. */
+#undef KAME
+
+/* Define if you have Linux ipv6 stack. */
+#undef LINUX_IPV6
+
+/* Define if you have NRL ipv6 stack. */
+#undef NRL
+
+/* Define if you have BSDI NRL IPv6 stack. */
+#undef BSDI_NRL
+
+/* Define if one-vty option is specified. */
+#undef VTYSH
+
+/* Define if interface aliases don't have distinct indeces */
+#undef HAVE_BROKEN_ALIASES
+
+/* Define if disable-bgp-announce option is specified. */
+#undef DISABLE_BGP_ANNOUNCE
+
+/* PAM support */
+#undef USE_PAM
+
+/* TCP/IP communication between zebra and protocol daemon. */
+#undef HAVE_TCP_ZEBRA
+
+/* The OSPF NSSA option (RFC1587). */
+#undef HAVE_NSSA
+
+/* The OSPF Opaque LSA option (RFC2370). */
+#undef HAVE_OPAQUE_LSA
+
+/* Traffic Engineering Extension to OSPF
+ (draft-katz-yeung-ospf-traffic-06.txt). */
+#undef HAVE_OSPF_TE
+
+/* Linux netlink. */
+#undef HAVE_NETLINK
+
+/* PATHS */
+#undef PATH_ZEBRA_PID
+#undef PATH_RIPD_PID
+#undef PATH_RIPNGD_PID
+#undef PATH_BGPD_PID
+#undef PATH_OSPFD_PID
+#undef PATH_OSPF6D_PID
+#undef PATH_ISISD_PID
+
+/* Define if Solaris */
+#undef SUNOS_5
+
+/* Define if FreeBSD 3.2 */
+#undef FREEBSD_32
+
+/* Define if OpenBSD */
+#undef OPEN_BSD
+
+#ifdef HAVE_IPV6
+#ifdef KAME
+#ifndef INET6
+#define INET6
+#endif /* INET6 */
+#endif /* KAME */
+#endif /* HAVE_IPV6 */
+
+#ifdef SUNOS_5
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+typedef unsigned short u_int8_t;
+#endif /* SUNOS_5 */
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
+
+/* Define to 1 if you have the <asm/types.h> header file. */
+#undef HAVE_ASM_TYPES_H
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Define to 1 if you have the `daemon' function. */
+#undef HAVE_DAEMON
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `if_indextoname' function. */
+#undef HAVE_IF_INDEXTONAME
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the <inet/nd.h> header file. */
+#undef HAVE_INET_ND_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <kvm.h> header file. */
+#undef HAVE_KVM_H
+
+/* Define to 1 if you have the `crypt' library (-lcrypt). */
+#undef HAVE_LIBCRYPT
+
+/* Define to 1 if you have the `kvm' library (-lkvm). */
+#undef HAVE_LIBKVM
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `ncurses' library (-lncurses). */
+#undef HAVE_LIBNCURSES
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `readline' library (-lreadline). */
+#undef HAVE_LIBREADLINE
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `tinfo' library (-ltinfo). */
+#undef HAVE_LIBTINFO
+
+/* Define to 1 if you have the <libutil.h> header file. */
+#undef HAVE_LIBUTIL_H
+
+/* Define to 1 if you have the `xnet' library (-lxnet). */
+#undef HAVE_LIBXNET
+
+/* Define to 1 if you have the <linux/version.h> header file. */
+#undef HAVE_LINUX_VERSION_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet6/nd6.h> header file. */
+#undef HAVE_NETINET6_ND6_H
+
+/* Define to 1 if you have the <netinet/icmp6.h> header file. */
+#undef HAVE_NETINET_ICMP6_H
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#undef HAVE_NETINET_IN6_H
+
+/* Define to 1 if you have the <netinet/in6_var.h> header file. */
+#undef HAVE_NETINET_IN6_VAR_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/in_var.h> header file. */
+#undef HAVE_NETINET_IN_VAR_H
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if_var.h> header file. */
+#undef HAVE_NET_IF_VAR_H
+
+/* Define to 1 if you have the <net/netopt.h> header file. */
+#undef HAVE_NET_NETOPT_H
+
+/* Define to 1 if you have the `setproctitle' function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define to 1 if you have the <sys/conf.h> header file. */
+#undef HAVE_SYS_CONF_H
+
+/* Define to 1 if you have the <sys/ksym.h> header file. */
+#undef HAVE_SYS_KSYM_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#undef HAVE_SYS_SYSCTL_H
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
diff --git a/isisd/modified/configure b/isisd/modified/configure
new file mode 100755
index 00000000..e4bf6d4f
--- /dev/null
+++ b/isisd/modified/configure
@@ -0,0 +1,8277 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.53.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# NLS nuisances.
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+(set +x; test -n "`(LANG=C; export LANG) 2>&1`") &&
+ { $as_unset LANG || test "${LANG+set}" != set; } ||
+ { LANG=C; export LANG; }
+(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") &&
+ { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } ||
+ { LC_ALL=C; export LC_ALL; }
+(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") &&
+ { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } ||
+ { LC_TIME=C; export LC_TIME; }
+(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") &&
+ { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } ||
+ { LC_CTYPE=C; export LC_CTYPE; }
+(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") &&
+ { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } ||
+ { LANGUAGE=C; export LANGUAGE; }
+(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") &&
+ { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } ||
+ { LC_COLLATE=C; export LC_COLLATE; }
+(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") &&
+ { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } ||
+ { LC_NUMERIC=C; export LC_NUMERIC; }
+(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") &&
+ { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } ||
+ { LC_MESSAGES=C; export LC_MESSAGES; }
+
+
+# Name of the executable.
+as_me=`(basename "$0") 2>/dev/null ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conftest.sh
+ echo "exit 0" >>conftest.sh
+ chmod +x conftest.sh
+ if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conftest.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="lib/zebra.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-dependency-tracking Speeds up one-time builds
+ --enable-dependency-tracking Do not reject slow dependency extractors
+ --enable-vtysh, Make integrated VTY version of zebra
+ --disable-ipv6 turn off IPv6 related features and daemons
+ --disable-zebra do not build zebra daemon
+ --disable-bgpd do not build bgpd
+ --disable-ripd do not build ripd
+ --disable-ripngd do not build ripngd
+ --disable-ospfd do not build ospfd
+ --disable-ospf6d do not build ospf6d
+ --disable-isisd do not build isisd
+ --disable-bgp-announce, turn off BGP route announcement
+ --enable-netlink force to use Linux netlink interface
+ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X
+ --enable-snmp enable SNMP support
+ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon
+ --enable-nssa enable OSPF NSSA option
+ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)
+ --enable-ospf-te enable Traffic Engineering Extension to OSPF
+ --enable-multipath=ARG enable multipath function, ARG must be digit
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-cflags Set CFLAGS for use in compilation.
+ --with-libpam use libpam for PAM support in vtysh
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.53. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+ case $ac_arg in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n ) continue ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ ac_sep=" " ;;
+ esac
+ # Get rid of the leading space.
+done
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+am__api_version="1.6"
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$,$program_suffix,;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm conftest.sed
+
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AWK" && break
+done
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+ # test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" &&
+ test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# Define the identity of the package.
+ PACKAGE=zebra
+ VERSION=0.93
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+install_sh=${install_sh-"$am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STRIP=$ac_ct_STRIP
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+
+
+
+# Add the stamp file to the list of files AC keeps track of,
+# along with our hook.
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+
+
+# Check whether --with-cflags or --without-cflags was given.
+if test "${with_cflags+set}" = set; then
+ withval="$with_cflags"
+
+fi;
+if test "x$with_cflags" != "x" ; then
+ CFLAGS="$with_cflags" ; cflags_specified=yes ;
+elif test -n "$CFLAGS" ; then
+ cflags_specified=yes ;
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$as_dir/$ac_word" ${1+"$@"}
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+for ac_file in `ls a_out.exe a.exe conftest.exe 2>/dev/null;
+ ls a.out conftest 2>/dev/null;
+ ls a.* conftest.* 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb | *.xSYM ) ;;
+ a.out ) # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables" >&5
+echo "$as_me: error: C compiler cannot create executables" >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_declaration
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+rm -f .deps 2>/dev/null
+mkdir .deps 2>/dev/null
+if test -d .deps; then
+ DEPDIR=.deps
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ DEPDIR=_deps
+fi
+rmdir .deps 2>/dev/null
+
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+doit:
+ @echo done
+END
+# If we don't find an include directive, just comment out the code.
+echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval="$enable_dependency_tracking"
+
+fi;
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+
+
+if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+
+depcc="$CC" am_compiler_list=
+
+echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ echo '#include "conftest.h"' > conftest.c
+ echo 'int i;' > conftest.h
+ echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=conftest.c object=conftest.o \
+ depfile=conftest.Po tmpdepfile=conftest.TPo \
+ $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 &&
+ grep conftest.h conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+
+
+if test "x$cflags_specified" = "x" ; then
+ CFLAGS="$CFLAGS -Wall"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ AR=$ac_ct_AR
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+
+
+echo "$as_me:$LINENO: checking for AIX" >&5
+echo $ECHO_N "checking for AIX... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#ifdef _AIX
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+cat >>confdefs.h <<\_ACEOF
+#define _ALL_SOURCE 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+
+# Check whether --enable-vtysh or --disable-vtysh was given.
+if test "${enable_vtysh+set}" = set; then
+ enableval="$enable_vtysh"
+
+fi;
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+ enableval="$enable_ipv6"
+
+fi;
+# Check whether --enable-zebra or --disable-zebra was given.
+if test "${enable_zebra+set}" = set; then
+ enableval="$enable_zebra"
+
+fi;
+# Check whether --enable-bgpd or --disable-bgpd was given.
+if test "${enable_bgpd+set}" = set; then
+ enableval="$enable_bgpd"
+
+fi;
+# Check whether --enable-ripd or --disable-ripd was given.
+if test "${enable_ripd+set}" = set; then
+ enableval="$enable_ripd"
+
+fi;
+# Check whether --enable-ripngd or --disable-ripngd was given.
+if test "${enable_ripngd+set}" = set; then
+ enableval="$enable_ripngd"
+
+fi;
+# Check whether --enable-ospfd or --disable-ospfd was given.
+if test "${enable_ospfd+set}" = set; then
+ enableval="$enable_ospfd"
+
+fi;
+# Check whether --enable-ospf6d or --disable-ospf6d was given.
+if test "${enable_ospf6d+set}" = set; then
+ enableval="$enable_ospf6d"
+
+fi;
+# Check whether --enable-isisd or --disable-isisd was given.
+if test "${enable_isisd+set}" = set; then
+ enableval="$enable_isisd"
+
+fi;
+# Check whether --enable-bgp-announce or --disable-bgp-announce was given.
+if test "${enable_bgp_announce+set}" = set; then
+ enableval="$enable_bgp_announce"
+
+fi;
+# Check whether --enable-netlink or --disable-netlink was given.
+if test "${enable_netlink+set}" = set; then
+ enableval="$enable_netlink"
+
+fi;
+# Check whether --enable-broken-aliases or --disable-broken-aliases was given.
+if test "${enable_broken_aliases+set}" = set; then
+ enableval="$enable_broken_aliases"
+
+fi;
+# Check whether --enable-snmp or --disable-snmp was given.
+if test "${enable_snmp+set}" = set; then
+ enableval="$enable_snmp"
+
+fi;
+
+# Check whether --with-libpam or --without-libpam was given.
+if test "${with_libpam+set}" = set; then
+ withval="$with_libpam"
+
+fi;
+# Check whether --enable-tcpsock or --disable-tcpsock was given.
+if test "${enable_tcpsock+set}" = set; then
+ enableval="$enable_tcpsock"
+
+fi;
+# Check whether --enable-nssa or --disable-nssa was given.
+if test "${enable_nssa+set}" = set; then
+ enableval="$enable_nssa"
+
+fi;
+# Check whether --enable-opaque-lsa or --disable-opaque-lsa was given.
+if test "${enable_opaque_lsa+set}" = set; then
+ enableval="$enable_opaque_lsa"
+
+fi;
+# Check whether --enable-ospf-te or --disable-ospf-te was given.
+if test "${enable_ospf_te+set}" = set; then
+ enableval="$enable_ospf_te"
+
+fi;
+# Check whether --enable-multipath or --disable-multipath was given.
+if test "${enable_multipath+set}" = set; then
+ enableval="$enable_multipath"
+
+fi;
+
+
+if test "${enable_broken_aliases}" = "yes"; then
+ if test "${enable_netlink}" = "yes"
+ then
+ echo "Sorry, you can't use netlink with broken aliases"
+ exit 1
+ fi
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_BROKEN_ALIASES 1
+_ACEOF
+
+ enable_netlink=no
+fi
+
+if test "${enable_tcp_zebra}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_TCP_ZEBRA 1
+_ACEOF
+
+fi
+
+if test "${enable_nssa}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NSSA 1
+_ACEOF
+
+fi
+
+if test "${enable_opaque_lsa}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPAQUE_LSA 1
+_ACEOF
+
+fi
+
+if test "${enable_ospf_te}" = "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPAQUE_LSA 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_OSPF_TE 1
+_ACEOF
+
+fi
+
+
+
+MULTIPATH_NUM=1
+
+case "${enable_multipath}" in
+ [0-9]|[1-9][0-9])
+ MULTIPATH_NUM="${enable_multipath}"
+ ;;
+ "")
+ ;;
+ *)
+ echo "Please specify digit to --enable-multipath ARG."
+ exit 1
+ ;;
+esac
+
+
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_const=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_signal=void
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_type_signal=int
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+case "$host" in
+ *-sunos5.6* | *-solaris2.6*)
+ opsys=sol2-6
+ cat >>confdefs.h <<\_ACEOF
+#define SUNOS_5 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for main in -lxnet" >&5
+echo $ECHO_N "checking for main in -lxnet... $ECHO_C" >&6
+if test "${ac_cv_lib_xnet_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxnet $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_xnet_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_xnet_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_xnet_main" >&5
+echo "${ECHO_T}$ac_cv_lib_xnet_main" >&6
+if test $ac_cv_lib_xnet_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBXNET 1
+_ACEOF
+
+ LIBS="-lxnet $LIBS"
+
+fi
+
+ CURSES=-lcurses
+ ;;
+ *-sunos5* | *-solaris2*)
+ cat >>confdefs.h <<\_ACEOF
+#define SUNOS_5 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for main in -lsocket" >&5
+echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_socket_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_main" >&6
+if test $ac_cv_lib_socket_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for main in -lnsl" >&5
+echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_nsl_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6
+if test $ac_cv_lib_nsl_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+ CURSES=-lcurses
+ ;;
+ *-linux-*)
+ opsys=gnu-linux
+ cat >>confdefs.h <<\_ACEOF
+#define GNU_LINUX 1
+_ACEOF
+
+ ;;
+ *-nec-sysv4*)
+
+echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6
+if test $ac_cv_lib_nsl_gethostbyname = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for socket in -lsocket" >&5
+echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6
+if test "${ac_cv_lib_socket_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+socket ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_socket_socket=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_socket_socket=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6
+if test $ac_cv_lib_socket_socket = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+ ;;
+ *-freebsd3.2)
+ cat >>confdefs.h <<\_ACEOF
+#define FREEBSD_32 1
+_ACEOF
+
+ ;;
+ *-openbsd*)
+ opsys=openbsd
+ cat >>confdefs.h <<\_ACEOF
+#define OPEN_BSD 1
+_ACEOF
+
+ ;;
+ *-bsdi*)
+ opsys=bsdi
+ OTHER_METHOD="mtu_kvm.o"
+
+echo "$as_me:$LINENO: checking for main in -lkvm" >&5
+echo $ECHO_N "checking for main in -lkvm... $ECHO_C" >&6
+if test "${ac_cv_lib_kvm_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkvm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_kvm_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_kvm_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_kvm_main" >&5
+echo "${ECHO_T}$ac_cv_lib_kvm_main" >&6
+if test $ac_cv_lib_kvm_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBKVM 1
+_ACEOF
+
+ LIBS="-lkvm $LIBS"
+
+fi
+
+ ;;
+esac
+
+case "${host_cpu}-${host_os}" in
+ i?86-solaris*)
+ cat >>confdefs.h <<\_ACEOF
+#define SOLARIS_X86 1
+_ACEOF
+
+ ;;
+esac
+
+case "${enable_vtysh}" in
+ "yes") VTYSH="vtysh";
+ cat >>confdefs.h <<\_ACEOF
+#define VTYSH 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for tputs in -ltinfo" >&5
+echo $ECHO_N "checking for tputs in -ltinfo... $ECHO_C" >&6
+if test "${ac_cv_lib_tinfo_tputs+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltinfo $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tputs ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+tputs ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tinfo_tputs=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tinfo_tputs=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tinfo_tputs" >&5
+echo "${ECHO_T}$ac_cv_lib_tinfo_tputs" >&6
+if test $ac_cv_lib_tinfo_tputs = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTINFO 1
+_ACEOF
+
+ LIBS="-ltinfo $LIBS"
+
+else
+
+echo "$as_me:$LINENO: checking for tputs in -lncurses" >&5
+echo $ECHO_N "checking for tputs in -lncurses... $ECHO_C" >&6
+if test "${ac_cv_lib_ncurses_tputs+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lncurses $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tputs ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+tputs ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ncurses_tputs=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_ncurses_tputs=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tputs" >&5
+echo "${ECHO_T}$ac_cv_lib_ncurses_tputs" >&6
+if test $ac_cv_lib_ncurses_tputs = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNCURSES 1
+_ACEOF
+
+ LIBS="-lncurses $LIBS"
+
+fi
+
+fi
+
+
+echo "$as_me:$LINENO: checking for main in -lreadline" >&5
+echo $ECHO_N "checking for main in -lreadline... $ECHO_C" >&6
+if test "${ac_cv_lib_readline_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_readline_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_readline_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_readline_main" >&5
+echo "${ECHO_T}$ac_cv_lib_readline_main" >&6
+if test $ac_cv_lib_readline_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBREADLINE 1
+_ACEOF
+
+ LIBS="-lreadline $LIBS"
+
+fi
+
+ if test $ac_cv_lib_readline_main = no; then
+ { { echo "$as_me:$LINENO: error: vtysh needs libreadline but was not found on your system." >&5
+echo "$as_me: error: vtysh needs libreadline but was not found on your system." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ if test "${ac_cv_header_readline_history_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for readline/history.h" >&5
+echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6
+if test "${ac_cv_header_readline_history_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5
+echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking readline/history.h usability" >&5
+echo $ECHO_N "checking readline/history.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <readline/history.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking readline/history.h presence" >&5
+echo $ECHO_N "checking readline/history.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <readline/history.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;};;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: readline/history.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: readline/history.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for readline/history.h" >&5
+echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6
+if test "${ac_cv_header_readline_history_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_readline_history_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5
+echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6
+
+fi
+
+
+ if test $ac_cv_header_readline_history_h = no;then
+ { { echo "$as_me:$LINENO: error: readline is too old to have readline/history.h, please update to the latest readline library." >&5
+echo "$as_me: error: readline is too old to have readline/history.h, please update to the latest readline library." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ;;
+ "no" ) VTYSH="";;
+ * ) ;;
+esac
+
+if test "$with_libpam" = "yes"; then
+echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5
+echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_pam_start+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pam_start ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+pam_start ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_pam_start=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_pam_start=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6
+if test $ac_cv_lib_pam_pam_start = yes; then
+ echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5
+echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_misc_conv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char misc_conv ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+misc_conv ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_misc_conv=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_misc_conv=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6
+if test $ac_cv_lib_pam_misc_conv = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam"
+else
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam -lpam_misc"
+
+fi
+
+
+else
+ echo "$as_me:$LINENO: checking for pam_end in -lpam" >&5
+echo $ECHO_N "checking for pam_end in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_pam_end+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam -ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pam_end ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+pam_end ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_pam_end=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_pam_end=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_end" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_end" >&6
+if test $ac_cv_lib_pam_pam_end = yes; then
+ echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5
+echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_misc_conv+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char misc_conv ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+misc_conv ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pam_misc_conv=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pam_misc_conv=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6
+if test $ac_cv_lib_pam_misc_conv = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam -ldl"
+else
+ cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+ LIBPAM="-lpam -ldl -lpam_misc"
+
+fi
+
+
+else
+ { echo "$as_me:$LINENO: WARNING: *** pam support will not be built ***" >&5
+echo "$as_me: WARNING: *** pam support will not be built ***" >&2;}
+fi
+
+
+
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in setproctitle
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: checking for setproctitle in -lutil" >&5
+echo $ECHO_N "checking for setproctitle in -lutil... $ECHO_C" >&6
+if test "${ac_cv_lib_util_setproctitle+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lutil $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char setproctitle ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+setproctitle ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_util_setproctitle=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_util_setproctitle=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_util_setproctitle" >&5
+echo "${ECHO_T}$ac_cv_lib_util_setproctitle" >&6
+if test $ac_cv_lib_util_setproctitle = yes; then
+ LIBS="$LIBS -lutil"; cat >>confdefs.h <<\_ACEOF
+#define HAVE_SETPROCTITLE 1
+_ACEOF
+
+fi
+
+fi
+done
+
+
+echo "$as_me:$LINENO: checking zebra between kernel interface method" >&5
+echo $ECHO_N "checking zebra between kernel interface method... $ECHO_C" >&6
+if test x"$opsys" = x"gnu-linux"; then
+ if test "${enable_netlink}" = "yes";then
+ echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+ RT_METHOD=rt_netlink.o
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NETLINK 1
+_ACEOF
+
+ netlink=yes
+ elif test "${enable_netlink}" = "no"; then
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+ RT_METHOD=rt_ioctl.o
+ netlink=no
+ else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <linux/autoconf.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 131328 /* 2.1.0 or later */
+#ifdef CONFIG_RTNETLINK
+ yes
+#endif
+#endif
+#if LINUX_VERSION_CODE > 132112 /* 2.4.17 or later */
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+ RT_METHOD=rt_netlink.o
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NETLINK 1
+_ACEOF
+
+ netlink=yes
+else
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+ RT_METHOD=rt_ioctl.o
+fi
+rm -f conftest*
+
+ fi
+else
+ if test "$opsys" = "sol2-6";then
+ echo "$as_me:$LINENO: result: solaris" >&5
+echo "${ECHO_T}solaris" >&6
+ KERNEL_METHOD="kernel_socket.o"
+ RT_METHOD="rt_socket.o"
+ else
+ if test "$cross_compiling" = yes; then
+ KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ echo "$as_me:$LINENO: result: socket" >&5
+echo "${ECHO_T}socket" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+main ()
+{
+ int ac_sock;
+
+ ac_sock = socket (AF_ROUTE, SOCK_RAW, 0);
+ if (ac_sock < 0 && errno == EINVAL)
+ exit (1);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_AF_ROUTE 1
+_ACEOF
+
+ KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ echo "$as_me:$LINENO: result: socket" >&5
+echo "${ECHO_T}socket" >&6
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+( exit $ac_status )
+RT_METHOD=rt_ioctl.o
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+fi
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ fi
+fi
+
+
+
+
+echo "$as_me:$LINENO: checking route read method check" >&5
+echo $ECHO_N "checking route read method check... $ECHO_C" >&6
+if test "${zebra_rtread+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$netlink" = yes; then
+ RTREAD_METHOD="rtread_netlink.o"
+ zebra_rtread="netlink"
+else
+for zebra_rtread in /proc/net/route /dev/ip /dev/null;
+do
+ test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break
+done
+case $zebra_rtread in
+ "/proc/net/route") RTREAD_METHOD="rtread_proc.o"
+ zebra_rtread="proc";;
+ "/dev/ip") RTREAD_METHOD="rtread_getmsg.o"
+ zebra_rtread="getmsg";;
+ *) RTREAD_METHOD="rtread_sysctl.o"
+ zebra_rtread="sysctl";;
+esac
+fi
+fi
+echo "$as_me:$LINENO: result: $zebra_rtread" >&5
+echo "${ECHO_T}$zebra_rtread" >&6
+
+
+echo "$as_me:$LINENO: checking interface looking up method" >&5
+echo $ECHO_N "checking interface looking up method... $ECHO_C" >&6
+if test "$netlink" = yes; then
+ echo "$as_me:$LINENO: result: netlink" >&5
+echo "${ECHO_T}netlink" >&6
+ IF_METHOD=if_netlink.o
+else
+ if test "$opsys" = "sol2-6";then
+ echo "$as_me:$LINENO: result: solaris" >&5
+echo "${ECHO_T}solaris" >&6
+ IF_METHOD=if_ioctl.o
+ elif test "$opsys" = "openbsd";then
+ echo "$as_me:$LINENO: result: openbsd" >&5
+echo "${ECHO_T}openbsd" >&6
+ IF_METHOD=if_ioctl.o
+ elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: sysctl" >&5
+echo "${ECHO_T}sysctl" >&6
+ IF_METHOD=if_sysctl.o
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_NET_RT_IFLIST 1
+_ACEOF
+
+ else
+ echo "$as_me:$LINENO: result: ioctl" >&5
+echo "${ECHO_T}ioctl" >&6
+ IF_METHOD=if_ioctl.o
+ fi
+fi
+
+
+if test -r /proc/net/dev; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_NET_DEV 1
+_ACEOF
+
+ IF_PROC=if_proc.o
+fi
+
+if test -r /proc/net/if_inet6; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_NET_IF_INET6 1
+_ACEOF
+
+ IF_PROC=if_proc.o
+fi
+
+
+echo "$as_me:$LINENO: checking ipforward method check" >&5
+echo $ECHO_N "checking ipforward method check... $ECHO_C" >&6
+if test "${zebra_ipforward_path+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null;
+do
+ test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break
+done
+case $zebra_ipforward_path in
+ "/proc/net/snmp") IPFORWARD=ipforward_proc.o
+ zebra_ipforward_path="proc";;
+ "/dev/ip")
+ case "$host" in
+ *-nec-sysv4*) IPFORWARD=ipforward_ews.o
+ zebra_ipforward_path="ews";;
+ *) IPFORWARD=ipforward_solaris.o
+ zebra_ipforward_path="solaris";;
+ esac;;
+ *) IPFORWARD=ipforward_sysctl.o
+ zebra_ipforward_path="sysctl";;
+esac
+fi
+echo "$as_me:$LINENO: result: $zebra_ipforward_path" >&5
+echo "${ECHO_T}$zebra_ipforward_path" >&6
+
+
+
+for ac_func in getaddrinfo
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ have_getaddrinfo=yes
+else
+ have_getaddrinfo=no
+fi
+done
+
+
+echo "$as_me:$LINENO: checking whether does this OS have IPv6 stack" >&5
+echo $ECHO_N "checking whether does this OS have IPv6 stack... $ECHO_C" >&6
+if test "${enable_ipv6}" = "no"; then
+ echo "$as_me:$LINENO: result: disabled" >&5
+echo "${ECHO_T}disabled" >&6
+else
+if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define INRIA_IPV6 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ LIB_IPV6=""
+ echo "$as_me:$LINENO: result: INRIA IPv6" >&5
+echo "${ECHO_T}INRIA IPv6" >&6
+fi
+if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define KAME 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then
+ LIB_IPV6="-L/usr/local/v6/lib -linet6"
+ fi
+ echo "$as_me:$LINENO: result: KAME" >&5
+echo "${ECHO_T}KAME" >&6
+fi
+if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define NRL 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test x"$opsys" = x"bsdi";then
+ cat >>confdefs.h <<\_ACEOF
+#define BSDI_NRL 1
+_ACEOF
+
+ echo "$as_me:$LINENO: result: BSDI_NRL" >&5
+echo "${ECHO_T}BSDI_NRL" >&6
+ else
+ echo "$as_me:$LINENO: result: NRL" >&5
+echo "${ECHO_T}NRL" >&6
+ fi
+fi
+
+if test "${enable_ipv6}" = "yes"; then
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+ #include <linux/version.h>
+ /* 2.1.128 or later */
+ #if LINUX_VERSION_CODE >= 0x020180
+ yes
+ #endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;echo "$as_me:$LINENO: result: Linux IPv6" >&5
+echo "${ECHO_T}Linux IPv6" >&6
+fi
+rm -f conftest*
+
+else
+ if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route"
+ then
+ zebra_cv_ipv6=yes
+ zebra_cv_linux_ipv6=yes
+ echo "$as_me:$LINENO: result: Linux IPv6" >&5
+echo "${ECHO_T}Linux IPv6" >&6
+ fi
+fi
+
+if test "$zebra_cv_linux_ipv6" = "yes";then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+ echo "$as_me:$LINENO: checking for GNU libc 2.1" >&5
+echo $ECHO_N "checking for GNU libc 2.1... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#include <features.h>
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+ yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ glibc=yes; echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+ cat >>confdefs.h <<\_ACEOF
+#define LINUX_IPV6 1
+_ACEOF
+
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test "$glibc" != "yes"; then
+ INCLUDES="-I/usr/inet6/include"
+ if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then
+ LIB_IPV6="-L/usr/inet6/lib -linet6"
+ fi
+ fi
+fi
+
+LIBS="$LIB_IPV6 $LIBS"
+
+
+if test x"$RIPNGD" = x""; then
+ echo "$as_me:$LINENO: result: IPv4 only" >&5
+echo "${ECHO_T}IPv4 only" >&6
+fi
+fi
+
+if test "${enable_zebra}" = "no";then
+ ZEBRA=""
+else
+ ZEBRA="zebra"
+fi
+
+if test "${enable_bgpd}" = "no";then
+ BGPD=""
+else
+ BGPD="bgpd"
+fi
+
+if test "${enable_ripd}" = "no";then
+ RIPD=""
+else
+ RIPD="ripd"
+fi
+
+if test "${enable_ospfd}" = "no";then
+ OSPFD=""
+else
+ OSPFD="ospfd"
+fi
+
+case "${enable_ripngd}" in
+ "yes") RIPNGD="ripngd";;
+ "no" ) RIPNGD="";;
+ * ) ;;
+esac
+
+case "${enable_ospf6d}" in
+ "yes") OSPF6D="ospf6d";;
+ "no" ) OSPF6D="";;
+ * ) ;;
+esac
+
+case "${enable_isisd}" in
+ "yes") ISISD="isisd";;
+ "no" ) ISISD="";;
+ * ) ;;
+esac
+
+if test "${enable_bgp_announce}" = "no";then
+ cat >>confdefs.h <<\_ACEOF
+#define DISABLE_BGP_ANNOUNCE 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+echo "$as_me:$LINENO: checking for inet_ntop in -lc" >&5
+echo $ECHO_N "checking for inet_ntop in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_inet_ntop+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_ntop ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+inet_ntop ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_inet_ntop=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_c_inet_ntop=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_ntop" >&5
+echo "${ECHO_T}$ac_cv_lib_c_inet_ntop" >&6
+if test $ac_cv_lib_c_inet_ntop = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_NTOP 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for inet_pton in -lc" >&5
+echo $ECHO_N "checking for inet_pton in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_inet_pton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inet_pton ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+inet_pton ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_inet_pton=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_c_inet_pton=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_pton" >&5
+echo "${ECHO_T}$ac_cv_lib_c_inet_pton" >&6
+if test $ac_cv_lib_c_inet_pton = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_PTON 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5
+echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6
+if test "${ac_cv_lib_crypt_crypt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_crypt_crypt=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_crypt_crypt=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5
+echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6
+if test $ac_cv_lib_crypt_crypt = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPT 1
+_ACEOF
+
+ LIBS="-lcrypt $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for res_init in -lresolv" >&5
+echo $ECHO_N "checking for res_init in -lresolv... $ECHO_C" >&6
+if test "${ac_cv_lib_resolv_res_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char res_init ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+res_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_resolv_res_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_resolv_res_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_init" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_res_init" >&6
+if test $ac_cv_lib_resolv_res_init = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for main in -lm" >&5
+echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_m_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_m_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5
+echo "${ECHO_T}$ac_cv_lib_m_main" >&6
+if test $ac_cv_lib_m_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for __inet_ntop" >&5
+echo $ECHO_N "checking for __inet_ntop... $ECHO_C" >&6
+if test "${ac_cv_func___inet_ntop+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __inet_ntop (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __inet_ntop ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___inet_ntop) || defined (__stub_____inet_ntop)
+choke me
+#else
+f = __inet_ntop;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___inet_ntop=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func___inet_ntop=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___inet_ntop" >&5
+echo "${ECHO_T}$ac_cv_func___inet_ntop" >&6
+if test $ac_cv_func___inet_ntop = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_NTOP 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for __inet_pton" >&5
+echo $ECHO_N "checking for __inet_pton... $ECHO_C" >&6
+if test "${ac_cv_func___inet_pton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __inet_pton (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __inet_pton ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___inet_pton) || defined (__stub_____inet_pton)
+choke me
+#else
+f = __inet_pton;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___inet_pton=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func___inet_pton=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___inet_pton" >&5
+echo "${ECHO_T}$ac_cv_func___inet_pton" >&6
+if test $ac_cv_func___inet_pton = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_PTON 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for __inet_aton" >&5
+echo $ECHO_N "checking for __inet_aton... $ECHO_C" >&6
+if test "${ac_cv_func___inet_aton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char __inet_aton (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __inet_aton ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub___inet_aton) || defined (__stub_____inet_aton)
+choke me
+#else
+f = __inet_aton;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func___inet_aton=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func___inet_aton=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func___inet_aton" >&5
+echo "${ECHO_T}$ac_cv_func___inet_aton" >&6
+if test $ac_cv_func___inet_aton = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INET_ATON 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for regexec in -lc" >&5
+echo $ECHO_N "checking for regexec in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_regexec+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char regexec ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+regexec ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_regexec=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_c_regexec=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_regexec" >&5
+echo "${ECHO_T}$ac_cv_lib_c_regexec" >&6
+if test $ac_cv_lib_c_regexec = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_GNU_REGEX 1
+_ACEOF
+
+ LIB_REGEX=""
+else
+ LIB_REGEX="regex.o"
+fi
+
+
+
+
+if test "${enable_snmp}" = "yes";then
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ unset ac_cv_lib_snmp_asn_parse_int
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes
+fi
+
+ if test "${HAVE_SNMP}" = ""; then
+ unset ac_cv_lib_snmp_asn_parse_int
+ echo "$as_me:$LINENO: checking for main in -lcrypto" >&5
+echo $ECHO_N "checking for main in -lcrypto... $ECHO_C" >&6
+if test "${ac_cv_lib_crypto_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_crypto_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_crypto_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_main" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_main" >&6
+if test $ac_cv_lib_crypto_main = yes; then
+ NEED_CRYPTO=yes
+fi
+
+ if test "${NEED_CRYPTO}" = ""; then
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes; NEED_CRYPTO=yes
+fi
+
+ else
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp "-lcrypto" $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto"
+fi
+
+ fi
+ fi
+ LIBS="${old_libs}"
+
+ if test "${HAVE_SNMP}" = ""; then
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5
+echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6
+if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsnmp $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char asn_parse_int ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+asn_parse_int ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_snmp_asn_parse_int=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_snmp_asn_parse_int=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5
+echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6
+if test $ac_cv_lib_snmp_asn_parse_int = yes; then
+ HAVE_SNMP=yes
+fi
+
+ LIBS="${old_libs}"
+ fi
+ if test "${HAVE_SNMP}" = "yes"; then
+ for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null
+ do
+ test -f "${ac_snmp}" && break
+ done
+ case ${ac_snmp} in
+ /usr/include/ucd-snmp/*)
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SNMP 1
+_ACEOF
+
+ CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp"
+ LIBS="${LIBS} -lsnmp"
+ ;;
+ /usr/local/include/ucd-snmp/*)
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SNMP 1
+_ACEOF
+
+ CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp"
+ LIBS="${LIBS} -L/usr/local/lib -lsnmp"
+ ;;
+ esac
+ if test "${NEED_CRYPTO}" = "yes"; then
+ LIBS="${LIBS} -lcrypto"
+ fi
+ fi
+fi
+
+echo "$as_me:$LINENO: checking whether struct sockaddr has a sa_len field" >&5
+echo $ECHO_N "checking whether struct sockaddr has a sa_len field... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether struct sockaddr_in has a sin_len field" >&5
+echo $ECHO_N "checking whether struct sockaddr_in has a sin_len field... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN_LEN 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether struct sockaddr_un has a sun_len field" >&5
+echo $ECHO_N "checking whether struct sockaddr_un has a sun_len field... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/un.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SUN_LEN 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+if test "$zebra_cv_ipv6" = yes; then
+ echo "$as_me:$LINENO: checking whether struct sockaddr_in6 has a sin6_scope_id field" >&5
+echo $ECHO_N "checking whether struct sockaddr_in6 has a sin6_scope_id field... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIN6_SCOPE_ID 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+
+echo "$as_me:$LINENO: checking whther socklen_t is defined" >&5
+echo $ECHO_N "checking whther socklen_t is defined... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+socklen_t ac_x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOCKLEN_T 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether struct sockaddr_dl exist" >&5
+echo $ECHO_N "checking whether struct sockaddr_dl exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <net/if_dl.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "sockaddr_dl" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SOCKADDR_DL 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct ifaliasreq exist" >&5
+echo $ECHO_N "checking whether struct ifaliasreq exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <net/if.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "ifaliasreq" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IFALIASREQ 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct if6_aliasreq exist" >&5
+echo $ECHO_N "checking whether struct if6_aliasreq exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <netinet6/in6_var.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "in6_aliasreq" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_IN6_ALIASREQ 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct rt_addrinfo exist" >&5
+echo $ECHO_N "checking whether struct rt_addrinfo exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <net/route.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "rt_addrinfo" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_RT_ADDRINFO 1
+_ACEOF
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking whether struct in_pktinfo exist" >&5
+echo $ECHO_N "checking whether struct in_pktinfo exist... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <netinet/in.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+struct in_pktinfo ac_x;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_INPKTINFO 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking whether getrusage is available" >&5
+echo $ECHO_N "checking whether getrusage is available... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <sys/resource.h>
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_RUSAGE 1
+_ACEOF
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+file="${srcdir}/lib/version.h"
+VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file`
+
+
+echo "$as_me:$LINENO: checking pid file directory" >&5
+echo $ECHO_N "checking pid file directory... $ECHO_C" >&6
+if test "${ac_piddir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ for ZEBRA_PID_DIR in /var/run /var/adm /etc /dev/null;
+do
+ test -d $ZEBRA_PID_DIR && break
+done
+ac_piddir=$ZEBRA_PID_DIR
+if test $ZEBRA_PID_DIR = "/dev/null"; then
+ echo "PID DIRECTORY NOT FOUND!"
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_piddir" >&5
+echo "${ECHO_T}$ac_piddir" >&6
+cat >>confdefs.h <<_ACEOF
+#define PATH_ZEBRA_PID "$ac_piddir/zebra.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_RIPD_PID "$ac_piddir/ripd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_RIPNGD_PID "$ac_piddir/ripngd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_BGPD_PID "$ac_piddir/bgpd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_OSPFD_PID "$ac_piddir/ospfd.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_OSPF6D_PID "$ac_piddir/ospf6d.pid"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PATH_ISISD_PID "$ac_piddir/isisd.pid"
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for working htonl" >&5
+echo $ECHO_N "checking for working htonl... $ECHO_C" >&6
+if test "${ac_cv_htonl_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+htonl (0);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_htonl_works=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_htonl_works=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+
+echo "$as_me:$LINENO: result: $ac_cv_htonl_works" >&5
+echo "${ECHO_T}$ac_cv_htonl_works" >&6
+
+ac_config_files="$ac_config_files Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overriden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if cmp -s $cache_file confcache; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# NLS nuisances.
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+(set +x; test -n "`(LANG=C; export LANG) 2>&1`") &&
+ { $as_unset LANG || test "${LANG+set}" != set; } ||
+ { LANG=C; export LANG; }
+(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") &&
+ { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } ||
+ { LC_ALL=C; export LC_ALL; }
+(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") &&
+ { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } ||
+ { LC_TIME=C; export LC_TIME; }
+(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") &&
+ { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } ||
+ { LC_CTYPE=C; export LC_CTYPE; }
+(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") &&
+ { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } ||
+ { LANGUAGE=C; export LANGUAGE; }
+(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") &&
+ { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } ||
+ { LC_COLLATE=C; export LC_COLLATE; }
+(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") &&
+ { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } ||
+ { LC_NUMERIC=C; export LC_NUMERIC; }
+(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") &&
+ { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } ||
+ { LC_MESSAGES=C; export LC_MESSAGES; }
+
+
+# Name of the executable.
+as_me=`(basename "$0") 2>/dev/null ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conftest.sh
+ echo "exit 0" >>conftest.sh
+ chmod +x conftest.sh
+ if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conftest.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.53. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.53,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ shift
+ set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
+ shift
+ ;;
+ -*);;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_need_defaults=false;;
+ esac
+
+ case $1 in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+ exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ shift
+ CONFIG_FILES="$CONFIG_FILES $1"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $1"
+ ac_need_defaults=false;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS section.
+#
+
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+ "zebra/Makefile" ) CONFIG_FILES="$CONFIG_FILES zebra/Makefile" ;;
+ "ripd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripd/Makefile" ;;
+ "ripngd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripngd/Makefile" ;;
+ "bgpd/Makefile" ) CONFIG_FILES="$CONFIG_FILES bgpd/Makefile" ;;
+ "ospfd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospfd/Makefile" ;;
+ "ospf6d/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospf6d/Makefile" ;;
+ "isisd/Makefile" ) CONFIG_FILES="$CONFIG_FILES isisd/Makefile" ;;
+ "vtysh/Makefile" ) CONFIG_FILES="$CONFIG_FILES vtysh/Makefile" ;;
+ "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=$TMPDIR/cs$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@ACLOCAL@,$ACLOCAL,;t t
+s,@AUTOCONF@,$AUTOCONF,;t t
+s,@AUTOMAKE@,$AUTOMAKE,;t t
+s,@AUTOHEADER@,$AUTOHEADER,;t t
+s,@MAKEINFO@,$MAKEINFO,;t t
+s,@AMTAR@,$AMTAR,;t t
+s,@install_sh@,$install_sh,;t t
+s,@STRIP@,$STRIP,;t t
+s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
+s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
+s,@AWK@,$AWK,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@DEPDIR@,$DEPDIR,;t t
+s,@am__include@,$am__include,;t t
+s,@am__quote@,$am__quote,;t t
+s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t
+s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t
+s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
+s,@CCDEPMODE@,$CCDEPMODE,;t t
+s,@CPP@,$CPP,;t t
+s,@AR@,$AR,;t t
+s,@ac_ct_AR@,$ac_ct_AR,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@MULTIPATH_NUM@,$MULTIPATH_NUM,;t t
+s,@LIBPAM@,$LIBPAM,;t t
+s,@RT_METHOD@,$RT_METHOD,;t t
+s,@KERNEL_METHOD@,$KERNEL_METHOD,;t t
+s,@OTHER_METHOD@,$OTHER_METHOD,;t t
+s,@RTREAD_METHOD@,$RTREAD_METHOD,;t t
+s,@IF_METHOD@,$IF_METHOD,;t t
+s,@IF_PROC@,$IF_PROC,;t t
+s,@IPFORWARD@,$IPFORWARD,;t t
+s,@LIB_IPV6@,$LIB_IPV6,;t t
+s,@ZEBRA@,$ZEBRA,;t t
+s,@BGPD@,$BGPD,;t t
+s,@RIPD@,$RIPD,;t t
+s,@RIPNGD@,$RIPNGD,;t t
+s,@OSPFD@,$OSPFD,;t t
+s,@OSPF6D@,$OSPF6D,;t t
+s,@ISISD@,$ISISD,;t t
+s,@VTYSH@,$VTYSH,;t t
+s,@INCLUDES@,$INCLUDES,;t t
+s,@CURSES@,$CURSES,;t t
+s,@LIB_REGEX@,$LIB_REGEX,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" ||
+ mkdir "$as_incr_dir" ||
+ { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+done; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h. The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status. Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless. Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo ' :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+ # Write a limited-size here document to $tmp/defines.sed.
+ echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#define' lines.
+ echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/defines.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo ' fi # egrep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo ' # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+ # Write a limited-size here document to $tmp/undefs.sed.
+ echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+ # Speed up: don't consider the non `#undef'
+ echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS
+ # Work around the forget-to-reset-the-flag bug.
+ echo 't clr' >>$CONFIG_STATUS
+ echo ': clr' >>$CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+ rm -f $tmp/in
+ mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+ rm -f conftest.undefs
+ mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if cmp -s $ac_file $tmp/config.h 2>/dev/null; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" ||
+ mkdir "$as_incr_dir" ||
+ { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+done; }
+
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+ # Run the commands associated with the file.
+ case $ac_file in
+ config.h ) # update the timestamp
+echo 'timestamp for config.h' >"./stamp-h1"
+ ;;
+ esac
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_COMMANDS section.
+#
+for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
+ ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
+ ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
+$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_dest" : 'X\(//\)[^/]' \| \
+ X"$ac_dest" : 'X\(//\)$' \| \
+ X"$ac_dest" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_dest" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
+echo "$as_me: executing $ac_dest commands" >&6;}
+ case $ac_dest in
+ depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # So let's grep whole file.
+ if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
+ dirpart=`(dirname "$mf") 2>/dev/null ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue
+ # Extract the definition of DEP_FILES from the Makefile without
+ # running `make'.
+ DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n -e '/^U = / s///p' < "$mf"`
+ test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR"
+ # We invoke sed twice because it is the simplest approach to
+ # changing $(DEPDIR) to its actual value in the expansion.
+ for file in `sed -n -e '
+ /^DEP_FILES = .*\\\\$/ {
+ s/^DEP_FILES = //
+ :loop
+ s/\\\\$//
+ p
+ n
+ /\\\\$/ b loop
+ p
+ }
+ /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`(dirname "$file") 2>/dev/null ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { case $dirpart/$fdir in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy=$dirpart/$fdir
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" ||
+ mkdir "$as_incr_dir" ||
+ { { echo "$as_me:$LINENO: error: cannot create $dirpart/$fdir" >&5
+echo "$as_me: error: cannot create $dirpart/$fdir" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ esac
+done; }
+
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+echo "
+zebra configuration
+-------------------
+zebra version : ${VERSION}
+host operationg system : ${host_os}
+source code location : ${srcdir}
+compiler : ${CC}
+compiler flags : ${CFLAGS}
+directory for pid files : ${ac_piddir}
+"
diff --git a/isisd/modified/configure.in b/isisd/modified/configure.in
new file mode 100755
index 00000000..49b508bc
--- /dev/null
+++ b/isisd/modified/configure.in
@@ -0,0 +1,882 @@
+##
+## Configure template file for Zebra.
+## autoconf will generate configure script.
+##
+## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+##
+AC_PREREQ(2.13)
+
+AC_INIT(lib/zebra.h)
+AM_INIT_AUTOMAKE(zebra, 0.93)
+AM_CONFIG_HEADER(config.h)
+
+dnl -----------------------------------
+dnl Get hostname and other information.
+dnl -----------------------------------
+AC_CANONICAL_HOST
+
+dnl ------------
+dnl Check CFLAGS
+dnl ------------
+AC_ARG_WITH(cflags,
+[ --with-cflags Set CFLAGS for use in compilation.])
+if test "x$with_cflags" != "x" ; then
+ CFLAGS="$with_cflags" ; cflags_specified=yes ;
+elif test -n "$CFLAGS" ; then
+ cflags_specified=yes ;
+fi
+
+dnl --------
+dnl Check CC
+dnl --------
+AC_PROG_CC
+
+dnl -----------------------------------------
+dnl If CLFAGS doesn\'t exist set default value
+dnl -----------------------------------------
+if test "x$cflags_specified" = "x" ; then
+ CFLAGS="$CFLAGS -Wall"
+fi
+
+dnl --------------
+dnl Check programs
+dnl --------------
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_CHECK_TOOL(AR, ar)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+
+dnl ---------
+dnl AIX check
+dnl ---------
+AC_AIX
+
+dnl ----------------------
+dnl Packages configuration
+dnl ----------------------
+AC_ARG_ENABLE(vtysh,
+[ --enable-vtysh, Make integrated VTY version of zebra])
+AC_ARG_ENABLE(ipv6,
+[ --disable-ipv6 turn off IPv6 related features and daemons])
+AC_ARG_ENABLE(zebra,
+[ --disable-zebra do not build zebra daemon])
+AC_ARG_ENABLE(bgpd,
+[ --disable-bgpd do not build bgpd])
+AC_ARG_ENABLE(ripd,
+[ --disable-ripd do not build ripd])
+AC_ARG_ENABLE(ripngd,
+[ --disable-ripngd do not build ripngd])
+AC_ARG_ENABLE(ospfd,
+[ --disable-ospfd do not build ospfd])
+AC_ARG_ENABLE(ospf6d,
+[ --disable-ospf6d do not build ospf6d])
+AC_ARG_ENABLE(isisd,
+[ --disable-isisd do not build isisd])
+AC_ARG_ENABLE(bgp-announce,
+[ --disable-bgp-announce, turn off BGP route announcement])
+AC_ARG_ENABLE(netlink,
+[ --enable-netlink force to use Linux netlink interface])
+AC_ARG_ENABLE(broken-aliases,
+[ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X])
+AC_ARG_ENABLE(snmp,
+[ --enable-snmp enable SNMP support])
+AC_ARG_WITH(libpam,
+[ --with-libpam use libpam for PAM support in vtysh])
+AC_ARG_ENABLE(tcpsock,
+[ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon])
+dnl Temporary option until OSPF NSSA implementation complete
+AC_ARG_ENABLE(nssa,
+[ --enable-nssa enable OSPF NSSA option])
+AC_ARG_ENABLE(opaque-lsa,
+[ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)])
+AC_ARG_ENABLE(ospf-te,
+[ --enable-ospf-te enable Traffic Engineering Extension to OSPF])
+AC_ARG_ENABLE(multipath,
+[ --enable-multipath=ARG enable multipath function, ARG must be digit])
+
+dnl AC_ARG_ENABLE(rtadv,
+dnl [ --enable-rtadv enable IPV6 router advertisment option])
+
+if test "${enable_broken_aliases}" = "yes"; then
+ if test "${enable_netlink}" = "yes"
+ then
+ echo "Sorry, you can't use netlink with broken aliases"
+ exit 1
+ fi
+ AC_DEFINE(HAVE_BROKEN_ALIASES)
+ enable_netlink=no
+fi
+
+if test "${enable_tcp_zebra}" = "yes"; then
+ AC_DEFINE(HAVE_TCP_ZEBRA)
+fi
+
+if test "${enable_nssa}" = "yes"; then
+ AC_DEFINE(HAVE_NSSA)
+fi
+
+if test "${enable_opaque_lsa}" = "yes"; then
+ AC_DEFINE(HAVE_OPAQUE_LSA)
+fi
+
+if test "${enable_ospf_te}" = "yes"; then
+ AC_DEFINE(HAVE_OPAQUE_LSA)
+ AC_DEFINE(HAVE_OSPF_TE)
+fi
+
+dnl if test "${enable_rtadv}" = "yes"; then
+dnl AC_DEFINE(HAVE_RTADV)
+dnl fi
+
+changequote(, )dnl
+
+MULTIPATH_NUM=1
+
+case "${enable_multipath}" in
+ [0-9]|[1-9][0-9])
+ MULTIPATH_NUM="${enable_multipath}"
+ ;;
+ "")
+ ;;
+ *)
+ echo "Please specify digit to --enable-multipath ARG."
+ exit 1
+ ;;
+esac
+
+changequote([, ])dnl
+
+AC_SUBST(MULTIPATH_NUM)
+
+dnl -------------------
+dnl Check header files.
+dnl -------------------
+AC_STDC_HEADERS
+AC_CHECK_HEADERS(string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h)
+
+dnl check some types
+AC_C_CONST
+dnl AC_TYPE_PID_T
+AC_TYPE_SIGNAL
+
+dnl Some systems (Solaris 2.x) require libnsl (Network Services Library)
+case "$host" in
+ *-sunos5.6* | *-solaris2.6*)
+ opsys=sol2-6
+ AC_DEFINE(SUNOS_5)
+ AC_CHECK_LIB(xnet, main)
+ CURSES=-lcurses
+ ;;
+ *-sunos5* | *-solaris2*)
+ AC_DEFINE(SUNOS_5)
+ AC_CHECK_LIB(socket, main)
+ AC_CHECK_LIB(nsl, main)
+ CURSES=-lcurses
+ ;;
+ *-linux-*)
+ opsys=gnu-linux
+ AC_DEFINE(GNU_LINUX)
+ ;;
+ *-nec-sysv4*)
+ AC_CHECK_LIB(nsl, gethostbyname)
+ AC_CHECK_LIB(socket, socket)
+ ;;
+ *-freebsd3.2)
+ AC_DEFINE(FREEBSD_32)
+ ;;
+ *-openbsd*)
+ opsys=openbsd
+ AC_DEFINE(OPEN_BSD)
+ ;;
+ *-bsdi*)
+ opsys=bsdi
+ OTHER_METHOD="mtu_kvm.o"
+ AC_CHECK_LIB(kvm, main)
+ ;;
+esac
+
+case "${host_cpu}-${host_os}" in
+ i?86-solaris*)
+ AC_DEFINE(SOLARIS_X86)
+ ;;
+esac
+
+dnl ---------------------
+dnl Integrated VTY option
+dnl ---------------------
+case "${enable_vtysh}" in
+ "yes") VTYSH="vtysh";
+ AC_DEFINE(VTYSH)
+ AC_CHECK_LIB(tinfo, tputs, , AC_CHECK_LIB(ncurses, tputs))
+ AC_CHECK_LIB(readline, main)
+ if test $ac_cv_lib_readline_main = no; then
+ AC_MSG_ERROR([vtysh needs libreadline but was not found on your system.])
+ fi
+ AC_CHECK_HEADER(readline/history.h)
+ if test $ac_cv_header_readline_history_h = no;then
+ AC_MSG_ERROR([readline is too old to have readline/history.h, please update to the latest readline library.])
+ fi
+ ;;
+ "no" ) VTYSH="";;
+ * ) ;;
+esac
+
+dnl ----------
+dnl PAM module
+dnl ----------
+if test "$with_libpam" = "yes"; then
+dnl took this test from proftpd's configure.in and suited to our needs
+dnl -------------------------------------------------------------------------
+dnl
+dnl This next check looks funky due to a linker problem with some versions
+dnl of the PAM library. Prior to 0.72 release, the Linux PAM shared library
+dnl omitted requiring libdl linking information. PAM-0.72 or better ships
+dnl with RedHat 6.2 and Debian 2.2 or better.
+AC_CHECK_LIB(pam, pam_start,
+ [AC_CHECK_LIB(pam, misc_conv,
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam"],
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam -lpam_misc"]
+ )
+ ],
+
+ [AC_CHECK_LIB(pam, pam_end,
+ [AC_CHECK_LIB(pam, misc_conv,
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam -ldl"],
+ [AC_DEFINE(USE_PAM)
+ LIBPAM="-lpam -ldl -lpam_misc"]
+ )
+ ],AC_MSG_WARN([*** pam support will not be built ***]),
+ [-ldl])
+ ]
+)
+fi
+AC_SUBST(LIBPAM)
+
+dnl -------------------------------
+dnl Endian-ness check
+dnl -------------------------------
+AC_DEFUN(ZEBRA_AC_C_BIGENDIAN,
+[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian,
+[ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/param.h>], [
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif], [# It does; now see whether it defined to BIG_ENDIAN or not.
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/param.h>], [
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)])
+if test $ac_cv_c_bigendian = unknown; then
+AC_TRY_RUN([main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)
+fi])
+if test $ac_cv_c_bigendian = yes; then
+ AC_DEFINE(WORDS_BIGENDIAN,1,Big endian words)
+fi
+])
+
+dnl -------------------------------
+dnl check the size in byte of the C
+dnl -------------------------------
+dnl AC_CHECK_SIZEOF(char)
+dnl AC_CHECK_SIZEOF(int)
+dnl AC_CHECK_SIZEOF(short)
+dnl AC_CHECK_SIZEOF(long)
+
+dnl ----------------------------
+dnl check existance of functions
+dnl ----------------------------
+AC_CHECK_FUNCS(bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs)
+AC_CHECK_FUNCS(setproctitle, ,[AC_CHECK_LIB(util, setproctitle, [LIBS="$LIBS -lutil"; AC_DEFINE(HAVE_SETPROCTITLE)])])
+
+dnl ------------------------------------
+dnl Determine routing get and set method
+dnl ------------------------------------
+AC_MSG_CHECKING(zebra between kernel interface method)
+if test x"$opsys" = x"gnu-linux"; then
+ if test "${enable_netlink}" = "yes";then
+ AC_MSG_RESULT(netlink)
+ RT_METHOD=rt_netlink.o
+ AC_DEFINE(HAVE_NETLINK)
+ netlink=yes
+ elif test "${enable_netlink}" = "no"; then
+ AC_MSG_RESULT(ioctl)
+ RT_METHOD=rt_ioctl.o
+ netlink=no
+ else
+ AC_EGREP_CPP(yes,
+ [#include <linux/autoconf.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 131328 /* 2.1.0 or later */
+#ifdef CONFIG_RTNETLINK
+ yes
+#endif
+#endif
+#if LINUX_VERSION_CODE > 132112 /* 2.4.17 or later */
+ yes
+#endif
+ ],
+ [AC_MSG_RESULT(netlink)
+ RT_METHOD=rt_netlink.o
+ AC_DEFINE(HAVE_NETLINK)
+ netlink=yes],
+ [AC_MSG_RESULT(ioctl)
+ RT_METHOD=rt_ioctl.o])
+ fi
+else
+ if test "$opsys" = "sol2-6";then
+ AC_MSG_RESULT(solaris)
+ KERNEL_METHOD="kernel_socket.o"
+ RT_METHOD="rt_socket.o"
+ else
+ AC_TRY_RUN([#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+main ()
+{
+ int ac_sock;
+
+ ac_sock = socket (AF_ROUTE, SOCK_RAW, 0);
+ if (ac_sock < 0 && errno == EINVAL)
+ exit (1);
+ exit (0);
+}],
+ [AC_DEFINE(HAVE_AF_ROUTE)
+ KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ AC_MSG_RESULT(socket)],
+ [RT_METHOD=rt_ioctl.o
+ AC_MSG_RESULT(ioctl)],
+ [KERNEL_METHOD=kernel_socket.o
+ RT_METHOD=rt_socket.o
+ AC_MSG_RESULT(socket)])
+ fi
+fi
+AC_SUBST(RT_METHOD)
+AC_SUBST(KERNEL_METHOD)
+AC_SUBST(OTHER_METHOD)
+
+dnl ------------------------------
+dnl check kernel route read method
+dnl ------------------------------
+AC_CACHE_CHECK(route read method check, zebra_rtread,
+[if test "$netlink" = yes; then
+ RTREAD_METHOD="rtread_netlink.o"
+ zebra_rtread="netlink"
+else
+for zebra_rtread in /proc/net/route /dev/ip /dev/null;
+do
+ test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break
+done
+case $zebra_rtread in
+ "/proc/net/route") RTREAD_METHOD="rtread_proc.o"
+ zebra_rtread="proc";;
+ "/dev/ip") RTREAD_METHOD="rtread_getmsg.o"
+ zebra_rtread="getmsg";;
+ *) RTREAD_METHOD="rtread_sysctl.o"
+ zebra_rtread="sysctl";;
+esac
+fi])
+AC_SUBST(RTREAD_METHOD)
+
+dnl -----------------------------
+dnl check interface lookup method
+dnl -----------------------------
+AC_MSG_CHECKING(interface looking up method)
+if test "$netlink" = yes; then
+ AC_MSG_RESULT(netlink)
+ IF_METHOD=if_netlink.o
+else
+ if test "$opsys" = "sol2-6";then
+ AC_MSG_RESULT(solaris)
+ IF_METHOD=if_ioctl.o
+ elif test "$opsys" = "openbsd";then
+ AC_MSG_RESULT(openbsd)
+ IF_METHOD=if_ioctl.o
+ elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
+ AC_MSG_RESULT(sysctl)
+ IF_METHOD=if_sysctl.o
+ AC_DEFINE(HAVE_NET_RT_IFLIST)
+ else
+ AC_MSG_RESULT(ioctl)
+ IF_METHOD=if_ioctl.o
+ fi
+fi
+AC_SUBST(IF_METHOD)
+
+dnl -----------------------
+dnl check proc file system.
+dnl -----------------------
+if test -r /proc/net/dev; then
+ AC_DEFINE(HAVE_PROC_NET_DEV)
+ IF_PROC=if_proc.o
+fi
+
+if test -r /proc/net/if_inet6; then
+ AC_DEFINE(HAVE_PROC_NET_IF_INET6)
+ IF_PROC=if_proc.o
+fi
+AC_SUBST(IF_PROC)
+
+dnl -----------------------------
+dnl check ipforward detect method
+dnl -----------------------------
+AC_CACHE_CHECK(ipforward method check, zebra_ipforward_path,
+[for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null;
+do
+ test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break
+done
+case $zebra_ipforward_path in
+ "/proc/net/snmp") IPFORWARD=ipforward_proc.o
+ zebra_ipforward_path="proc";;
+ "/dev/ip")
+ case "$host" in
+ *-nec-sysv4*) IPFORWARD=ipforward_ews.o
+ zebra_ipforward_path="ews";;
+ *) IPFORWARD=ipforward_solaris.o
+ zebra_ipforward_path="solaris";;
+ esac;;
+ *) IPFORWARD=ipforward_sysctl.o
+ zebra_ipforward_path="sysctl";;
+esac])
+AC_SUBST(IPFORWARD)
+
+AC_CHECK_FUNCS(getaddrinfo, [have_getaddrinfo=yes], [have_getaddrinfo=no])
+
+dnl ----------
+dnl IPv6 check
+dnl ----------
+AC_MSG_CHECKING(whether does this OS have IPv6 stack)
+if test "${enable_ipv6}" = "no"; then
+ AC_MSG_RESULT(disabled)
+else
+dnl ----------
+dnl INRIA IPv6
+dnl ----------
+if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ AC_DEFINE(HAVE_IPV6)
+ AC_DEFINE(INRIA_IPV6)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ LIB_IPV6=""
+ AC_MSG_RESULT(INRIA IPv6)
+fi
+dnl ---------
+dnl KAME IPv6
+dnl ---------
+if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ AC_DEFINE(HAVE_IPV6)
+ AC_DEFINE(KAME)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then
+ LIB_IPV6="-L/usr/local/v6/lib -linet6"
+ fi
+ AC_MSG_RESULT(KAME)
+fi
+dnl ---------
+dnl NRL check
+dnl ---------
+if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then
+ zebra_cv_ipv6=yes
+ AC_DEFINE(HAVE_IPV6)
+ AC_DEFINE(NRL)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test x"$opsys" = x"bsdi";then
+ AC_DEFINE(BSDI_NRL)
+ AC_MSG_RESULT(BSDI_NRL)
+ else
+ AC_MSG_RESULT(NRL)
+ fi
+fi
+
+dnl ----------
+dnl Linux IPv6
+dnl ----------
+if test "${enable_ipv6}" = "yes"; then
+ AC_EGREP_CPP(yes, [
+ #include <linux/version.h>
+ /* 2.1.128 or later */
+ #if LINUX_VERSION_CODE >= 0x020180
+ yes
+ #endif],
+ [zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;AC_MSG_RESULT(Linux IPv6)])
+else
+ if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route"
+ then
+ zebra_cv_ipv6=yes
+ zebra_cv_linux_ipv6=yes
+ AC_MSG_RESULT(Linux IPv6)
+ fi
+fi
+
+if test "$zebra_cv_linux_ipv6" = "yes";then
+ AC_DEFINE(HAVE_IPV6)
+ AC_MSG_CHECKING(for GNU libc 2.1)
+ AC_EGREP_CPP(yes, [
+#include <features.h>
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+ yes
+#endif], [glibc=yes; AC_MSG_RESULT(yes)], AC_MSG_RESULT(no))
+ AC_DEFINE(LINUX_IPV6)
+ RIPNGD="ripngd"
+ OSPF6D="ospf6d"
+ if test "$glibc" != "yes"; then
+ INCLUDES="-I/usr/inet6/include"
+ if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then
+ LIB_IPV6="-L/usr/inet6/lib -linet6"
+ fi
+ fi
+fi
+
+dnl -----------------------
+dnl Set IPv6 related values
+dnl -----------------------
+LIBS="$LIB_IPV6 $LIBS"
+AC_SUBST(LIB_IPV6)
+
+if test x"$RIPNGD" = x""; then
+ AC_MSG_RESULT(IPv4 only)
+fi
+fi
+
+dnl --------------------
+dnl Daemon disable check
+dnl --------------------
+if test "${enable_zebra}" = "no";then
+ ZEBRA=""
+else
+ ZEBRA="zebra"
+fi
+
+if test "${enable_bgpd}" = "no";then
+ BGPD=""
+else
+ BGPD="bgpd"
+fi
+
+if test "${enable_ripd}" = "no";then
+ RIPD=""
+else
+ RIPD="ripd"
+fi
+
+if test "${enable_ospfd}" = "no";then
+ OSPFD=""
+else
+ OSPFD="ospfd"
+fi
+
+case "${enable_ripngd}" in
+ "yes") RIPNGD="ripngd";;
+ "no" ) RIPNGD="";;
+ * ) ;;
+esac
+
+case "${enable_ospf6d}" in
+ "yes") OSPF6D="ospf6d";;
+ "no" ) OSPF6D="";;
+ * ) ;;
+esac
+
+case "${enable_isisd}" in
+ "yes") ISISD="isisd";;
+ "no" ) ISISD="";;
+ * ) ;;
+esac
+
+if test "${enable_bgp_announce}" = "no";then
+ AC_DEFINE(DISABLE_BGP_ANNOUNCE)
+fi
+
+AC_SUBST(ZEBRA)
+AC_SUBST(BGPD)
+AC_SUBST(RIPD)
+AC_SUBST(RIPNGD)
+AC_SUBST(OSPFD)
+AC_SUBST(OSPF6D)
+AC_SUBST(ISISD)
+AC_SUBST(VTYSH)
+AC_SUBST(INCLUDES)
+AC_SUBST(CURSES)
+AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP)])
+AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON)])
+AC_CHECK_LIB(crypt, crypt)
+AC_CHECK_LIB(resolv, res_init)
+AC_CHECK_LIB(m, main)
+
+dnl ---------------------------------------------------
+dnl BSD/OS 4.1 define inet_XtoY function as __inet_XtoY
+dnl ---------------------------------------------------
+AC_CHECK_FUNC(__inet_ntop, AC_DEFINE(HAVE_INET_NTOP))
+AC_CHECK_FUNC(__inet_pton, AC_DEFINE(HAVE_INET_PTON))
+AC_CHECK_FUNC(__inet_aton, AC_DEFINE(HAVE_INET_ATON))
+
+dnl ---------------------------
+dnl check system has GNU regexp
+dnl ---------------------------
+dnl AC_MSG_CHECKING(whether system has GNU regex)
+AC_CHECK_LIB(c, regexec,
+[AC_DEFINE(HAVE_GNU_REGEX)
+ LIB_REGEX=""],
+[LIB_REGEX="regex.o"])
+AC_SUBST(LIB_REGEX)
+
+dnl AC_MSG_CHECKING(whether system has GNU regex)
+dnl if grep RE_NO_GNU_OPS /usr/include/regex.h >/dev/null 2>&1; then
+dnl AC_MSG_RESULT(yes)
+dnl AC_DEFINE(HAVE_GNU_REGEX)
+dnl LIB_REGEX=""
+dnl else
+dnl AC_MSG_RESULT(no)
+dnl LIB_REGEX="regex.o"
+dnl fi
+dnl AC_SUBST(LIB_REGEX)
+
+dnl ------------------
+dnl check SNMP library
+dnl ------------------
+if test "${enable_snmp}" = "yes";then
+dnl AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes)
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ unset ac_cv_lib_snmp_asn_parse_int
+ AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, )
+ if test "${HAVE_SNMP}" = ""; then
+ unset ac_cv_lib_snmp_asn_parse_int
+ AC_CHECK_LIB(crypto, main, [NEED_CRYPTO=yes ], )
+ if test "${NEED_CRYPTO}" = ""; then
+ AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes ],)
+ else
+ AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto")
+ fi
+ fi
+ LIBS="${old_libs}"
+
+ if test "${HAVE_SNMP}" = ""; then
+ old_libs="${LIBS}"
+ LIBS="-L/usr/local/lib"
+ AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes)
+ LIBS="${old_libs}"
+ fi
+ if test "${HAVE_SNMP}" = "yes"; then
+ for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null
+ do
+ test -f "${ac_snmp}" && break
+ done
+ case ${ac_snmp} in
+ /usr/include/ucd-snmp/*)
+ AC_DEFINE(HAVE_SNMP)
+ CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp"
+ LIBS="${LIBS} -lsnmp"
+ ;;
+ /usr/local/include/ucd-snmp/*)
+ AC_DEFINE(HAVE_SNMP)
+ CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp"
+ LIBS="${LIBS} -L/usr/local/lib -lsnmp"
+ ;;
+ esac
+ if test "${NEED_CRYPTO}" = "yes"; then
+ LIBS="${LIBS} -lcrypto"
+ fi
+ fi
+fi
+
+dnl ----------------------------
+dnl check sa_len of sockaddr
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct sockaddr has a sa_len field)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+],[static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SA_LEN)],
+ AC_MSG_RESULT(no))
+
+dnl ----------------------------
+dnl check sin_len of sockaddr_in
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct sockaddr_in has a sin_len field)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>
+],[static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SIN_LEN)],
+ AC_MSG_RESULT(no))
+
+dnl ----------------------------
+dnl check sun_len of sockaddr_un
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct sockaddr_un has a sun_len field)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/un.h>
+],[static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SUN_LEN)],
+ AC_MSG_RESULT(no))
+
+dnl -----------------------------------
+dnl check sin6_scope_id of sockaddr_in6
+dnl -----------------------------------
+if test "$zebra_cv_ipv6" = yes; then
+ AC_MSG_CHECKING(whether struct sockaddr_in6 has a sin6_scope_id field)
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <netinet/in.h>
+],[static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SIN6_SCOPE_ID)],
+ AC_MSG_RESULT(no))
+fi
+
+dnl ----------------------------
+dnl check socklen_t exist or not
+dnl ----------------------------
+AC_MSG_CHECKING(whther socklen_t is defined)
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+],[socklen_t ac_x;],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SOCKLEN_T)],
+ AC_MSG_RESULT(no))
+
+dnl ------------------------
+dnl check struct sockaddr_dl
+dnl ------------------------
+AC_MSG_CHECKING(whether struct sockaddr_dl exist)
+AC_EGREP_HEADER(sockaddr_dl,
+net/if_dl.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SOCKADDR_DL)],
+ AC_MSG_RESULT(no))
+
+dnl --------------------------
+dnl check structure ifaliasreq
+dnl --------------------------
+AC_MSG_CHECKING(whether struct ifaliasreq exist)
+AC_EGREP_HEADER(ifaliasreq,
+net/if.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IFALIASREQ)],
+ AC_MSG_RESULT(no))
+
+dnl ----------------------------
+dnl check structure in6_aliasreq
+dnl ----------------------------
+AC_MSG_CHECKING(whether struct if6_aliasreq exist)
+AC_EGREP_HEADER(in6_aliasreq,
+netinet6/in6_var.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IN6_ALIASREQ)],
+ AC_MSG_RESULT(no))
+
+dnl ---------------------------
+dnl check structure rt_addrinfo
+dnl ---------------------------
+AC_MSG_CHECKING(whether struct rt_addrinfo exist)
+AC_EGREP_HEADER(rt_addrinfo,
+net/route.h,
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_RT_ADDRINFO)],
+ AC_MSG_RESULT(no))
+
+dnl --------------------------
+dnl check structure in_pktinfo
+dnl --------------------------
+AC_MSG_CHECKING(whether struct in_pktinfo exist)
+AC_TRY_COMPILE([#include <netinet/in.h>
+],[struct in_pktinfo ac_x;],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INPKTINFO)],
+ AC_MSG_RESULT(no))
+
+dnl --------------------------------------
+dnl checking for getrusage struct and call
+dnl --------------------------------------
+AC_MSG_CHECKING(whether getrusage is available)
+AC_TRY_COMPILE([#include <sys/resource.h>
+],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_RUSAGE)],
+ AC_MSG_RESULT(no))
+
+dnl -------------
+dnl check version
+dnl -------------
+file="${srcdir}/lib/version.h"
+VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file`
+AC_SUBST(VERSION)
+
+dnl ------------------------------
+dnl set paths for process id files
+dnl ------------------------------
+AC_CACHE_CHECK(pid file directory,ac_piddir,
+[for ZEBRA_PID_DIR in /var/run dnl
+ /var/adm dnl
+ /etc dnl
+ /dev/null;
+do
+ test -d $ZEBRA_PID_DIR && break
+done
+ac_piddir=$ZEBRA_PID_DIR
+if test $ZEBRA_PID_DIR = "/dev/null"; then
+ echo "PID DIRECTORY NOT FOUND!"
+fi])
+AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$ac_piddir/zebra.pid")
+AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$ac_piddir/ripd.pid")
+AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$ac_piddir/ripngd.pid")
+AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$ac_piddir/bgpd.pid")
+AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$ac_piddir/ospfd.pid")
+AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$ac_piddir/ospf6d.pid")
+AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$ac_piddir/isisd.pid")
+
+dnl ---------------------------
+dnl Check htonl works correctly
+dnl ---------------------------
+AC_MSG_CHECKING(for working htonl)
+AC_CACHE_VAL(ac_cv_htonl_works, [
+AC_TRY_LINK([#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif],
+[htonl (0);],
+ac_cv_htonl_works=yes,
+ac_cv_htonl_works=no)])
+AC_MSG_RESULT($ac_cv_htonl_works)
+
+AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile)
+
+echo "
+zebra configuration
+-------------------
+zebra version : ${VERSION}
+host operationg system : ${host_os}
+source code location : ${srcdir}
+compiler : ${CC}
+compiler flags : ${CFLAGS}
+directory for pid files : ${ac_piddir}
+"
diff --git a/isisd/modified/log.c b/isisd/modified/log.c
new file mode 100644
index 00000000..385fb38f
--- /dev/null
+++ b/isisd/modified/log.c
@@ -0,0 +1,484 @@
+/* Logging of zebra
+ * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "command.h"
+
+struct zlog *zlog_default = NULL;
+
+const char *zlog_proto_names[] =
+{
+ "NONE",
+ "DEFAULT",
+ "ZEBRA",
+ "RIP",
+ "BGP",
+ "OSPF",
+ "RIPNG",
+ "OSPF6",
+ "ISIS",
+ "MASC",
+ NULL,
+};
+
+const char *zlog_priority[] =
+{
+ "emergencies",
+ "alerts",
+ "critical",
+ "errors",
+ "warnings",
+ "notifications",
+ "informational",
+ "debugging",
+ NULL,
+};
+
+
+
+/* For time string format. */
+#define TIME_BUF 27
+
+/* Utility routine for current time printing. */
+static void
+time_print (FILE *fp)
+{
+ int ret;
+ char buf [TIME_BUF];
+ time_t clock;
+ struct tm *tm;
+
+ time (&clock);
+ tm = localtime (&clock);
+
+ ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
+ if (ret == 0) {
+ zlog_warn ("strftime error");
+ }
+
+ fprintf (fp, "%s ", buf);
+}
+
+/* va_list version of zlog. */
+void
+vzlog (struct zlog *zl, int priority, const char *format, va_list *args)
+{
+ /* If zlog is not specified, use default one. */
+ if (zl == NULL)
+ zl = zlog_default;
+
+ /* When zlog_default is also NULL, use stderr for logging. */
+ if (zl == NULL)
+ {
+ time_print (stderr);
+ fprintf (stderr, "%s: ", "unknown");
+ vfprintf (stderr, format, args[ZLOG_NOLOG_INDEX]);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+
+ /* In this case we return at here. */
+ return;
+ }
+
+ /* only log this information if it has not been masked out */
+ if ( priority > zl->maskpri )
+ return ;
+
+ /* Syslog output */
+ if (zl->flags & ZLOG_SYSLOG)
+ vsyslog (priority, format, args[ZLOG_SYSLOG_INDEX]);
+
+ /* File output. */
+ if (zl->flags & ZLOG_FILE)
+ {
+ time_print (zl->fp);
+ if (zl->record_priority) fprintf (zl->fp, "%s: ", zlog_priority[priority]);
+ fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
+ vfprintf (zl->fp, format, args[ZLOG_FILE_INDEX]);
+ fprintf (zl->fp, "\n");
+ fflush (zl->fp);
+ }
+
+ /* stdout output. */
+ if (zl->flags & ZLOG_STDOUT)
+ {
+ time_print (stdout);
+ if (zl->record_priority) fprintf (stdout, "%s: ", zlog_priority[priority]);
+ fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
+ vfprintf (stdout, format, args[ZLOG_STDOUT_INDEX]);
+ fprintf (stdout, "\n");
+ fflush (stdout);
+ }
+
+ /* stderr output. */
+ if (zl->flags & ZLOG_STDERR)
+ {
+ time_print (stderr);
+ if (zl->record_priority) fprintf (stderr, "%s: ", zlog_priority[priority]);
+ fprintf (stderr, "%s: ", zlog_proto_names[zl->protocol]);
+ vfprintf (stderr, format, args[ZLOG_STDERR_INDEX]);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+ }
+
+ /* Terminal monitor. */
+ vty_log (zlog_proto_names[zl->protocol], format, args[ZLOG_NOLOG_INDEX]);
+}
+
+void
+zlog (struct zlog *zl, int priority, const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (zl, priority, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+zlog_err (const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (NULL, LOG_ERR, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+zlog_warn (const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (NULL, LOG_WARNING, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+zlog_info (const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (NULL, LOG_INFO, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+zlog_notice (const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (NULL, LOG_NOTICE, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+zlog_debug (const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (NULL, LOG_DEBUG, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+plog_err (struct zlog *zl, const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (zl, LOG_ERR, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+plog_warn (struct zlog *zl, const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (zl, LOG_WARNING, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+plog_info (struct zlog *zl, const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (zl, LOG_INFO, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+plog_notice (struct zlog *zl, const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (zl, LOG_NOTICE, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+void
+plog_debug (struct zlog *zl, const char *format, ...)
+{
+ va_list args[ZLOG_MAX_INDEX];
+ int index;
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_start(args[index], format);
+
+ vzlog (zl, LOG_DEBUG, format, args);
+
+ for (index = 0; index < ZLOG_MAX_INDEX; index++)
+ va_end (args[index]);
+}
+
+
+/* Open log stream */
+struct zlog *
+openzlog (const char *progname, int flags, zlog_proto_t protocol,
+ int syslog_flags, int syslog_facility)
+{
+ struct zlog *zl;
+
+ zl = XMALLOC(MTYPE_ZLOG, sizeof (struct zlog));
+ memset (zl, 0, sizeof (struct zlog));
+
+ zl->ident = progname;
+ zl->flags = flags;
+ zl->protocol = protocol;
+ zl->facility = syslog_facility;
+ zl->maskpri = LOG_DEBUG;
+ zl->record_priority = 0;
+
+ openlog (progname, syslog_flags, zl->facility);
+
+ return zl;
+}
+
+void
+closezlog (struct zlog *zl)
+{
+ closelog();
+ fclose (zl->fp);
+
+ XFREE (MTYPE_ZLOG, zl);
+}
+
+/* Called from command.c. */
+void
+zlog_set_flag (struct zlog *zl, int flags)
+{
+ if (zl == NULL)
+ zl = zlog_default;
+
+ zl->flags |= flags;
+}
+
+void
+zlog_reset_flag (struct zlog *zl, int flags)
+{
+ if (zl == NULL)
+ zl = zlog_default;
+
+ zl->flags &= ~flags;
+}
+
+int
+zlog_set_file (struct zlog *zl, int flags, char *filename)
+{
+ FILE *fp;
+
+ /* There is opend file. */
+ zlog_reset_file (zl);
+
+ /* Set default zl. */
+ if (zl == NULL)
+ zl = zlog_default;
+
+ /* Open file. */
+ fp = fopen (filename, "a");
+ if (fp == NULL)
+ return 0;
+
+ /* Set flags. */
+ zl->filename = strdup (filename);
+ zl->flags |= ZLOG_FILE;
+ zl->fp = fp;
+
+ return 1;
+}
+
+/* Reset opend file. */
+int
+zlog_reset_file (struct zlog *zl)
+{
+ if (zl == NULL)
+ zl = zlog_default;
+
+ zl->flags &= ~ZLOG_FILE;
+
+ if (zl->fp)
+ fclose (zl->fp);
+ zl->fp = NULL;
+
+ if (zl->filename)
+ free (zl->filename);
+ zl->filename = NULL;
+
+ return 1;
+}
+
+/* Reopen log file. */
+int
+zlog_rotate (struct zlog *zl)
+{
+ FILE *fp;
+
+ if (zl == NULL)
+ zl = zlog_default;
+
+ if (zl->fp)
+ fclose (zl->fp);
+ zl->fp = NULL;
+
+ if (zl->filename)
+ {
+ fp = fopen (zl->filename, "a");
+ if (fp == NULL)
+ return -1;
+ zl->fp = fp;
+ }
+
+ return 1;
+}
+
+static char *zlog_cwd = NULL;
+
+void
+zlog_save_cwd ()
+{
+ char *cwd;
+
+ cwd = getcwd (NULL, MAXPATHLEN);
+
+ zlog_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
+ strcpy (zlog_cwd, cwd);
+}
+
+char *
+zlog_get_cwd ()
+{
+ return zlog_cwd;
+}
+
+void
+zlog_free_cwd ()
+{
+ if (zlog_cwd)
+ XFREE (MTYPE_TMP, zlog_cwd);
+}
+
+/* Message lookup function. */
+char *
+lookup (struct message *mes, int key)
+{
+ struct message *pnt;
+
+ for (pnt = mes; pnt->key != 0; pnt++)
+ if (pnt->key == key)
+ return pnt->str;
+
+ return "";
+}
+
+/* Very old hacky version of message lookup function. Still partly
+ used in bgpd and ospfd. */
+char *
+mes_lookup (struct message *meslist, int max, int index)
+{
+ if (index < 0 || index >= max)
+ {
+ zlog_err ("message index out of bound: %d", max);
+ return NULL;
+ }
+ return meslist[index].str;
+}
diff --git a/isisd/modified/log.h b/isisd/modified/log.h
new file mode 100644
index 00000000..8948ea00
--- /dev/null
+++ b/isisd/modified/log.h
@@ -0,0 +1,129 @@
+/* Zebra logging funcions.
+ * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_LOG_H
+#define _ZEBRA_LOG_H
+
+#include <syslog.h>
+
+#define ZLOG_NOLOG 0x00
+#define ZLOG_FILE 0x01
+#define ZLOG_SYSLOG 0x02
+#define ZLOG_STDOUT 0x04
+#define ZLOG_STDERR 0x08
+
+#define ZLOG_NOLOG_INDEX 0
+#define ZLOG_FILE_INDEX 1
+#define ZLOG_SYSLOG_INDEX 2
+#define ZLOG_STDOUT_INDEX 3
+#define ZLOG_STDERR_INDEX 4
+#define ZLOG_MAX_INDEX 5
+
+typedef enum
+{
+ ZLOG_NONE,
+ ZLOG_DEFAULT,
+ ZLOG_ZEBRA,
+ ZLOG_RIP,
+ ZLOG_BGP,
+ ZLOG_OSPF,
+ ZLOG_RIPNG,
+ ZLOG_OSPF6,
+ ZLOG_ISIS,
+ ZLOG_MASC
+} zlog_proto_t;
+
+struct zlog
+{
+ const char *ident;
+ zlog_proto_t protocol;
+ int flags;
+ FILE *fp;
+ char *filename;
+ int syslog;
+ int stat;
+ int connected;
+ int maskpri; /* as per syslog setlogmask */
+ int priority; /* as per syslog priority */
+ int facility; /* as per syslog facility */
+ int record_priority;
+};
+
+/* Message structure. */
+struct message
+{
+ int key;
+ char *str;
+};
+
+/* Default logging strucutre. */
+extern struct zlog *zlog_default;
+
+/* Open zlog function */
+struct zlog *openzlog (const char *, int, zlog_proto_t, int, int);
+
+/* Close zlog function. */
+void closezlog (struct zlog *zl);
+
+/* GCC have printf type attribute check. */
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* __GNUC__ */
+
+/* Generic function for zlog. */
+void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+
+/* Handy zlog functions. */
+void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/* For bgpd's peer oriented log. */
+void plog_err (struct zlog *, const char *format, ...);
+void plog_warn (struct zlog *, const char *format, ...);
+void plog_info (struct zlog *, const char *format, ...);
+void plog_notice (struct zlog *, const char *format, ...);
+void plog_debug (struct zlog *, const char *format, ...);
+
+/* Set zlog flags. */
+void zlog_set_flag (struct zlog *zl, int flags);
+void zlog_reset_flag (struct zlog *zl, int flags);
+
+/* Set zlog filename. */
+int zlog_set_file (struct zlog *zl, int flags, char *filename);
+int zlog_reset_file (struct zlog *zl);
+
+/* Rotate log. */
+int zlog_rotate ();
+
+/* For hackey massage lookup and check */
+#define LOOKUP(x, y) mes_lookup(x, x ## _max, y)
+
+char *lookup (struct message *, int);
+char *mes_lookup (struct message *meslist, int max, int index);
+
+extern const char *zlog_priority[];
+
+#endif /* _ZEBRA_LOG_H */
diff --git a/isisd/modified/memory.c b/isisd/modified/memory.c
new file mode 100644
index 00000000..49ff3213
--- /dev/null
+++ b/isisd/modified/memory.c
@@ -0,0 +1,527 @@
+/*
+ * Memory management routine
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+void alloc_inc (int);
+void alloc_dec (int);
+
+struct message mstr [] =
+{
+ { MTYPE_THREAD, "thread" },
+ { MTYPE_THREAD_MASTER, "thread_master" },
+ { MTYPE_VECTOR, "vector" },
+ { MTYPE_VECTOR_INDEX, "vector_index" },
+ { MTYPE_IF, "interface" },
+ { 0, NULL },
+};
+
+/* Fatal memory allocation error occured. */
+static void
+zerror (const char *fname, int type, size_t size)
+{
+ fprintf (stderr, "%s : can't allocate memory for `%s' size %d\n",
+ fname, lookup (mstr, type), (int) size);
+ exit (1);
+}
+
+/* Memory allocation. */
+void *
+zmalloc (int type, size_t size)
+{
+ void *memory;
+
+ memory = malloc (size);
+
+ if (memory == NULL)
+ zerror ("malloc", type, size);
+
+ alloc_inc (type);
+
+ return memory;
+}
+
+/* Memory allocation with num * size with cleared. */
+void *
+zcalloc (int type, size_t size)
+{
+ void *memory;
+
+ memory = calloc (1, size);
+
+ if (memory == NULL)
+ zerror ("calloc", type, size);
+
+ alloc_inc (type);
+
+ return memory;
+}
+
+/* Memory reallocation. */
+void *
+zrealloc (int type, void *ptr, size_t size)
+{
+ void *memory;
+
+ memory = realloc (ptr, size);
+ if (memory == NULL)
+ zerror ("realloc", type, size);
+ return memory;
+}
+
+/* Memory free. */
+void
+zfree (int type, void *ptr)
+{
+ alloc_dec (type);
+ free (ptr);
+}
+
+/* String duplication. */
+char *
+zstrdup (int type, char *str)
+{
+ void *dup;
+
+ dup = strdup (str);
+ if (dup == NULL)
+ zerror ("strdup", type, strlen (str));
+ alloc_inc (type);
+ return dup;
+}
+
+#ifdef MEMORY_LOG
+struct
+{
+ char *name;
+ unsigned long alloc;
+ unsigned long t_malloc;
+ unsigned long c_malloc;
+ unsigned long t_calloc;
+ unsigned long c_calloc;
+ unsigned long t_realloc;
+ unsigned long t_free;
+ unsigned long c_strdup;
+} mstat [MTYPE_MAX];
+
+void
+mtype_log (char *func, void *memory, const char *file, int line, int type)
+{
+ zlog_info ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line);
+}
+
+void *
+mtype_zmalloc (const char *file, int line, int type, size_t size)
+{
+ void *memory;
+
+ mstat[type].c_malloc++;
+ mstat[type].t_malloc++;
+
+ memory = zmalloc (type, size);
+ mtype_log ("zmalloc", memory, file, line, type);
+
+ return memory;
+}
+
+void *
+mtype_zcalloc (const char *file, int line, int type, size_t size)
+{
+ void *memory;
+
+ mstat[type].c_calloc++;
+ mstat[type].t_calloc++;
+
+ memory = zcalloc (type, size);
+ mtype_log ("xcalloc", memory, file, line, type);
+
+ return memory;
+}
+
+void *
+mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
+{
+ void *memory;
+
+ /* Realloc need before allocated pointer. */
+ mstat[type].t_realloc++;
+
+ memory = zrealloc (type, ptr, size);
+
+ mtype_log ("xrealloc", memory, file, line, type);
+
+ return memory;
+}
+
+/* Important function. */
+void
+mtype_zfree (const char *file, int line, int type, void *ptr)
+{
+ mstat[type].t_free++;
+
+ mtype_log ("xfree", ptr, file, line, type);
+
+ zfree (type, ptr);
+}
+
+char *
+mtype_zstrdup (const char *file, int line, int type, char *str)
+{
+ char *memory;
+
+ mstat[type].c_strdup++;
+
+ memory = zstrdup (type, str);
+
+ mtype_log ("xstrdup", memory, file, line, type);
+
+ return memory;
+}
+#else
+struct
+{
+ char *name;
+ unsigned long alloc;
+} mstat [MTYPE_MAX];
+#endif /* MTPYE_LOG */
+
+/* Increment allocation counter. */
+void
+alloc_inc (int type)
+{
+ mstat[type].alloc++;
+}
+
+/* Decrement allocation counter. */
+void
+alloc_dec (int type)
+{
+ mstat[type].alloc--;
+}
+
+/* Looking up memory status from vty interface. */
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+
+/* For pretty printng of memory allocate information. */
+struct memory_list
+{
+ int index;
+ char *format;
+};
+
+struct memory_list memory_list_lib[] =
+{
+ { MTYPE_TMP, "Temporary memory" },
+ { MTYPE_ROUTE_TABLE, "Route table " },
+ { MTYPE_ROUTE_NODE, "Route node " },
+ { MTYPE_RIB, "RIB " },
+ { MTYPE_NEXTHOP, "Nexthop " },
+ { MTYPE_LINK_LIST, "Link List " },
+ { MTYPE_LINK_NODE, "Link Node " },
+ { MTYPE_HASH, "Hash " },
+ { MTYPE_HASH_BACKET, "Hash Bucket " },
+ { MTYPE_ACCESS_LIST, "Access List " },
+ { MTYPE_ACCESS_LIST_STR, "Access List Str " },
+ { MTYPE_ACCESS_FILTER, "Access Filter " },
+ { MTYPE_PREFIX_LIST, "Prefix List " },
+ { MTYPE_PREFIX_LIST_STR, "Prefix List Str " },
+ { MTYPE_PREFIX_LIST_ENTRY, "Prefix List Entry "},
+ { MTYPE_ROUTE_MAP, "Route map " },
+ { MTYPE_ROUTE_MAP_NAME, "Route map name " },
+ { MTYPE_ROUTE_MAP_INDEX, "Route map index " },
+ { MTYPE_ROUTE_MAP_RULE, "Route map rule " },
+ { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
+ { MTYPE_DESC, "Command desc " },
+ { MTYPE_BUFFER, "Buffer " },
+ { MTYPE_BUFFER_DATA, "Buffer data " },
+ { MTYPE_STREAM, "Stream " },
+ { MTYPE_KEYCHAIN, "Key chain " },
+ { MTYPE_KEY, "Key " },
+ { MTYPE_VTY, "VTY " },
+ { -1, NULL }
+};
+
+struct memory_list memory_list_bgp[] =
+{
+ { MTYPE_BGP_PEER, "BGP peer" },
+ { MTYPE_ATTR, "BGP attribute" },
+ { MTYPE_AS_PATH, "BGP aspath" },
+ { MTYPE_AS_SEG, "BGP aspath seg" },
+ { MTYPE_AS_STR, "BGP aspath str" },
+ { 0, NULL },
+ { MTYPE_BGP_TABLE, "BGP table" },
+ { MTYPE_BGP_NODE, "BGP node" },
+ { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" },
+ { MTYPE_BGP_ADVERTISE, "BGP adv" },
+ { MTYPE_BGP_ADJ_IN, "BGP adj in" },
+ { MTYPE_BGP_ADJ_OUT, "BGP adj out" },
+ { 0, NULL },
+ { MTYPE_AS_LIST, "BGP AS list" },
+ { MTYPE_AS_FILTER, "BGP AS filter" },
+ { MTYPE_AS_FILTER_STR, "BGP AS filter str" },
+ { 0, NULL },
+ { MTYPE_COMMUNITY, "community" },
+ { MTYPE_COMMUNITY_VAL, "community val" },
+ { MTYPE_COMMUNITY_STR, "community str" },
+ { 0, NULL },
+ { MTYPE_ECOMMUNITY, "extcommunity" },
+ { MTYPE_ECOMMUNITY_VAL, "extcommunity val" },
+ { MTYPE_ECOMMUNITY_STR, "extcommunity str" },
+ { 0, NULL },
+ { MTYPE_COMMUNITY_LIST, "community-list" },
+ { MTYPE_COMMUNITY_LIST_NAME, "community-list name" },
+ { MTYPE_COMMUNITY_LIST_ENTRY, "community-list entry" },
+ { MTYPE_COMMUNITY_LIST_CONFIG, "community-list config" },
+ { 0, NULL },
+ { MTYPE_CLUSTER, "Cluster list" },
+ { MTYPE_CLUSTER_VAL, "Cluster list val" },
+ { 0, NULL },
+ { MTYPE_TRANSIT, "BGP transit attr" },
+ { MTYPE_TRANSIT_VAL, "BGP transit val" },
+ { 0, NULL },
+ { MTYPE_BGP_DISTANCE, "BGP distance" },
+ { MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" },
+ { MTYPE_BGP_CONFED_LIST, "BGP confed list" },
+ { MTYPE_PEER_UPDATE_SOURCE, "peer update if" },
+ { MTYPE_BGP_DAMP_INFO, "Dampening info" },
+ { MTYPE_BGP_REGEXP, "BGP regexp" },
+ { -1, NULL }
+};
+
+struct memory_list memory_list_rip[] =
+{
+ { MTYPE_RIP, "RIP structure " },
+ { MTYPE_RIP_INFO, "RIP route info " },
+ { MTYPE_RIP_INTERFACE, "RIP interface " },
+ { MTYPE_RIP_PEER, "RIP peer " },
+ { MTYPE_RIP_OFFSET_LIST, "RIP offset list " },
+ { MTYPE_RIP_DISTANCE, "RIP distance " },
+ { -1, NULL }
+};
+
+struct memory_list memory_list_ospf[] =
+{
+ { MTYPE_OSPF_TOP, "OSPF top " },
+ { MTYPE_OSPF_AREA, "OSPF area " },
+ { MTYPE_OSPF_AREA_RANGE, "OSPF area range " },
+ { MTYPE_OSPF_NETWORK, "OSPF network " },
+#ifdef NBMA_ENABLE
+ { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " },
+#endif /* NBMA_ENABLE */
+ { MTYPE_OSPF_IF, "OSPF interface " },
+ { MTYPE_OSPF_NEIGHBOR, "OSPF neighbor " },
+ { MTYPE_OSPF_ROUTE, "OSPF route " },
+ { MTYPE_OSPF_TMP, "OSPF tmp mem " },
+ { MTYPE_OSPF_LSA, "OSPF LSA " },
+ { MTYPE_OSPF_LSA_DATA, "OSPF LSA data " },
+ { MTYPE_OSPF_LSDB, "OSPF LSDB " },
+ { MTYPE_OSPF_PACKET, "OSPF packet " },
+ { MTYPE_OSPF_FIFO, "OSPF FIFO queue " },
+ { MTYPE_OSPF_VERTEX, "OSPF vertex " },
+ { MTYPE_OSPF_NEXTHOP, "OSPF nexthop " },
+ { MTYPE_OSPF_PATH, "OSPF path " },
+ { MTYPE_OSPF_VL_DATA, "OSPF VL data " },
+ { MTYPE_OSPF_CRYPT_KEY, "OSPF crypt key " },
+ { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info " },
+ { MTYPE_OSPF_DISTANCE, "OSPF distance " },
+ { MTYPE_OSPF_IF_INFO, "OSPF if info " },
+ { MTYPE_OSPF_IF_PARAMS, "OSPF if params " },
+ { -1, NULL },
+};
+
+struct memory_list memory_list_ospf6[] =
+{
+ { MTYPE_OSPF6_TOP, "OSPF6 top " },
+ { MTYPE_OSPF6_AREA, "OSPF6 area " },
+ { MTYPE_OSPF6_IF, "OSPF6 interface " },
+ { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor " },
+ { MTYPE_OSPF6_ROUTE, "OSPF6 route " },
+ { MTYPE_OSPF6_PREFIX, "OSPF6 prefix " },
+ { MTYPE_OSPF6_MESSAGE, "OSPF6 message " },
+ { MTYPE_OSPF6_LSA, "OSPF6 LSA " },
+ { MTYPE_OSPF6_LSA_SUMMARY, "OSPF6 LSA summary " },
+ { MTYPE_OSPF6_LSDB, "OSPF6 LSA database" },
+ { MTYPE_OSPF6_VERTEX, "OSPF6 vertex " },
+ { MTYPE_OSPF6_SPFTREE, "OSPF6 SPF tree " },
+ { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop " },
+ { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info " },
+ { MTYPE_OSPF6_OTHER, "OSPF6 other " },
+ { -1, NULL },
+};
+
+
+struct memory_list memory_list_isis[] =
+{
+ { MTYPE_ISIS, "ISIS : %ld\r\n" },
+ { MTYPE_ISIS_TMP, "ISIS TMP : %ld\r\n" },
+ { MTYPE_ISIS_CIRCUIT, "ISIS circuit : %ld\r\n" },
+ { MTYPE_ISIS_LSP, "ISIS LSP : %ld\r\n" },
+ { MTYPE_ISIS_ADJACENCY, "ISIS adjacency : %ld\r\n" },
+ { MTYPE_ISIS_AREA, "ISIS area : %ld\r\n" },
+ { MTYPE_ISIS_AREA_ADDR, "ISIS area address: %ld\r\n" },
+ { MTYPE_ISIS_TLV, "ISIS TLV : %ld\r\n" },
+ { MTYPE_ISIS_DYNHN, "ISIS dyn hostname: %ld\r\n" },
+ { MTYPE_ISIS_SPFTREE, "ISIS SPFtree : %ld\r\n" },
+ { MTYPE_ISIS_VERTEX, "ISIS vertex : %ld\r\n" },
+ { MTYPE_ISIS_ROUTE_INFO, "ISIS route info : %ld\r\n" },
+ { MTYPE_ISIS_NEXTHOP, "ISIS nexthop : %ld\r\n" },
+ { MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6 : %ld\r\n" },
+ { -1, NULL },
+};
+
+struct memory_list memory_list_separator[] =
+{
+ { 0, NULL},
+ {-1, NULL}
+};
+
+void
+show_memory_vty (struct vty *vty, struct memory_list *list)
+{
+ struct memory_list *m;
+
+ for (m = list; m->index >= 0; m++)
+ if (m->index == 0)
+ vty_out (vty, "-----------------------------\r\n");
+ else
+ vty_out (vty, "%-22s: %5ld\r\n", m->format, mstat[m->index].alloc);
+}
+
+DEFUN (show_memory_all,
+ show_memory_all_cmd,
+ "show memory all",
+ "Show running system information\n"
+ "Memory statistics\n"
+ "All memory statistics\n")
+{
+ show_memory_vty (vty, memory_list_lib);
+ show_memory_vty (vty, memory_list_separator);
+ show_memory_vty (vty, memory_list_rip);
+ show_memory_vty (vty, memory_list_separator);
+ show_memory_vty (vty, memory_list_ospf);
+ show_memory_vty (vty, memory_list_separator);
+ show_memory_vty (vty, memory_list_ospf6);
+ show_memory_vty (vty, memory_list_separator);
+ show_memory_vty (vty, memory_list_bgp);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (show_memory_all,
+ show_memory_cmd,
+ "show memory",
+ "Show running system information\n"
+ "Memory statistics\n")
+
+DEFUN (show_memory_lib,
+ show_memory_lib_cmd,
+ "show memory lib",
+ SHOW_STR
+ "Memory statistics\n"
+ "Library memory\n")
+{
+ show_memory_vty (vty, memory_list_lib);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_rip,
+ show_memory_rip_cmd,
+ "show memory rip",
+ SHOW_STR
+ "Memory statistics\n"
+ "RIP memory\n")
+{
+ show_memory_vty (vty, memory_list_rip);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_bgp,
+ show_memory_bgp_cmd,
+ "show memory bgp",
+ SHOW_STR
+ "Memory statistics\n"
+ "BGP memory\n")
+{
+ show_memory_vty (vty, memory_list_bgp);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_ospf,
+ show_memory_ospf_cmd,
+ "show memory ospf",
+ SHOW_STR
+ "Memory statistics\n"
+ "OSPF memory\n")
+{
+ show_memory_vty (vty, memory_list_ospf);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_ospf6,
+ show_memory_ospf6_cmd,
+ "show memory ospf6",
+ SHOW_STR
+ "Memory statistics\n"
+ "OSPF6 memory\n")
+{
+ show_memory_vty (vty, memory_list_ospf6);
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_memory_isis,
+ show_memory_isis_cmd,
+ "show memory isis",
+ SHOW_STR
+ "Memory statistics\n"
+ "ISIS memory\n")
+{
+ show_memory_vty (vty, memory_list_isis);
+ return CMD_SUCCESS;
+}
+
+void
+memory_init ()
+{
+ install_element (VIEW_NODE, &show_memory_cmd);
+ install_element (VIEW_NODE, &show_memory_all_cmd);
+ install_element (VIEW_NODE, &show_memory_lib_cmd);
+ install_element (VIEW_NODE, &show_memory_rip_cmd);
+ install_element (VIEW_NODE, &show_memory_bgp_cmd);
+ install_element (VIEW_NODE, &show_memory_ospf_cmd);
+ install_element (VIEW_NODE, &show_memory_ospf6_cmd);
+ install_element (VIEW_NODE, &show_memory_isis_cmd);
+
+ install_element (ENABLE_NODE, &show_memory_cmd);
+ install_element (ENABLE_NODE, &show_memory_all_cmd);
+ install_element (ENABLE_NODE, &show_memory_lib_cmd);
+ install_element (ENABLE_NODE, &show_memory_rip_cmd);
+ install_element (ENABLE_NODE, &show_memory_bgp_cmd);
+ install_element (ENABLE_NODE, &show_memory_ospf_cmd);
+ install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
+ install_element (ENABLE_NODE, &show_memory_isis_cmd);
+}
diff --git a/isisd/modified/memory.h b/isisd/modified/memory.h
new file mode 100644
index 00000000..d80cdf5f
--- /dev/null
+++ b/isisd/modified/memory.h
@@ -0,0 +1,257 @@
+/* Memory management routine
+ Copyright (C) 1998 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _ZEBRA_MEMORY_H
+#define _ZEBRA_MEMORY_H
+
+/* #define MEMORY_LOG */
+
+/* For tagging memory, below is the type of the memory. */
+enum
+{
+ MTYPE_TMP = 1,
+ MTYPE_STRVEC,
+ MTYPE_VECTOR,
+ MTYPE_VECTOR_INDEX,
+ MTYPE_LINK_LIST,
+ MTYPE_LINK_NODE,
+ MTYPE_THREAD,
+ MTYPE_THREAD_MASTER,
+ MTYPE_VTY,
+ MTYPE_VTY_HIST,
+ MTYPE_VTY_OUT_BUF,
+ MTYPE_IF,
+ MTYPE_CONNECTED,
+ MTYPE_AS_SEG,
+ MTYPE_AS_STR,
+ MTYPE_AS_PATH,
+ MTYPE_CLUSTER,
+ MTYPE_CLUSTER_VAL,
+ MTYPE_ATTR,
+ MTYPE_TRANSIT,
+ MTYPE_TRANSIT_VAL,
+ MTYPE_BUFFER,
+ MTYPE_BUFFER_DATA,
+ MTYPE_STREAM,
+ MTYPE_STREAM_DATA,
+ MTYPE_STREAM_FIFO,
+ MTYPE_PREFIX,
+ MTYPE_PREFIX_IPV4,
+ MTYPE_PREFIX_IPV6,
+ MTYPE_HASH,
+ MTYPE_HASH_INDEX,
+ MTYPE_HASH_BACKET,
+ MTYPE_RIPNG_ROUTE,
+ MTYPE_RIPNG_AGGREGATE,
+ MTYPE_ROUTE_TABLE,
+ MTYPE_ROUTE_NODE,
+ MTYPE_ACCESS_LIST,
+ MTYPE_ACCESS_LIST_STR,
+ MTYPE_ACCESS_FILTER,
+ MTYPE_PREFIX_LIST,
+ MTYPE_PREFIX_LIST_STR,
+ MTYPE_PREFIX_LIST_ENTRY,
+ MTYPE_ROUTE_MAP,
+ MTYPE_ROUTE_MAP_NAME,
+ MTYPE_ROUTE_MAP_INDEX,
+ MTYPE_ROUTE_MAP_RULE,
+ MTYPE_ROUTE_MAP_RULE_STR,
+ MTYPE_ROUTE_MAP_COMPILED,
+
+ MTYPE_RIB,
+ MTYPE_DISTRIBUTE,
+ MTYPE_ZLOG,
+ MTYPE_ZCLIENT,
+ MTYPE_NEXTHOP,
+ MTYPE_RTADV_PREFIX,
+ MTYPE_IF_RMAP,
+ MTYPE_SOCKUNION,
+ MTYPE_STATIC_IPV4,
+ MTYPE_STATIC_IPV6,
+
+ MTYPE_DESC,
+ MTYPE_OSPF_TOP,
+ MTYPE_OSPF_AREA,
+ MTYPE_OSPF_AREA_RANGE,
+ MTYPE_OSPF_NETWORK,
+ MTYPE_OSPF_NEIGHBOR_STATIC,
+ MTYPE_OSPF_IF,
+ MTYPE_OSPF_NEIGHBOR,
+ MTYPE_OSPF_ROUTE,
+ MTYPE_OSPF_TMP,
+ MTYPE_OSPF_LSA,
+ MTYPE_OSPF_LSA_DATA,
+ MTYPE_OSPF_LSDB,
+ MTYPE_OSPF_PACKET,
+ MTYPE_OSPF_FIFO,
+ MTYPE_OSPF_VERTEX,
+ MTYPE_OSPF_NEXTHOP,
+ MTYPE_OSPF_PATH,
+ MTYPE_OSPF_VL_DATA,
+ MTYPE_OSPF_CRYPT_KEY,
+ MTYPE_OSPF_EXTERNAL_INFO,
+ MTYPE_OSPF_MESSAGE,
+ MTYPE_OSPF_DISTANCE,
+ MTYPE_OSPF_IF_INFO,
+ MTYPE_OSPF_IF_PARAMS,
+
+ MTYPE_OSPF6_TOP,
+ MTYPE_OSPF6_AREA,
+ MTYPE_OSPF6_IF,
+ MTYPE_OSPF6_NEIGHBOR,
+ MTYPE_OSPF6_ROUTE,
+ MTYPE_OSPF6_PREFIX,
+ MTYPE_OSPF6_MESSAGE,
+ MTYPE_OSPF6_LSA,
+ MTYPE_OSPF6_LSA_SUMMARY,
+ MTYPE_OSPF6_LSDB,
+ MTYPE_OSPF6_VERTEX,
+ MTYPE_OSPF6_SPFTREE,
+ MTYPE_OSPF6_NEXTHOP,
+ MTYPE_OSPF6_EXTERNAL_INFO,
+ MTYPE_OSPF6_OTHER,
+
+ MTYPE_ISIS,
+ MTYPE_ISIS_TMP,
+ MTYPE_ISIS_CIRCUIT,
+ MTYPE_ISIS_LSP,
+ MTYPE_ISIS_ADJACENCY,
+ MTYPE_ISIS_AREA,
+ MTYPE_ISIS_AREA_ADDR,
+ MTYPE_ISIS_TLV,
+ MTYPE_ISIS_DYNHN,
+ MTYPE_ISIS_SPFTREE,
+ MTYPE_ISIS_VERTEX,
+ MTYPE_ISIS_ROUTE_INFO,
+ MTYPE_ISIS_NEXTHOP,
+ MTYPE_ISIS_NEXTHOP6,
+
+ MTYPE_BGP,
+ MTYPE_BGP_PEER,
+ MTYPE_PEER_GROUP,
+ MTYPE_PEER_DESC,
+ MTYPE_PEER_UPDATE_SOURCE,
+ MTYPE_BGP_STATIC,
+ MTYPE_BGP_AGGREGATE,
+ MTYPE_BGP_CONFED_LIST,
+ MTYPE_BGP_NEXTHOP_CACHE,
+ MTYPE_BGP_DAMP_INFO,
+ MTYPE_BGP_DAMP_ARRAY,
+ MTYPE_BGP_ANNOUNCE,
+ MTYPE_BGP_ATTR_QUEUE,
+ MTYPE_BGP_ROUTE_QUEUE,
+ MTYPE_BGP_DISTANCE,
+ MTYPE_BGP_ROUTE,
+ MTYPE_BGP_TABLE,
+ MTYPE_BGP_NODE,
+ MTYPE_BGP_ADVERTISE_ATTR,
+ MTYPE_BGP_ADVERTISE,
+ MTYPE_BGP_ADJ_IN,
+ MTYPE_BGP_ADJ_OUT,
+ MTYPE_BGP_REGEXP,
+ MTYPE_AS_FILTER,
+ MTYPE_AS_FILTER_STR,
+ MTYPE_AS_LIST,
+
+ MTYPE_COMMUNITY,
+ MTYPE_COMMUNITY_VAL,
+ MTYPE_COMMUNITY_STR,
+
+ MTYPE_ECOMMUNITY,
+ MTYPE_ECOMMUNITY_VAL,
+ MTYPE_ECOMMUNITY_STR,
+
+ /* community-list and extcommunity-list. */
+ MTYPE_COMMUNITY_LIST_HANDLER,
+ MTYPE_COMMUNITY_LIST,
+ MTYPE_COMMUNITY_LIST_NAME,
+ MTYPE_COMMUNITY_LIST_ENTRY,
+ MTYPE_COMMUNITY_LIST_CONFIG,
+
+ MTYPE_RIP,
+ MTYPE_RIP_INTERFACE,
+ MTYPE_RIP_DISTANCE,
+ MTYPE_RIP_OFFSET_LIST,
+ MTYPE_RIP_INFO,
+ MTYPE_RIP_PEER,
+ MTYPE_KEYCHAIN,
+ MTYPE_KEY,
+
+ MTYPE_VTYSH_CONFIG,
+ MTYPE_VTYSH_CONFIG_LINE,
+
+ MTYPE_MAX
+};
+
+#ifdef MEMORY_LOG
+#define XMALLOC(mtype, size) \
+ mtype_zmalloc (__FILE__, __LINE__, (mtype), (size))
+#define XCALLOC(mtype, size) \
+ mtype_zcalloc (__FILE__, __LINE__, (mtype), (size))
+#define XREALLOC(mtype, ptr, size) \
+ mtype_zrealloc (__FILE__, __LINE__, (mtype), (ptr), (size))
+#define XFREE(mtype, ptr) \
+ mtype_zfree (__FILE__, __LINE__, (mtype), (ptr))
+#define XSTRDUP(mtype, str) \
+ mtype_zstrdup (__FILE__, __LINE__, (mtype), (str))
+#else
+#define XMALLOC(mtype, size) zmalloc ((mtype), (size))
+#define XCALLOC(mtype, size) zcalloc ((mtype), (size))
+#define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size))
+#define XFREE(mtype, ptr) zfree ((mtype), (ptr))
+#define XSTRDUP(mtype, str) zstrdup ((mtype), (str))
+#endif /* MEMORY_LOG */
+
+/* Prototypes of memory function. */
+void *zmalloc (int type, size_t size);
+void *zcalloc (int type, size_t size);
+void *zrealloc (int type, void *ptr, size_t size);
+void zfree (int type, void *ptr);
+char *zstrdup (int type, char *str);
+
+void *mtype_zmalloc (const char *file,
+ int line,
+ int type,
+ size_t size);
+
+void *mtype_zcalloc (const char *file,
+ int line,
+ int type,
+ size_t num,
+ size_t size);
+
+void *mtype_zrealloc (const char *file,
+ int line,
+ int type,
+ void *ptr,
+ size_t size);
+
+void mtype_zfree (const char *file,
+ int line,
+ int type,
+ void *ptr);
+
+char *mtype_zstrdup (const char *file,
+ int line,
+ int type,
+ char *str);
+void memory_init ();
+
+#endif /* _ZEBRA_MEMORY_H */
diff --git a/isisd/modified/rib.c b/isisd/modified/rib.c
new file mode 100644
index 00000000..39a7690b
--- /dev/null
+++ b/isisd/modified/rib.c
@@ -0,0 +1,3321 @@
+/* Routing Information Base.
+ * Copyright (C) 1997, 98, 99, 2001 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "vty.h"
+#include "str.h"
+#include "command.h"
+#include "linklist.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+
+/* Routing information base and static table for IPv4. */
+struct route_table *rib_table_ipv4;
+struct route_table *static_table_ipv4;
+
+/* Routing information base and static table for IPv6. */
+#ifdef HAVE_IPV6
+struct route_table *rib_table_ipv6;
+struct route_table *static_table_ipv6;
+#endif /* HAVE_IPV6 */
+
+/* Default rtm_table for all clients */
+extern int rtm_table_default;
+
+/* Each route type's string and default distance value. */
+struct
+{
+ int key;
+ char c;
+ char *str;
+ int distance;
+} route_info[] =
+{
+ {ZEBRA_ROUTE_SYSTEM, 'X', "system", 0},
+ {ZEBRA_ROUTE_KERNEL, 'K', "kernel", 0},
+ {ZEBRA_ROUTE_CONNECT, 'C', "connected", 0},
+ {ZEBRA_ROUTE_STATIC, 'S', "static", 1},
+ {ZEBRA_ROUTE_RIP, 'R', "rip", 120},
+ {ZEBRA_ROUTE_RIPNG, 'R', "ripng", 120},
+ {ZEBRA_ROUTE_OSPF, 'O', "ospf", 110},
+ {ZEBRA_ROUTE_OSPF6, 'O', "ospf6", 110},
+ {ZEBRA_ROUTE_ISIS, 'I', "isis", 115},
+ {ZEBRA_ROUTE_BGP, 'B', "bgp", 20 /* IBGP is 200. */}
+};
+
+/* Add nexthop to the end of the list. */
+void
+nexthop_add (struct rib *rib, struct nexthop *nexthop)
+{
+ struct nexthop *last;
+
+ for (last = rib->nexthop; last && last->next; last = last->next)
+ ;
+ if (last)
+ last->next = nexthop;
+ else
+ rib->nexthop = nexthop;
+ nexthop->prev = last;
+
+ rib->nexthop_num++;
+}
+
+/* Delete specified nexthop from the list. */
+void
+nexthop_delete (struct rib *rib, struct nexthop *nexthop)
+{
+ if (nexthop->next)
+ nexthop->next->prev = nexthop->prev;
+ if (nexthop->prev)
+ nexthop->prev->next = nexthop->next;
+ else
+ rib->nexthop = nexthop->next;
+ rib->nexthop_num--;
+}
+
+/* Free nexthop. */
+void
+nexthop_free (struct nexthop *nexthop)
+{
+ if (nexthop->type == NEXTHOP_TYPE_IFNAME && nexthop->ifname)
+ free (nexthop->ifname);
+ XFREE (MTYPE_NEXTHOP, nexthop);
+}
+
+struct nexthop *
+nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IFINDEX;
+ nexthop->ifindex = ifindex;
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+
+struct nexthop *
+nexthop_ifname_add (struct rib *rib, char *ifname)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IFNAME;
+ nexthop->ifname = strdup (ifname);
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IPV4;
+ nexthop->gate.ipv4 = *ipv4;
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
+ unsigned int ifindex)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ nexthop->gate.ipv4 = *ipv4;
+ nexthop->ifindex = ifindex;
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+
+#ifdef HAVE_IPV6
+struct nexthop *
+nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IPV6;
+ nexthop->gate.ipv6 = *ipv6;
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
+ char *ifname)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
+ nexthop->gate.ipv6 = *ipv6;
+ nexthop->ifname = XSTRDUP (0, ifname);
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+
+struct nexthop *
+nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
+ unsigned int ifindex)
+{
+ struct nexthop *nexthop;
+
+ nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nexthop->gate.ipv6 = *ipv6;
+ nexthop->ifindex = ifindex;
+
+ nexthop_add (rib, nexthop);
+
+ return nexthop;
+}
+#endif /* HAVE_IPV6 */
+
+/* If force flag is not set, do not modify falgs at all for uninstall
+ the route from FIB. */
+int
+nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
+ struct route_node *top)
+{
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+ struct rib *match;
+ struct nexthop *newhop;
+
+ if (nexthop->type == NEXTHOP_TYPE_IPV4)
+ nexthop->ifindex = 0;
+
+ if (set)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+ /* Make lookup prefix. */
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+ p.prefix = nexthop->gate.ipv4;
+
+ rn = route_node_match (rib_table_ipv4, (struct prefix *) &p);
+ while (rn)
+ {
+ route_unlock_node (rn);
+
+ /* If lookup self prefix return immidiately. */
+ if (rn == top)
+ return 0;
+
+ /* Pick up selected route. */
+ for (match = rn->info; match; match = match->next)
+ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ break;
+
+ /* If there is no selected route or matched route is EGP, go up
+ tree. */
+ if (! match
+ || match->type == ZEBRA_ROUTE_BGP)
+ {
+ do {
+ rn = rn->parent;
+ } while (rn && rn->info == NULL);
+ if (rn)
+ route_lock_node (rn);
+ }
+ else
+ {
+ if (match->type == ZEBRA_ROUTE_CONNECT)
+ {
+ /* Directly point connected route. */
+ newhop = match->nexthop;
+ if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4)
+ nexthop->ifindex = newhop->ifindex;
+
+ return 1;
+ }
+ else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+ {
+ for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+ && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (set)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ nexthop->rtype = newhop->type;
+ if (newhop->type == NEXTHOP_TYPE_IPV4 ||
+ newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ nexthop->rgate.ipv4 = newhop->gate.ipv4;
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME
+ || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ nexthop->rifindex = newhop->ifindex;
+ }
+ return 1;
+ }
+ return 0;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+/* If force flag is not set, do not modify falgs at all for uninstall
+ the route from FIB. */
+int
+nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
+ struct route_node *top)
+{
+ struct prefix_ipv6 p;
+ struct route_node *rn;
+ struct rib *match;
+ struct nexthop *newhop;
+
+ if (nexthop->type == NEXTHOP_TYPE_IPV6)
+ nexthop->ifindex = 0;
+
+ if (set)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+ /* Make lookup prefix. */
+ memset (&p, 0, sizeof (struct prefix_ipv6));
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_PREFIXLEN;
+ p.prefix = nexthop->gate.ipv6;
+
+ rn = route_node_match (rib_table_ipv6, (struct prefix *) &p);
+ while (rn)
+ {
+ route_unlock_node (rn);
+
+ /* If lookup self prefix return immidiately. */
+ if (rn == top)
+ return 0;
+
+ /* Pick up selected route. */
+ for (match = rn->info; match; match = match->next)
+ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ break;
+
+ /* If there is no selected route or matched route is EGP, go up
+ tree. */
+ if (! match
+ || match->type == ZEBRA_ROUTE_BGP)
+ {
+ do {
+ rn = rn->parent;
+ } while (rn && rn->info == NULL);
+ if (rn)
+ route_lock_node (rn);
+ }
+ else
+ {
+ if (match->type == ZEBRA_ROUTE_CONNECT)
+ {
+ /* Directly point connected route. */
+ newhop = match->nexthop;
+
+ if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6)
+ nexthop->ifindex = newhop->ifindex;
+
+ return 1;
+ }
+ else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
+ {
+ for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
+ && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ if (set)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ nexthop->rtype = newhop->type;
+ if (newhop->type == NEXTHOP_TYPE_IPV6
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ nexthop->rgate.ipv6 = newhop->gate.ipv6;
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ nexthop->rifindex = newhop->ifindex;
+ }
+ return 1;
+ }
+ return 0;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+#endif /* HAVE_IPV6 */
+
+struct rib *
+rib_match_ipv4 (struct in_addr addr)
+{
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+ struct rib *match;
+ struct nexthop *newhop;
+
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_PREFIXLEN;
+ p.prefix = addr;
+
+ rn = route_node_match (rib_table_ipv4, (struct prefix *) &p);
+
+ while (rn)
+ {
+ route_unlock_node (rn);
+
+ /* Pick up selected route. */
+ for (match = rn->info; match; match = match->next)
+ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ break;
+
+ /* If there is no selected route or matched route is EGP, go up
+ tree. */
+ if (! match
+ || match->type == ZEBRA_ROUTE_BGP)
+ {
+ do {
+ rn = rn->parent;
+ } while (rn && rn->info == NULL);
+ if (rn)
+ route_lock_node (rn);
+ }
+ else
+ {
+ if (match->type == ZEBRA_ROUTE_CONNECT)
+ /* Directly point connected route. */
+ return match;
+ else
+ {
+ for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+ return match;
+ return NULL;
+ }
+ }
+ }
+ return NULL;
+}
+
+struct rib *
+rib_lookup_ipv4 (struct prefix_ipv4 *p)
+{
+ struct route_node *rn;
+ struct rib *match;
+ struct nexthop *nexthop;
+
+ rn = route_node_lookup (rib_table_ipv4, (struct prefix *) p);
+
+ /* No route for this prefix. */
+ if (! rn)
+ return NULL;
+
+ /* Unlock node. */
+ route_unlock_node (rn);
+
+ /* Pick up selected route. */
+ for (match = rn->info; match; match = match->next)
+ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ break;
+
+ if (! match || match->type == ZEBRA_ROUTE_BGP)
+ return NULL;
+
+ if (match->type == ZEBRA_ROUTE_CONNECT)
+ return match;
+
+ for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ return match;
+
+ return NULL;
+}
+
+#ifdef HAVE_IPV6
+struct rib *
+rib_match_ipv6 (struct in6_addr *addr)
+{
+ struct prefix_ipv6 p;
+ struct route_node *rn;
+ struct rib *match;
+ struct nexthop *newhop;
+
+ memset (&p, 0, sizeof (struct prefix_ipv6));
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_PREFIXLEN;
+ IPV6_ADDR_COPY (&p.prefix, addr);
+
+ rn = route_node_match (rib_table_ipv6, (struct prefix *) &p);
+
+ while (rn)
+ {
+ route_unlock_node (rn);
+
+ /* Pick up selected route. */
+ for (match = rn->info; match; match = match->next)
+ if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+ break;
+
+ /* If there is no selected route or matched route is EGP, go up
+ tree. */
+ if (! match
+ || match->type == ZEBRA_ROUTE_BGP)
+ {
+ do {
+ rn = rn->parent;
+ } while (rn && rn->info == NULL);
+ if (rn)
+ route_lock_node (rn);
+ }
+ else
+ {
+ if (match->type == ZEBRA_ROUTE_CONNECT)
+ /* Directly point connected route. */
+ return match;
+ else
+ {
+ for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+ return match;
+ return NULL;
+ }
+ }
+ }
+ return NULL;
+}
+#endif /* HAVE_IPV6 */
+
+int
+nexthop_active_check (struct route_node *rn, struct rib *rib,
+ struct nexthop *nexthop, int set)
+{
+ struct interface *ifp;
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IFINDEX:
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (ifp && if_is_up (ifp))
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ ifp = if_lookup_by_name (nexthop->ifname);
+ if (ifp && if_is_up (ifp))
+ {
+ if (set)
+ nexthop->ifindex = ifp->ifindex;
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+ else
+ {
+ if (set)
+ nexthop->ifindex = 0;
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ if (nexthop_active_ipv4 (rib, nexthop, set, rn))
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ break;
+#ifdef HAVE_IPV6
+ case NEXTHOP_TYPE_IPV6:
+ if (nexthop_active_ipv6 (rib, nexthop, set, rn))
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
+ {
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (ifp && if_is_up (ifp))
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+ else
+ {
+ if (nexthop_active_ipv6 (rib, nexthop, set, rn))
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+ break;
+#endif /* HAVE_IPV6 */
+ default:
+ break;
+ }
+ return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+}
+
+int
+nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
+{
+ struct nexthop *nexthop;
+ int active;
+
+ rib->nexthop_active_num = 0;
+ UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ rib->nexthop_active_num += nexthop_active_check (rn, rib, nexthop, set);
+ if (active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+ }
+ return rib->nexthop_active_num;
+}
+
+#define RIB_SYSTEM_ROUTE(R) \
+ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+
+void
+newrib_free (struct rib *rib)
+{
+ struct nexthop *nexthop;
+ struct nexthop *next;
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = next)
+ {
+ next = nexthop->next;
+ nexthop_free (nexthop);
+ }
+ XFREE (MTYPE_RIB, rib);
+}
+
+void
+rib_install_kernel (struct route_node *rn, struct rib *rib)
+{
+ int ret = 0;
+ struct nexthop *nexthop;
+
+ switch (PREFIX_FAMILY (&rn->p))
+ {
+ case AF_INET:
+ ret = kernel_add_ipv4 (&rn->p, rib);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = kernel_add_ipv6 (&rn->p, rib);
+ break;
+#endif /* HAVE_IPV6 */
+ }
+
+ if (ret < 0)
+ {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+}
+
+/* Uninstall the route from kernel. */
+int
+rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
+{
+ int ret = 0;
+ struct nexthop *nexthop;
+
+ switch (PREFIX_FAMILY (&rn->p))
+ {
+ case AF_INET:
+ ret = kernel_delete_ipv4 (&rn->p, rib);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = kernel_delete_ipv6 (&rn->p, rib);
+ break;
+#endif /* HAVE_IPV6 */
+ }
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ return ret;
+}
+
+/* Uninstall the route from kernel. */
+void
+rib_uninstall (struct route_node *rn, struct rib *rib)
+{
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ {
+ redistribute_delete (&rn->p, rib);
+ if (! RIB_SYSTEM_ROUTE (rib))
+ rib_uninstall_kernel (rn, rib);
+ UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
+ }
+}
+
+/* Core function for processing routing information base. */
+void
+rib_process (struct route_node *rn, struct rib *del)
+{
+ struct rib *rib;
+ struct rib *next;
+ struct rib *fib = NULL;
+ struct rib *select = NULL;
+
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+
+ /* Currently installed rib. */
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ fib = rib;
+
+ /* Skip unreachable nexthop. */
+ if (! nexthop_active_update (rn, rib, 0))
+ continue;
+
+ /* Infinit distance. */
+ if (rib->distance == DISTANCE_INFINITY)
+ continue;
+
+ /* Newly selected rib. */
+ if (! select || rib->distance < select->distance
+ || rib->type == ZEBRA_ROUTE_CONNECT)
+ select = rib;
+ }
+
+ /* Deleted route check. */
+ if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED))
+ fib = del;
+
+ /* Same route is selected. */
+ if (select && select == fib)
+ {
+ if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED))
+ {
+ redistribute_delete (&rn->p, select);
+ if (! RIB_SYSTEM_ROUTE (select))
+ rib_uninstall_kernel (rn, select);
+
+ /* Set real nexthop. */
+ nexthop_active_update (rn, select, 1);
+
+ if (! RIB_SYSTEM_ROUTE (select))
+ rib_install_kernel (rn, select);
+ redistribute_add (&rn->p, select);
+ }
+ return;
+ }
+
+ /* Uninstall old rib from forwarding table. */
+ if (fib)
+ {
+ redistribute_delete (&rn->p, fib);
+ if (! RIB_SYSTEM_ROUTE (fib))
+ rib_uninstall_kernel (rn, fib);
+ UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+
+ /* Set real nexthop. */
+ nexthop_active_update (rn, fib, 1);
+ }
+
+ /* Install new rib into forwarding table. */
+ if (select)
+ {
+ /* Set real nexthop. */
+ nexthop_active_update (rn, select, 1);
+
+ if (! RIB_SYSTEM_ROUTE (select))
+ rib_install_kernel (rn, select);
+ SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
+ redistribute_add (&rn->p, select);
+ }
+}
+
+/* Add RIB to head of the route node. */
+void
+rib_addnode (struct route_node *rn, struct rib *rib)
+{
+ struct rib *head;
+
+ head = rn->info;
+ if (head)
+ head->prev = rib;
+ rib->next = head;
+ rn->info = rib;
+}
+
+void
+rib_delnode (struct route_node *rn, struct rib *rib)
+{
+ if (rib->next)
+ rib->next->prev = rib->prev;
+ if (rib->prev)
+ rib->prev->next = rib->next;
+ else
+ rn->info = rib->next;
+}
+
+int
+rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+ struct in_addr *gate, unsigned int ifindex, int table,
+ u_int32_t metric, u_char distance)
+{
+ struct rib *rib;
+ struct rib *same = NULL;
+ struct route_node *rn;
+ struct nexthop *nexthop;
+
+ /* Make it sure prefixlen is applied to the prefix. */
+ apply_mask_ipv4 (p);
+
+ /* Set default distance by route type. */
+ if (distance == 0)
+ {
+ distance = route_info[type].distance;
+
+ /* iBGP distance is 200. */
+ if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
+ distance = 200;
+ }
+
+ /* Lookup route node.*/
+ rn = route_node_get (rib_table_ipv4, (struct prefix *) p);
+
+ /* If same type of route are installed, treat it as a implicit
+ withdraw. */
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (rib->type == ZEBRA_ROUTE_CONNECT)
+ {
+ nexthop = rib->nexthop;
+
+ /* Duplicate connected route comes in. */
+ if (rib->type == type
+ && (! table || rib->table == table)
+ && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+ && nexthop->ifindex == ifindex)
+ {
+ rib->refcnt++;
+ return 0 ;
+ }
+ }
+ else if (rib->type == type
+ && (! table || rib->table == table))
+ {
+ same = rib;
+ rib_delnode (rn, same);
+ route_unlock_node (rn);
+ break;
+ }
+ }
+
+ /* Allocate new rib structure. */
+ rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+ memset (rib, 0, sizeof (struct rib));
+ rib->type = type;
+ rib->distance = distance;
+ rib->flags = flags;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ /* Nexthop settings. */
+ if (gate)
+ {
+ if (ifindex)
+ nexthop_ipv4_ifindex_add (rib, gate, ifindex);
+ else
+ nexthop_ipv4_add (rib, gate);
+ }
+ else
+ nexthop_ifindex_add (rib, ifindex);
+
+ /* If this route is kernel route, set FIB flag to the route. */
+ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
+
+ /* Process this route node. */
+ rib_process (rn, same);
+
+ /* Free implicit route.*/
+ if (same)
+ newrib_free (same);
+
+ return 0;
+}
+
+int
+rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+{
+ struct route_node *rn;
+ struct rib *same;
+ struct nexthop *nexthop;
+
+ /* Make it sure prefixlen is applied to the prefix. */
+ apply_mask_ipv4 (p);
+
+ /* Set default distance by route type. */
+ if (rib->distance == 0)
+ {
+ rib->distance = route_info[rib->type].distance;
+
+ /* iBGP distance is 200. */
+ if (rib->type == ZEBRA_ROUTE_BGP
+ && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+ rib->distance = 200;
+ }
+
+ /* Lookup route node.*/
+ rn = route_node_get (rib_table_ipv4, (struct prefix *) p);
+
+ /* If same type of route are installed, treat it as a implicit
+ withdraw. */
+ for (same = rn->info; same; same = same->next)
+ {
+ if (same->type == rib->type && same->table == rib->table
+ && same->type != ZEBRA_ROUTE_CONNECT)
+ {
+ rib_delnode (rn, same);
+ route_unlock_node (rn);
+ break;
+ }
+ }
+
+ /* If this route is kernel route, set FIB flag to the route. */
+ if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
+
+ /* Process this route node. */
+ rib_process (rn, same);
+
+ /* Free implicit route.*/
+ if (same)
+ newrib_free (same);
+
+ return 0;
+}
+
+int
+rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+ struct in_addr *gate, unsigned int ifindex, int table)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *fib = NULL;
+ struct rib *same = NULL;
+ struct nexthop *nexthop;
+ char buf1[BUFSIZ];
+ char buf2[BUFSIZ];
+
+ /* Apply mask. */
+ apply_mask_ipv4 (p);
+
+ /* Lookup route node. */
+ rn = route_node_lookup (rib_table_ipv4, (struct prefix *) p);
+ if (! rn)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ if (gate)
+ zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib",
+ inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+ ifindex);
+ else
+ zlog_info ("route %s/%d ifindex %d doesn't exist in rib",
+ inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ ifindex);
+ }
+ return ZEBRA_ERR_RTNOEXIST;
+ }
+
+ /* Lookup same type route. */
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ fib = rib;
+
+ if (rib->type == ZEBRA_ROUTE_CONNECT)
+ {
+ nexthop = rib->nexthop;
+
+ if (rib->type == type
+ && (! table || rib->table == table)
+ && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+ && nexthop->ifindex == ifindex)
+ {
+ if (rib->refcnt)
+ {
+ rib->refcnt--;
+ route_unlock_node (rn);
+ route_unlock_node (rn);
+ return 0;
+ }
+ same = rib;
+ break;
+ }
+ }
+ else
+ {
+ if (rib->type == type
+ && (!table || rib->table == table))
+ {
+ same = rib;
+ break;
+ }
+ }
+ }
+
+ /* If same type of route can't be found and this message is from
+ kernel. */
+ if (! same)
+ {
+ if (fib && type == ZEBRA_ROUTE_KERNEL)
+ {
+ /* Unset flags. */
+ for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+ }
+ else
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ if (gate)
+ zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
+ inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+ ifindex,
+ type);
+ else
+ zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib",
+ inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ ifindex,
+ type);
+ }
+ route_unlock_node (rn);
+ return ZEBRA_ERR_RTNOEXIST;
+ }
+ }
+
+ if (same)
+ rib_delnode (rn, same);
+
+ /* Process changes. */
+ rib_process (rn, same);
+
+ if (same)
+ {
+ newrib_free (same);
+ route_unlock_node (rn);
+ }
+
+ route_unlock_node (rn);
+
+ return 0;
+}
+
+/* Delete all added route and close rib. */
+void
+rib_close_ipv4 ()
+{
+ struct route_node *rn;
+ struct rib *rib;
+
+ for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (! RIB_SYSTEM_ROUTE (rib)
+ && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ rib_uninstall_kernel (rn, rib);
+}
+
+/* Install static route into rib. */
+void
+static_ipv4_install (struct prefix_ipv4 *p, struct static_ipv4 *si)
+{
+ struct rib *rib;
+ struct route_node *rn;
+
+ /* Lookup existing route */
+ rn = route_node_get (rib_table_ipv4, (struct prefix *) p);
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+ break;
+
+ if (rib)
+ {
+ /* Same distance static route is there. Update it with new
+ nexthop. */
+ rib_uninstall (rn, rib);
+ route_unlock_node (rn);
+
+ switch (si->type)
+ {
+ case STATIC_IPV4_GATEWAY:
+ nexthop_ipv4_add (rib, &si->gate.ipv4);
+ break;
+ case STATIC_IPV4_IFNAME:
+ nexthop_ifname_add (rib, si->gate.ifname);
+ break;
+ }
+ rib_process (rn, NULL);
+ }
+ else
+ {
+ /* This is new static route. */
+ rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+ memset (rib, 0, sizeof (struct rib));
+
+ rib->type = ZEBRA_ROUTE_STATIC;
+ rib->distance = si->distance;
+ rib->metric = 0;
+ rib->nexthop_num = 0;
+
+ switch (si->type)
+ {
+ case STATIC_IPV4_GATEWAY:
+ nexthop_ipv4_add (rib, &si->gate.ipv4);
+ break;
+ case STATIC_IPV4_IFNAME:
+ nexthop_ifname_add (rib, si->gate.ifname);
+ break;
+ }
+
+ /* Link this rib to the tree. */
+ rib_addnode (rn, rib);
+
+ /* Process this prefix. */
+ rib_process (rn, NULL);
+ }
+}
+
+int
+static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si)
+{
+ if (nexthop->type == NEXTHOP_TYPE_IPV4
+ && si->type == STATIC_IPV4_GATEWAY
+ && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4))
+ return 1;
+ if (nexthop->type == NEXTHOP_TYPE_IFNAME
+ && si->type == STATIC_IPV4_IFNAME
+ && strcmp (nexthop->ifname, si->gate.ifname) == 0)
+ return 1;
+ return 0;;
+}
+
+/* Uninstall static route from RIB. */
+void
+static_ipv4_uninstall (struct prefix_ipv4 *p, struct static_ipv4 *si)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct nexthop *nexthop;
+
+ /* Lookup existing route with type and distance. */
+ rn = route_node_lookup (rib_table_ipv4, (struct prefix *) p);
+ if (! rn)
+ return;
+
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+ break;
+ if (! rib)
+ {
+ route_unlock_node (rn);
+ return;
+ }
+
+ /* Lookup nexthop. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ if (static_ipv4_nexthop_same (nexthop, si))
+ break;
+
+ /* Can't find nexthop. */
+ if (! nexthop)
+ {
+ route_unlock_node (rn);
+ return;
+ }
+
+ /* Check nexthop. */
+ if (rib->nexthop_num == 1)
+ {
+ rib_delnode (rn, rib);
+ rib_process (rn, rib);
+ newrib_free (rib);
+ route_unlock_node (rn);
+ }
+ else
+ {
+ rib_uninstall (rn, rib);
+ nexthop_delete (rib, nexthop);
+ nexthop_free (nexthop);
+ rib_process (rn, rib);
+ }
+
+ /* Unlock node. */
+ route_unlock_node (rn);
+}
+
+/* Add static route into static route configuration. */
+int
+static_ipv4_add (struct prefix_ipv4 *p, struct in_addr *gate, char *ifname,
+ u_char distance, int table)
+{
+ u_char type = 0;
+ struct route_node *rn;
+ struct static_ipv4 *si;
+ struct static_ipv4 *pp;
+ struct static_ipv4 *cp;
+
+ /* Lookup static route prefix. */
+ rn = route_node_get (static_table_ipv4, (struct prefix *) p);
+
+ /* Make flags. */
+ if (gate)
+ type = STATIC_IPV4_GATEWAY;
+ if (ifname)
+ type = STATIC_IPV4_IFNAME;
+
+ /* Do nothing if there is a same static route. */
+ for (si = rn->info; si; si = si->next)
+ {
+ if (distance == si->distance
+ && type == si->type
+ && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
+ && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+ {
+ route_unlock_node (rn);
+ return 0;
+ }
+ }
+
+ /* Make new static route structure. */
+ si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
+ memset (si, 0, sizeof (struct static_ipv4));
+
+ si->type = type;
+ si->distance = distance;
+
+ if (gate)
+ si->gate.ipv4 = *gate;
+ if (ifname)
+ si->gate.ifname = XSTRDUP (0, ifname);
+
+ /* Add new static route information to the tree with sort by
+ distance value and gateway address. */
+ for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+ {
+ if (si->distance < cp->distance)
+ break;
+ if (si->distance > cp->distance)
+ continue;
+ if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
+ {
+ if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr))
+ break;
+ if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr))
+ continue;
+ }
+ }
+
+ /* Make linked list. */
+ if (pp)
+ pp->next = si;
+ else
+ rn->info = si;
+ if (cp)
+ cp->prev = si;
+ si->prev = pp;
+ si->next = cp;
+
+ /* Install into rib. */
+ static_ipv4_install (p, si);
+
+ return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *gate, char *ifname,
+ u_char distance, int table)
+{
+ u_char type = 0;
+ struct route_node *rn;
+ struct static_ipv4 *si;
+
+ /* Lookup static route prefix. */
+ rn = route_node_lookup (static_table_ipv4, (struct prefix *) p);
+ if (! rn)
+ return 0;
+
+ /* Make flags. */
+ if (gate)
+ type = STATIC_IPV4_GATEWAY;
+ if (ifname)
+ type = STATIC_IPV4_IFNAME;
+
+ /* Find same static route is the tree */
+ for (si = rn->info; si; si = si->next)
+ if (distance == si->distance
+ && type == si->type
+ && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
+ && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+ break;
+
+ /* Can't find static route. */
+ if (! si)
+ {
+ route_unlock_node (rn);
+ return 0;
+ }
+
+ /* Install into rib. */
+ static_ipv4_uninstall (p, si);
+
+ /* Unlink static route from linked list. */
+ if (si->prev)
+ si->prev->next = si->next;
+ else
+ rn->info = si->next;
+ if (si->next)
+ si->next->prev = si->prev;
+
+ /* Free static route configuration. */
+ XFREE (MTYPE_STATIC_IPV4, si);
+
+ return 1;
+}
+
+/* Write IPv4 static route configuration. */
+int
+static_ipv4_write (struct vty *vty)
+{
+ struct route_node *rn;
+ struct static_ipv4 *si;
+ int write;
+
+ write = 0;
+
+ for (rn = route_top (static_table_ipv4); rn; rn = route_next (rn))
+ for (si = rn->info; si; si = si->next)
+ {
+ vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4),
+ rn->p.prefixlen);
+
+ switch (si->type)
+ {
+ case STATIC_IPV4_GATEWAY:
+ vty_out (vty, " %s", inet_ntoa (si->gate.ipv4));
+ break;
+ case STATIC_IPV4_IFNAME:
+ vty_out (vty, " %s", si->gate.ifname);
+ break;
+ }
+
+ if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+ vty_out (vty, " %d", si->distance);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ write = 1;
+ }
+ return write;
+}
+
+/* General fucntion for static route. */
+int
+static_ipv4_func (struct vty *vty, int add_cmd,
+ char *dest_str, char *mask_str, char *gate_str,
+ char *distance_str)
+{
+ int ret;
+ u_char distance;
+ struct prefix_ipv4 p;
+ struct in_addr gate;
+ struct in_addr mask;
+ char *ifname;
+ int table = rtm_table_default;
+
+ ret = str2prefix_ipv4 (dest_str, &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Cisco like mask notation. */
+ if (mask_str)
+ {
+ ret = inet_aton (mask_str, &mask);
+ if (ret == 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ p.prefixlen = ip_masklen (mask);
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask_ipv4 (&p);
+
+ /* Administrative distance. */
+ if (distance_str)
+ distance = atoi (distance_str);
+ else
+ distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+ /* When gateway is A.B.C.D format, gate is treated as nexthop
+ address other case gate is treated as interface name. */
+ ret = inet_aton (gate_str, &gate);
+ if (ret)
+ ifname = NULL;
+ else
+ ifname = gate_str;
+
+ if (add_cmd)
+ static_ipv4_add (&p, ifname ? NULL : &gate, ifname, distance, table);
+ else
+ static_ipv4_delete (&p, ifname ? NULL : &gate, ifname, distance, table);
+
+ return CMD_SUCCESS;
+}
+
+/* Static route configuration. */
+DEFUN (ip_route,
+ ip_route_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE)",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+{
+ return static_ipv4_func (vty, 1, argv[0], NULL, argv[1], NULL);
+}
+
+DEFUN (ip_route_mask,
+ ip_route_mask_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+{
+ return static_ipv4_func (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (ip_route_pref,
+ ip_route_pref_cmd,
+ "ip route A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+{
+ return static_ipv4_func (vty, 1, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (ip_route_mask_pref,
+ ip_route_mask_pref_cmd,
+ "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+{
+ return static_ipv4_func (vty, 1, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ip_route,
+ no_ip_route_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE)",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+{
+ return static_ipv4_func (vty, 0, argv[0], NULL, argv[1], NULL);
+}
+
+DEFUN (no_ip_route_mask,
+ no_ip_route_mask_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n")
+{
+ return static_ipv4_func (vty, 0, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ip_route_pref,
+ no_ip_route_pref_cmd,
+ "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix (e.g. 10.0.0.0/8)\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+{
+ return static_ipv4_func (vty, 0, argv[0], NULL, argv[1], argv[2]);
+}
+
+DEFUN (no_ip_route_mask_pref,
+ no_ip_route_mask_pref_cmd,
+ "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IP destination prefix\n"
+ "IP destination prefix mask\n"
+ "IP gateway address\n"
+ "IP gateway interface name\n"
+ "Distance value for this route\n")
+{
+ return static_ipv4_func (vty, 0, argv[0], argv[1], argv[2], argv[3]);
+}
+
+/* New RIB. Detailed information for IPv4 route. */
+void
+vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
+{
+ struct rib *rib;
+ struct nexthop *nexthop;
+
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ vty_out (vty, "Routing entry for %s/%d%s",
+ inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+ VTY_NEWLINE);
+ vty_out (vty, " Known via \"%s\"", route_info[rib->type].str);
+ vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ vty_out (vty, ", best");
+ if (rib->refcnt)
+ vty_out (vty, ", refcnt %ld", rib->refcnt);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+ if (rib->type == ZEBRA_ROUTE_RIP
+ || rib->type == ZEBRA_ROUTE_OSPF
+ || rib->type == ZEBRA_ROUTE_ISIS
+ || rib->type == ZEBRA_ROUTE_BGP)
+ {
+ time_t uptime;
+ struct tm *tm;
+
+ uptime = time (NULL);
+ uptime -= rib->uptime;
+ tm = gmtime (&uptime);
+
+ vty_out (vty, " Last update ");
+
+ if (uptime < ONE_DAY_SECOND)
+ vty_out (vty, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out (vty, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, "%02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ vty_out (vty, " ago%s", VTY_NEWLINE);
+ }
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ vty_out (vty, " %c",
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " directly connected, %s",
+ nexthop->ifname);
+ break;
+ default:
+ break;
+ }
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out (vty, " inactive");
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ vty_out (vty, " (recursive");
+
+ switch (nexthop->rtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s)",
+ ifindex2ifname (nexthop->rifindex));
+ break;
+ default:
+ break;
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+}
+
+void
+vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
+{
+ struct nexthop *nexthop;
+ int len = 0;
+ char buf[BUFSIZ];
+
+ /* Nexthop information. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ if (nexthop == rib->nexthop)
+ {
+ /* Prefix information. */
+ len = vty_out (vty, "%c%c%c %s/%d",
+ route_info[rib->type].c,
+ CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+ ? '>' : ' ',
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ),
+ rn->p.prefixlen);
+
+ /* Distance and metric display. */
+ if (rib->type != ZEBRA_ROUTE_CONNECT
+ && rib->type != ZEBRA_ROUTE_KERNEL)
+ len += vty_out (vty, " [%d/%d]", rib->distance,
+ rib->metric);
+ }
+ else
+ vty_out (vty, " %c%*c",
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ len - 3, ' ');
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
+ if (nexthop->ifindex)
+ vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " is directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s",
+ nexthop->ifname);
+ break;
+ default:
+ break;
+ }
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out (vty, " inactive");
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ vty_out (vty, " (recursive");
+
+ switch (nexthop->rtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s)",
+ ifindex2ifname (nexthop->rifindex));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (rib->type == ZEBRA_ROUTE_RIP
+ || rib->type == ZEBRA_ROUTE_OSPF
+ || rib->type == ZEBRA_ROUTE_ISIS
+ || rib->type == ZEBRA_ROUTE_BGP)
+ {
+ time_t uptime;
+ struct tm *tm;
+
+ uptime = time (NULL);
+ uptime -= rib->uptime;
+ tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+ if (uptime < ONE_DAY_SECOND)
+ vty_out (vty, ", %02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out (vty, ", %dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, ", %02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+}
+
+#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s I - IS-IS, %s B - BGP, > - selected route, * - FIB route%s%s"
+
+DEFUN (show_ip_route,
+ show_ip_route_cmd,
+ "show ip route",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n")
+{
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+
+ /* Show all IPv4 routes. */
+ for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix_longer,
+ show_ip_route_prefix_longer_cmd,
+ "show ip route A.B.C.D/M longer-prefixes",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+ "Show route matching the specified Network/Mask pair only\n")
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct prefix p;
+ int ret;
+ int first = 1;
+
+ ret = str2prefix (argv[0], &p);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Show matched type IPv4 routes. */
+ for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (prefix_match (&p, &rn->p))
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_supernets,
+ show_ip_route_supernets_cmd,
+ "show ip route supernets-only",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Show supernet entries only\n")
+{
+ struct route_node *rn;
+ struct rib *rib;
+ u_int32_t addr;
+ int first = 1;
+
+
+ /* Show matched type IPv4 routes. */
+ for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ addr = ntohl (rn->p.u.prefix4.s_addr);
+
+ if ((IN_CLASSC (addr) && rn->p.prefixlen < 24)
+ || (IN_CLASSB (addr) && rn->p.prefixlen < 16)
+ || (IN_CLASSA (addr) && rn->p.prefixlen < 8))
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_ip_route_protocol,
+ show_ip_route_protocol_cmd,
+ "show ip route (bgp|connected|kernel|ospf|isis|rip|static)",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Connected\n"
+ "Kernel\n"
+ "Open Shortest Path First (OSPF)\n"
+ "ISO IS-IS (ISIS)\n"
+ "Routing Information Protocol (RIP)\n"
+ "Static routes\n")
+{
+ int type;
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+
+ if (strncmp (argv[0], "b", 1) == 0)
+ type = ZEBRA_ROUTE_BGP;
+ else if (strncmp (argv[0], "c", 1) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "k", 1) ==0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "o", 1) == 0)
+ type = ZEBRA_ROUTE_OSPF;
+ else if (strncmp (argv[0], "i", 1) == 0)
+ type = ZEBRA_ROUTE_ISIS;
+ else if (strncmp (argv[0], "r", 1) == 0)
+ type = ZEBRA_ROUTE_RIP;
+ else if (strncmp (argv[0], "s", 1) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else
+ {
+ vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Show matched type IPv4 routes. */
+ for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == type)
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
+ VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ip_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_addr,
+ show_ip_route_addr_cmd,
+ "show ip route A.B.C.D",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Network in the IP routing table to display\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "Malformed IPv4 address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rn = route_node_match (rib_table_ipv4, (struct prefix *) &p);
+ if (! rn)
+ {
+ vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_show_ip_route_detail (vty, rn);
+
+ route_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_route_prefix,
+ show_ip_route_prefix_cmd,
+ "show ip route A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+ int ret;
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+
+ ret = str2prefix_ipv4 (argv[0], &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "Malformed IPv4 address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rn = route_node_match (rib_table_ipv4, (struct prefix *) &p);
+ if (! rn || rn->p.prefixlen != p.prefixlen)
+ {
+ vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_show_ip_route_detail (vty, rn);
+
+ route_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+int
+rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
+ struct in6_addr *gate, unsigned int ifindex, int table)
+{
+ if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix))
+ return 1;
+ if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
+ && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
+ {
+ kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
+ return 1;
+ }
+ return 0;
+}
+
+int
+rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+ struct in6_addr *gate, unsigned int ifindex, int table)
+{
+ struct rib *rib;
+ struct rib *same = NULL;
+ struct route_node *rn;
+ struct nexthop *nexthop;
+
+ int distance;
+ u_int32_t metric = 0;
+
+ /* Make sure mask is applied. */
+ apply_mask_ipv6 (p);
+
+ /* Set default distance by route type. */
+ distance = route_info[type].distance;
+
+ if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
+ distance = 200;
+
+ /* Make new rib. */
+ if (!table)
+ table = RT_TABLE_MAIN;
+
+ /* Filter bogus route. */
+ if (rib_bogus_ipv6 (type, p, gate, ifindex, table))
+ return 0;
+
+ /* Lookup route node.*/
+ rn = route_node_get (rib_table_ipv6, (struct prefix *) p);
+
+ /* If same type of route are installed, treat it as a implicit
+ withdraw. */
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (rib->type == ZEBRA_ROUTE_CONNECT)
+ {
+ nexthop = rib->nexthop;
+
+ if (rib->type == type
+ && (! table || rib->table == table)
+ && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+ && nexthop->ifindex == ifindex)
+ {
+ rib->refcnt++;
+ return 0;
+ }
+ }
+ else if (rib->type == type
+ && (! table || (rib->table == table)))
+ {
+ same = rib;
+ rib_delnode (rn, same);
+ route_unlock_node (rn);
+ break;
+ }
+ }
+
+ /* Allocate new rib structure. */
+ rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+ memset (rib, 0, sizeof (struct rib));
+ rib->type = type;
+ rib->distance = distance;
+ rib->flags = flags;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ /* Nexthop settings. */
+ if (gate)
+ {
+ if (ifindex)
+ nexthop_ipv6_ifindex_add (rib, gate, ifindex);
+ else
+ nexthop_ipv6_add (rib, gate);
+ }
+ else
+ nexthop_ifindex_add (rib, ifindex);
+
+ /* If this route is kernel route, set FIB flag to the route. */
+ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
+
+ /* Process this route node. */
+ rib_process (rn, same);
+
+ /* Free implicit route.*/
+ if (same)
+ newrib_free (same);
+
+ return 0;
+}
+
+int
+rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+ struct in6_addr *gate, unsigned int ifindex, int table)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *fib = NULL;
+ struct rib *same = NULL;
+ struct nexthop *nexthop;
+ char buf1[BUFSIZ];
+ char buf2[BUFSIZ];
+
+ /* Apply mask. */
+ apply_mask_ipv6 (p);
+
+ /* Lookup route node. */
+ rn = route_node_lookup (rib_table_ipv6, (struct prefix *) p);
+ if (! rn)
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ if (gate)
+ zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib",
+ inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+ ifindex);
+ else
+ zlog_info ("route %s/%d ifindex %d doesn't exist in rib",
+ inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ ifindex);
+ }
+ return ZEBRA_ERR_RTNOEXIST;
+ }
+
+ /* Lookup same type route. */
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ fib = rib;
+
+ if (rib->type == ZEBRA_ROUTE_CONNECT)
+ {
+ nexthop = rib->nexthop;
+
+ if (rib->type == type
+ && (! table || rib->table == table)
+ && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
+ && nexthop->ifindex == ifindex)
+ {
+ if (rib->refcnt)
+ {
+ rib->refcnt--;
+ route_unlock_node (rn);
+ route_unlock_node (rn);
+ return 0;
+ }
+ same = rib;
+ break;
+ }
+ }
+ else
+ {
+ if (rib->type == type
+ && (! table || rib->table == table))
+ {
+ same = rib;
+ break;
+ }
+ }
+ }
+
+ /* If same type of route can't be found and this message is from
+ kernel. */
+ if (! same)
+ {
+ if (fib && type == ZEBRA_ROUTE_KERNEL)
+ {
+ /* Unset flags. */
+ for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+
+ UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+ }
+ else
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ if (gate)
+ zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
+ inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+ ifindex,
+ type);
+ else
+ zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib",
+ inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ ifindex,
+ type);
+ }
+ route_unlock_node (rn);
+ return ZEBRA_ERR_RTNOEXIST;
+ }
+ }
+
+ if (same)
+ rib_delnode (rn, same);
+
+ /* Process changes. */
+ rib_process (rn, same);
+
+ if (same)
+ {
+ newrib_free (same);
+ route_unlock_node (rn);
+ }
+
+ route_unlock_node (rn);
+
+ return 0;
+}
+
+/* Delete non system routes. */
+void
+rib_close_ipv6 ()
+{
+ struct route_node *rn;
+ struct rib *rib;
+
+ for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (! RIB_SYSTEM_ROUTE (rib)
+ && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ rib_uninstall_kernel (rn, rib);
+}
+
+/* Install static route into rib. */
+void
+static_ipv6_install (struct prefix_ipv6 *p, struct static_ipv6 *si)
+{
+ struct rib *rib;
+ struct route_node *rn;
+
+ /* Lookup existing route */
+ rn = route_node_get (rib_table_ipv6, (struct prefix *) p);
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+ break;
+
+ if (rib)
+ {
+ /* Same distance static route is there. Update it with new
+ nexthop. */
+ rib_uninstall (rn, rib);
+ route_unlock_node (rn);
+
+ switch (si->type)
+ {
+ case STATIC_IPV6_GATEWAY:
+ nexthop_ipv6_add (rib, &si->ipv6);
+ break;
+ case STATIC_IPV6_IFNAME:
+ nexthop_ifname_add (rib, si->ifname);
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+ break;
+ }
+ rib_process (rn, NULL);
+ }
+ else
+ {
+ /* This is new static route. */
+ rib = XMALLOC (MTYPE_RIB, sizeof (struct rib));
+ memset (rib, 0, sizeof (struct rib));
+
+ rib->type = ZEBRA_ROUTE_STATIC;
+ rib->distance = si->distance;
+ rib->metric = 0;
+ rib->nexthop_num = 0;
+
+ switch (si->type)
+ {
+ case STATIC_IPV6_GATEWAY:
+ nexthop_ipv6_add (rib, &si->ipv6);
+ break;
+ case STATIC_IPV6_IFNAME:
+ nexthop_ifname_add (rib, si->ifname);
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+ break;
+ }
+
+ /* Link this rib to the tree. */
+ rib_addnode (rn, rib);
+
+ /* Process this prefix. */
+ rib_process (rn, NULL);
+ }
+}
+
+int
+static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si)
+{
+ if (nexthop->type == NEXTHOP_TYPE_IPV6
+ && si->type == STATIC_IPV6_GATEWAY
+ && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6))
+ return 1;
+ if (nexthop->type == NEXTHOP_TYPE_IFNAME
+ && si->type == STATIC_IPV6_IFNAME
+ && strcmp (nexthop->ifname, si->ifname) == 0)
+ return 1;
+ if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+ && si->type == STATIC_IPV6_GATEWAY_IFNAME
+ && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)
+ && strcmp (nexthop->ifname, si->ifname) == 0)
+ return 1;
+ return 0;;
+}
+
+void
+static_ipv6_uninstall (struct prefix_ipv6 *p, struct static_ipv6 *si)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct nexthop *nexthop;
+
+ /* Lookup existing route with type and distance. */
+ rn = route_node_lookup (rib_table_ipv6, (struct prefix *) p);
+ if (! rn)
+ return;
+
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+ break;
+ if (! rib)
+ {
+ route_unlock_node (rn);
+ return;
+ }
+
+ /* Lookup nexthop. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ if (static_ipv6_nexthop_same (nexthop, si))
+ break;
+
+ /* Can't find nexthop. */
+ if (! nexthop)
+ {
+ route_unlock_node (rn);
+ return;
+ }
+
+ /* Check nexthop. */
+ if (rib->nexthop_num == 1)
+ {
+ rib_delnode (rn, rib);
+ rib_process (rn, rib);
+ newrib_free (rib);
+ route_unlock_node (rn);
+ }
+ else
+ {
+ rib_uninstall (rn, rib);
+ nexthop_delete (rib, nexthop);
+ nexthop_free (nexthop);
+ rib_process (rn, rib);
+ }
+
+ /* Unlock node. */
+ route_unlock_node (rn);
+}
+
+/* Add static route into static route configuration. */
+int
+static_ipv6_add (struct prefix_ipv6 *p, u_char type, struct in6_addr *gate,
+ char *ifname, u_char distance, int table)
+{
+ struct route_node *rn;
+ struct static_ipv6 *si;
+ struct static_ipv6 *pp;
+ struct static_ipv6 *cp;
+
+ /* Lookup static route prefix. */
+ rn = route_node_get (static_table_ipv6, (struct prefix *) p);
+
+ /* Do nothing if there is a same static route. */
+ for (si = rn->info; si; si = si->next)
+ {
+ if (distance == si->distance
+ && type == si->type
+ && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
+ && (! ifname || strcmp (ifname, si->ifname) == 0))
+ {
+ route_unlock_node (rn);
+ return 0;
+ }
+ }
+
+ /* Make new static route structure. */
+ si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
+ memset (si, 0, sizeof (struct static_ipv6));
+
+ si->type = type;
+ si->distance = distance;
+
+ switch (type)
+ {
+ case STATIC_IPV6_GATEWAY:
+ si->ipv6 = *gate;
+ break;
+ case STATIC_IPV6_IFNAME:
+ si->ifname = XSTRDUP (0, ifname);
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ si->ipv6 = *gate;
+ si->ifname = XSTRDUP (0, ifname);
+ break;
+ }
+
+ /* Add new static route information to the tree with sort by
+ distance value and gateway address. */
+ for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+ {
+ if (si->distance < cp->distance)
+ break;
+ if (si->distance > cp->distance)
+ continue;
+ }
+
+ /* Make linked list. */
+ if (pp)
+ pp->next = si;
+ else
+ rn->info = si;
+ if (cp)
+ cp->prev = si;
+ si->prev = pp;
+ si->next = cp;
+
+ /* Install into rib. */
+ static_ipv6_install (p, si);
+
+ return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_ipv6_delete (struct prefix_ipv6 *p, u_char type, struct in6_addr *gate,
+ char *ifname, u_char distance, int table)
+{
+ struct route_node *rn;
+ struct static_ipv6 *si;
+
+ /* Lookup static route prefix. */
+ rn = route_node_lookup (static_table_ipv6, (struct prefix *) p);
+ if (! rn)
+ return 0;
+
+ /* Find same static route is the tree */
+ for (si = rn->info; si; si = si->next)
+ if (distance == si->distance
+ && type == si->type
+ && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
+ && (! ifname || strcmp (ifname, si->ifname) == 0))
+ break;
+
+ /* Can't find static route. */
+ if (! si)
+ {
+ route_unlock_node (rn);
+ return 0;
+ }
+
+ /* Install into rib. */
+ static_ipv6_uninstall (p, si);
+
+ /* Unlink static route from linked list. */
+ if (si->prev)
+ si->prev->next = si->next;
+ else
+ rn->info = si->next;
+ if (si->next)
+ si->next->prev = si->prev;
+
+ /* Free static route configuration. */
+ XFREE (MTYPE_STATIC_IPV6, si);
+
+ return 1;
+}
+
+/* General fucntion for IPv6 static route. */
+int
+static_ipv6_func (struct vty *vty, int add_cmd, char *dest_str,
+ char *gate_str, char *ifname, char *distance_str)
+{
+ int ret;
+ u_char distance;
+ struct prefix_ipv6 p;
+ struct in6_addr *gate = NULL;
+ struct in6_addr gate_addr;
+ u_char type = 0;
+ int table = rtm_table_default;
+
+ ret = str2prefix_ipv6 (dest_str, &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Apply mask for given prefix. */
+ apply_mask_ipv6 (&p);
+
+ /* Administrative distance. */
+ if (distance_str)
+ distance = atoi (distance_str);
+ else
+ distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+
+ /* When gateway is valid IPv6 addrees, then gate is treated as
+ nexthop address other case gate is treated as interface name. */
+ ret = inet_pton (AF_INET6, gate_str, &gate_addr);
+
+ if (ifname)
+ {
+ /* When ifname is specified. It must be come with gateway
+ address. */
+ if (ret != 1)
+ {
+ vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ type = STATIC_IPV6_GATEWAY_IFNAME;
+ gate = &gate_addr;
+ }
+ else
+ {
+ if (ret == 1)
+ {
+ type = STATIC_IPV6_GATEWAY;
+ gate = &gate_addr;
+ }
+ else
+ {
+ type = STATIC_IPV6_IFNAME;
+ ifname = gate_str;
+ }
+ }
+
+ if (add_cmd)
+ static_ipv6_add (&p, type, gate, ifname, distance, table);
+ else
+ static_ipv6_delete (&p, type, gate, ifname, distance, table);
+
+ return CMD_SUCCESS;
+}
+
+/* Write IPv6 static route configuration. */
+int
+static_ipv6_write (struct vty *vty)
+{
+ struct route_node *rn;
+ struct static_ipv6 *si;
+ int write;
+ char buf[BUFSIZ];
+
+ write = 0;
+
+ for (rn = route_top (static_table_ipv6); rn; rn = route_next (rn))
+ for (si = rn->info; si; si = si->next)
+ {
+ vty_out (vty, "ipv6 route %s/%d",
+ inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+ rn->p.prefixlen);
+
+ switch (si->type)
+ {
+ case STATIC_IPV6_GATEWAY:
+ vty_out (vty, " %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ));
+ break;
+ case STATIC_IPV6_IFNAME:
+ vty_out (vty, " %s", si->ifname);
+ break;
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ vty_out (vty, " %s %s",
+ inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname);
+ break;
+ }
+
+ if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
+ vty_out (vty, " %d", si->distance);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ write = 1;
+ }
+ return write;
+}
+
+DEFUN (ipv6_route,
+ ipv6_route_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname,
+ ipv6_route_ifname_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (ipv6_route_pref,
+ ipv6_route_pref_cmd,
+ "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2]);
+}
+
+DEFUN (ipv6_route_ifname_pref,
+ ipv6_route_ifname_pref_cmd,
+ "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_ipv6_route,
+ no_ipv6_route_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL);
+}
+
+DEFUN (no_ipv6_route_ifname,
+ no_ipv6_route_ifname_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_ipv6_route_pref,
+ no_ipv6_route_pref_cmd,
+ "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2]);
+}
+
+DEFUN (no_ipv6_route_ifname_pref,
+ no_ipv6_route_ifname_pref_cmd,
+ "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>",
+ NO_STR
+ IP_STR
+ "Establish static routes\n"
+ "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+ "IPv6 gateway address\n"
+ "IPv6 gateway interface name\n"
+ "Distance value for this prefix\n")
+{
+ return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3]);
+}
+
+/* New RIB. Detailed information for IPv4 route. */
+void
+vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
+{
+ struct rib *rib;
+ struct nexthop *nexthop;
+ char buf[BUFSIZ];
+
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ vty_out (vty, "Routing entry for %s/%d%s",
+ inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+ rn->p.prefixlen,
+ VTY_NEWLINE);
+ vty_out (vty, " Known via \"%s\"", route_info[rib->type].str);
+ vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric);
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ vty_out (vty, ", best");
+ if (rib->refcnt)
+ vty_out (vty, ", refcnt %ld", rib->refcnt);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+ if (rib->type == ZEBRA_ROUTE_RIPNG
+ || rib->type == ZEBRA_ROUTE_OSPF6
+ || rib->type == ZEBRA_ROUTE_ISIS
+ || rib->type == ZEBRA_ROUTE_BGP)
+ {
+ time_t uptime;
+ struct tm *tm;
+
+ uptime = time (NULL);
+ uptime -= rib->uptime;
+ tm = gmtime (&uptime);
+
+ vty_out (vty, " Last update ");
+
+ if (uptime < ONE_DAY_SECOND)
+ vty_out (vty, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out (vty, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, "%02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ vty_out (vty, " ago%s", VTY_NEWLINE);
+ }
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ vty_out (vty, " %c",
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ vty_out (vty, " %s",
+ inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+ if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ vty_out (vty, ", %s", nexthop->ifname);
+ else if (nexthop->ifindex)
+ vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " directly connected, %s",
+ nexthop->ifname);
+ break;
+ default:
+ break;
+ }
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out (vty, " inactive");
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ vty_out (vty, " (recursive");
+
+ switch (nexthop->rtype)
+ {
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ vty_out (vty, " via %s)",
+ inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
+ buf, BUFSIZ));
+ if (nexthop->rifindex)
+ vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s)",
+ ifindex2ifname (nexthop->rifindex));
+ break;
+ default:
+ break;
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+}
+
+void
+vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
+ struct rib *rib)
+{
+ struct nexthop *nexthop;
+ int len = 0;
+ char buf[BUFSIZ];
+
+ /* Nexthop information. */
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ if (nexthop == rib->nexthop)
+ {
+ /* Prefix information. */
+ len = vty_out (vty, "%c%c%c %s/%d",
+ route_info[rib->type].c,
+ CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)
+ ? '>' : ' ',
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+ rn->p.prefixlen);
+
+ /* Distance and metric display. */
+ if (rib->type != ZEBRA_ROUTE_CONNECT
+ && rib->type != ZEBRA_ROUTE_KERNEL)
+ len += vty_out (vty, " [%d/%d]", rib->distance,
+ rib->metric);
+ }
+ else
+ vty_out (vty, " %c%*c",
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ len - 3, ' ');
+
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ vty_out (vty, " via %s",
+ inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
+ if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ vty_out (vty, ", %s", nexthop->ifname);
+ else if (nexthop->ifindex)
+ vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " is directly connected, %s",
+ ifindex2ifname (nexthop->ifindex));
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s",
+ nexthop->ifname);
+ break;
+ default:
+ break;
+ }
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ vty_out (vty, " inactive");
+
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ {
+ vty_out (vty, " (recursive");
+
+ switch (nexthop->rtype)
+ {
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ vty_out (vty, " via %s)",
+ inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
+ buf, BUFSIZ));
+ if (nexthop->rifindex)
+ vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IFNAME:
+ vty_out (vty, " is directly connected, %s)",
+ ifindex2ifname (nexthop->rifindex));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (rib->type == ZEBRA_ROUTE_RIPNG
+ || rib->type == ZEBRA_ROUTE_OSPF6
+ || rib->type == ZEBRA_ROUTE_ISIS
+ || rib->type == ZEBRA_ROUTE_BGP)
+ {
+ time_t uptime;
+ struct tm *tm;
+
+ uptime = time (NULL);
+ uptime -= rib->uptime;
+ tm = gmtime (&uptime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+ if (uptime < ONE_DAY_SECOND)
+ vty_out (vty, ", %02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out (vty, ", %dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, ", %02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+}
+
+#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3, I - IS-IS,%s B - BGP, * - FIB route.%s%s"
+
+DEFUN (show_ipv6_route,
+ show_ipv6_route_cmd,
+ "show ipv6 route",
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n")
+{
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+
+ /* Show all IPv6 route. */
+ for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ipv6_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_prefix_longer,
+ show_ipv6_route_prefix_longer_cmd,
+ "show ipv6 route X:X::X:X/M longer-prefixes",
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n"
+ "IPv6 prefix\n"
+ "Show route matching the specified Network/Mask pair only\n")
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct prefix p;
+ int ret;
+ int first = 1;
+
+ ret = str2prefix (argv[0], &p);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Show matched type IPv6 routes. */
+ for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (prefix_match (&p, &rn->p))
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ipv6_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_protocol,
+ show_ipv6_route_protocol_cmd,
+ "show ipv6 route (bgp|connected|kernel|ospf6|isis|ripng|static)",
+ SHOW_STR
+ IP_STR
+ "IP routing table\n"
+ "Border Gateway Protocol (BGP)\n"
+ "Connected\n"
+ "Kernel\n"
+ "Open Shortest Path First (OSPFv3)\n"
+ "ISO IS-IS (ISIS)\n"
+ "Routing Information Protocol (RIPng)\n"
+ "Static routes\n")
+{
+ int type;
+ struct route_node *rn;
+ struct rib *rib;
+ int first = 1;
+
+ if (strncmp (argv[0], "b", 1) == 0)
+ type = ZEBRA_ROUTE_BGP;
+ else if (strncmp (argv[0], "c", 1) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "k", 1) ==0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "o", 1) == 0)
+ type = ZEBRA_ROUTE_OSPF6;
+ else if (strncmp (argv[0], "i", 1) == 0)
+ type = ZEBRA_ROUTE_ISIS;
+ else if (strncmp (argv[0], "r", 1) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "s", 1) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else
+ {
+ vty_out (vty, "Unknown route type%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Show matched type IPv6 routes. */
+ for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ if (rib->type == type)
+ {
+ if (first)
+ {
+ vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ first = 0;
+ }
+ vty_show_ipv6_route (vty, rn, rib);
+ }
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (show_ipv6_route_addr,
+ show_ipv6_route_addr_cmd,
+ "show ipv6 route X:X::X:X",
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n"
+ "IPv6 Address\n")
+{
+ int ret;
+ struct prefix_ipv6 p;
+ struct route_node *rn;
+
+ ret = str2prefix_ipv6 (argv[0], &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rn = route_node_match (rib_table_ipv6, (struct prefix *) &p);
+ if (! rn)
+ {
+ vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_show_ipv6_route_detail (vty, rn);
+
+ route_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_route_prefix,
+ show_ipv6_route_prefix_cmd,
+ "show ipv6 route X:X::X:X/M",
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n"
+ "IPv6 prefix\n")
+{
+ int ret;
+ struct prefix_ipv6 p;
+ struct route_node *rn;
+
+ ret = str2prefix_ipv6 (argv[0], &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rn = route_node_match (rib_table_ipv6, (struct prefix *) &p);
+ if (! rn || rn->p.prefixlen != p.prefixlen)
+ {
+ vty_out (vty, "%% Network not in table%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_show_ipv6_route_detail (vty, rn);
+
+ route_unlock_node (rn);
+
+ return CMD_SUCCESS;
+}
+#endif /* HAVE_IPV6 */
+
+/* RIB update function. */
+void
+rib_update ()
+{
+ struct route_node *rn;
+
+ for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn))
+ /* Update reachability. */
+ rib_process (rn, NULL);
+
+#ifdef HAVE_IPV6
+ for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn))
+ rib_process (rn, NULL);
+#endif /* HAVE_IPV6 */
+}
+
+/* Interface goes up. */
+void
+rib_if_up (struct interface *ifp)
+{
+ rib_update ();
+}
+
+/* Interface goes down. */
+void
+rib_if_down (struct interface *ifp)
+{
+ rib_update ();
+}
+
+/* Clean up routines. */
+void
+rib_weed_table (struct route_table *rib_table)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *next;
+
+ for (rn = route_top (rib_table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+
+ if (rib->table != rtm_table_default &&
+ rib->table != RT_TABLE_MAIN)
+ {
+ rib_delnode (rn, rib);
+ newrib_free (rib);
+ route_unlock_node (rn);
+ }
+ }
+}
+
+/* Delete all routes from unmanaged tables. */
+void
+rib_weed_tables ()
+{
+ rib_weed_table (rib_table_ipv4);
+#ifdef HAVE_IPV6
+ rib_weed_table (rib_table_ipv6);
+#endif /* HAVE_IPV6 */
+}
+
+void
+rib_sweep_table (struct route_table *rib_table)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *next;
+ int ret = 0;
+
+ for (rn = route_top (rib_table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+
+ if ((rib->type == ZEBRA_ROUTE_KERNEL) &&
+ CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE))
+ {
+ ret = rib_uninstall_kernel (rn, rib);
+
+ if (! ret)
+ {
+ rib_delnode (rn, rib);
+ newrib_free (rib);
+ route_unlock_node (rn);
+ }
+ }
+ }
+}
+
+void
+rib_sweep_route ()
+{
+ rib_sweep_table (rib_table_ipv4);
+#ifdef HAVE_IPV6
+ rib_sweep_table (rib_table_ipv6);
+#endif /* HAVE_IPV6 */
+}
+
+/* Close rib when zebra terminates. */
+void
+rib_close ()
+{
+ rib_close_ipv4 ();
+#ifdef HAVE_IPV6
+ rib_close_ipv6 ();
+#endif /* HAVE_IPV6 */
+}
+
+/* Static ip route configuration write function. */
+int
+config_write_ip (struct vty *vty)
+{
+ int write = 0;
+
+ write += static_ipv4_write (vty);
+#ifdef HAVE_IPV6
+ write += static_ipv6_write (vty);
+#endif /* HAVE_IPV6 */
+
+ return write;
+}
+
+/* IP node for static routes. */
+struct cmd_node ip_node =
+{
+ IP_NODE,
+ "", /* This node has no interface. */
+ 1
+};
+
+/* Routing information base initialize. */
+void
+rib_init ()
+{
+ install_node (&ip_node, config_write_ip);
+
+ rib_table_ipv4 = route_table_init ();
+ static_table_ipv4 = route_table_init ();
+
+ install_element (VIEW_NODE, &show_ip_route_cmd);
+ install_element (VIEW_NODE, &show_ip_route_addr_cmd);
+ install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
+ install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
+ install_element (VIEW_NODE, &show_ip_route_protocol_cmd);
+ install_element (VIEW_NODE, &show_ip_route_supernets_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_protocol_cmd);
+ install_element (ENABLE_NODE, &show_ip_route_supernets_cmd);
+ install_element (CONFIG_NODE, &ip_route_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_cmd);
+ install_element (CONFIG_NODE, &ip_route_pref_cmd);
+ install_element (CONFIG_NODE, &ip_route_mask_pref_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_pref_cmd);
+ install_element (CONFIG_NODE, &no_ip_route_mask_pref_cmd);
+
+#ifdef HAVE_IPV6
+ rib_table_ipv6 = route_table_init ();
+ static_table_ipv6 = route_table_init ();
+
+ install_element (CONFIG_NODE, &ipv6_route_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_pref_cmd);
+ install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_addr_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd);
+#endif /* HAVE_IPV6 */
+}
diff --git a/isisd/modified/thread.c b/isisd/modified/thread.c
new file mode 100644
index 00000000..af954b83
--- /dev/null
+++ b/isisd/modified/thread.c
@@ -0,0 +1,713 @@
+/* Thread management routine
+ * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/* #define DEBUG */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+
+/* Struct timeval's tv_usec one second value. */
+#define TIMER_SECOND_MICRO 1000000L
+
+struct timeval
+timeval_adjust (struct timeval a)
+{
+ while (a.tv_usec >= TIMER_SECOND_MICRO)
+ {
+ a.tv_usec -= TIMER_SECOND_MICRO;
+ a.tv_sec++;
+ }
+
+ while (a.tv_usec < 0)
+ {
+ a.tv_usec += TIMER_SECOND_MICRO;
+ a.tv_sec--;
+ }
+
+ if (a.tv_sec < 0)
+ {
+ a.tv_sec = 0;
+ a.tv_usec = 10;
+ }
+
+ if (a.tv_sec > TIMER_SECOND_MICRO)
+ a.tv_sec = TIMER_SECOND_MICRO;
+
+ return a;
+}
+
+static struct timeval
+timeval_subtract (struct timeval a, struct timeval b)
+{
+ struct timeval ret;
+
+ ret.tv_usec = a.tv_usec - b.tv_usec;
+ ret.tv_sec = a.tv_sec - b.tv_sec;
+
+ return timeval_adjust (ret);
+}
+
+static int
+timeval_cmp (struct timeval a, struct timeval b)
+{
+ return (a.tv_sec == b.tv_sec
+ ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
+}
+
+static unsigned long
+timeval_elapsed (struct timeval a, struct timeval b)
+{
+ return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+ + (a.tv_usec - b.tv_usec));
+}
+
+/* List allocation and head/tail print out. */
+static void
+thread_list_debug (struct thread_list *list)
+{
+ printf ("count [%d] head [%p] tail [%p]\n",
+ list->count, list->head, list->tail);
+}
+
+/* Debug print for thread_master. */
+void
+thread_master_debug (struct thread_master *m)
+{
+ printf ("-----------\n");
+ printf ("readlist : ");
+ thread_list_debug (&m->read);
+ printf ("writelist : ");
+ thread_list_debug (&m->write);
+ printf ("timerlist : ");
+ thread_list_debug (&m->timer);
+ printf ("eventlist : ");
+ thread_list_debug (&m->event);
+ printf ("unuselist : ");
+ thread_list_debug (&m->unuse);
+ printf ("total alloc: [%ld]\n", m->alloc);
+ printf ("-----------\n");
+}
+
+/* Allocate new thread master. */
+struct thread_master *
+thread_master_create ()
+{
+ return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
+ sizeof (struct thread_master));
+}
+
+/* Add a new thread to the list. */
+static void
+thread_list_add (struct thread_list *list, struct thread *thread)
+{
+ thread->next = NULL;
+ thread->prev = list->tail;
+ if (list->tail)
+ list->tail->next = thread;
+ else
+ list->head = thread;
+ list->tail = thread;
+ list->count++;
+}
+
+/* Add a new thread just before the point. */
+static void
+thread_list_add_before (struct thread_list *list,
+ struct thread *point,
+ struct thread *thread)
+{
+ thread->next = point;
+ thread->prev = point->prev;
+ if (point->prev)
+ point->prev->next = thread;
+ else
+ list->head = thread;
+ point->prev = thread;
+ list->count++;
+}
+
+/* Delete a thread from the list. */
+static struct thread *
+thread_list_delete (struct thread_list *list, struct thread *thread)
+{
+ if (thread->next)
+ thread->next->prev = thread->prev;
+ else
+ list->tail = thread->prev;
+ if (thread->prev)
+ thread->prev->next = thread->next;
+ else
+ list->head = thread->next;
+ thread->next = thread->prev = NULL;
+ list->count--;
+ return thread;
+}
+
+/* Move thread to unuse list. */
+static void
+thread_add_unuse (struct thread_master *m, struct thread *thread)
+{
+ assert (m != NULL);
+ assert (thread->next == NULL);
+ assert (thread->prev == NULL);
+ assert (thread->type == THREAD_UNUSED);
+ thread_list_add (&m->unuse, thread);
+}
+
+/* Free all unused thread. */
+static void
+thread_list_free (struct thread_master *m, struct thread_list *list)
+{
+ struct thread *t;
+ struct thread *next;
+
+ for (t = list->head; t; t = next)
+ {
+ next = t->next;
+ XFREE (MTYPE_THREAD, t);
+ list->count--;
+ m->alloc--;
+ }
+}
+
+/* Stop thread scheduler. */
+void
+thread_master_free (struct thread_master *m)
+{
+ thread_list_free (m, &m->read);
+ thread_list_free (m, &m->write);
+ thread_list_free (m, &m->timer);
+ thread_list_free (m, &m->event);
+ thread_list_free (m, &m->ready);
+ thread_list_free (m, &m->unuse);
+
+ XFREE (MTYPE_THREAD_MASTER, m);
+}
+
+/* Delete top of the list and return it. */
+static struct thread *
+thread_trim_head (struct thread_list *list)
+{
+ if (list->head)
+ return thread_list_delete (list, list->head);
+ return NULL;
+}
+
+/* Thread list is empty or not. */
+int
+thread_empty (struct thread_list *list)
+{
+ return list->head ? 0 : 1;
+}
+
+/* Return remain time in second. */
+unsigned long
+thread_timer_remain_second (struct thread *thread)
+{
+ struct timeval timer_now;
+
+ gettimeofday (&timer_now, NULL);
+
+ if (thread->u.sands.tv_sec - timer_now.tv_sec > 0)
+ return thread->u.sands.tv_sec - timer_now.tv_sec;
+ else
+ return 0;
+}
+
+/* Get new thread. */
+static struct thread *
+thread_get (struct thread_master *m, u_char type,
+ int (*func) (struct thread *), void *arg)
+{
+ struct thread *thread;
+
+ if (m->unuse.head)
+ thread = thread_trim_head (&m->unuse);
+ else
+ {
+ thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
+ m->alloc++;
+ }
+ thread->type = type;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
+
+ return thread;
+}
+
+/* Add new read thread. */
+struct thread *
+thread_add_read (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, int fd)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ if (FD_ISSET (fd, &m->readfd))
+ {
+ zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
+ return NULL;
+ }
+
+ thread = thread_get (m, THREAD_READ, func, arg);
+ FD_SET (fd, &m->readfd);
+ thread->u.fd = fd;
+ thread_list_add (&m->read, thread);
+
+ return thread;
+}
+
+/* Add new write thread. */
+struct thread *
+thread_add_write (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, int fd)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ if (FD_ISSET (fd, &m->writefd))
+ {
+ zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
+ return NULL;
+ }
+
+ thread = thread_get (m, THREAD_WRITE, func, arg);
+ FD_SET (fd, &m->writefd);
+ thread->u.fd = fd;
+ thread_list_add (&m->write, thread);
+
+ return thread;
+}
+
+/* Add timer event thread. */
+struct thread *
+thread_add_timer (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, long timer)
+{
+ struct timeval timer_now;
+ struct thread *thread;
+#ifndef TIMER_NO_SORT
+ struct thread *tt;
+#endif /* TIMER_NO_SORT */
+
+ assert (m != NULL);
+
+ thread = thread_get (m, THREAD_TIMER, func, arg);
+
+ /* Do we need jitter here? */
+ gettimeofday (&timer_now, NULL);
+ timer_now.tv_sec += timer;
+ thread->u.sands = timer_now;
+
+ /* Sort by timeval. */
+#ifdef TIMER_NO_SORT
+ thread_list_add (&m->timer, thread);
+#else
+ for (tt = m->timer.head; tt; tt = tt->next)
+ if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
+ break;
+
+ if (tt)
+ thread_list_add_before (&m->timer, tt, thread);
+ else
+ thread_list_add (&m->timer, thread);
+#endif /* TIMER_NO_SORT */
+
+ return thread;
+}
+
+/* Add timer event thread with "millisecond" resolution */
+struct thread *
+thread_add_timer_msec (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg, long timer)
+{
+ struct timeval timer_now;
+ struct thread *thread;
+#ifndef TIMER_NO_SORT
+ struct thread *tt;
+#endif /* TIMER_NO_SORT */
+
+ assert (m != NULL);
+
+ thread = thread_get (m, THREAD_TIMER, func, arg);
+
+ timer = 1000*timer; /* milli -> micro */
+
+ gettimeofday (&timer_now, NULL);
+ timer_now.tv_sec += timer / TIMER_SECOND_MICRO;
+ timer_now.tv_usec += (timer % TIMER_SECOND_MICRO);
+ thread->u.sands = timer_now;
+
+
+ /* Sort by timeval. */
+#ifdef TIMER_NO_SORT
+ thread_list_add (&m->timer, thread);
+#else
+ for (tt = m->timer.head; tt; tt = tt->next)
+ if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
+ break;
+
+ if (tt)
+ thread_list_add_before (&m->timer, tt, thread);
+ else
+ thread_list_add (&m->timer, thread);
+#endif /* TIMER_NO_SORT */
+
+ return thread;
+}
+
+
+/* Add simple event thread. */
+struct thread *
+thread_add_event (struct thread_master *m,
+ int (*func) (struct thread *), void *arg, int val)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ thread = thread_get (m, THREAD_EVENT, func, arg);
+ thread->u.val = val;
+ thread_list_add (&m->event, thread);
+
+ return thread;
+}
+
+/* Cancel thread from scheduler. */
+void
+thread_cancel (struct thread *thread)
+{
+ switch (thread->type)
+ {
+ case THREAD_READ:
+ assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
+ FD_CLR (thread->u.fd, &thread->master->readfd);
+ thread_list_delete (&thread->master->read, thread);
+ break;
+ case THREAD_WRITE:
+ assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
+ FD_CLR (thread->u.fd, &thread->master->writefd);
+ thread_list_delete (&thread->master->write, thread);
+ break;
+ case THREAD_TIMER:
+ thread_list_delete (&thread->master->timer, thread);
+ break;
+ case THREAD_EVENT:
+ thread_list_delete (&thread->master->event, thread);
+ break;
+ case THREAD_READY:
+ thread_list_delete (&thread->master->ready, thread);
+ break;
+ case THREAD_UNUSED:
+ thread_list_delete (&thread->master->unuse, thread);
+ break;
+ default:
+ break;
+ }
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (thread->master, thread);
+}
+
+/* Delete all events which has argument value arg. */
+void
+thread_cancel_event (struct thread_master *m, void *arg)
+{
+ struct thread *thread;
+
+ thread = m->event.head;
+ while (thread)
+ {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ if (t->arg == arg)
+ {
+ thread_list_delete (&m->event, t);
+ t->type = THREAD_UNUSED;
+ thread_add_unuse (m, t);
+ }
+ }
+}
+
+#ifdef TIMER_NO_SORT
+struct timeval *
+thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
+{
+ struct timeval timer_now;
+ struct timeval timer_min;
+ struct timeval *timer_wait;
+
+ gettimeofday (&timer_now, NULL);
+
+ timer_wait = NULL;
+ for (thread = m->timer.head; thread; thread = thread->next)
+ {
+ if (! timer_wait)
+ timer_wait = &thread->u.sands;
+ else if (timeval_cmp (thread->u.sands, *timer_wait) < 0)
+ timer_wait = &thread->u.sands;
+ }
+
+ if (m->timer.head)
+ {
+ timer_min = *timer_wait;
+ timer_min = timeval_subtract (timer_min, timer_now);
+ if (timer_min.tv_sec < 0)
+ {
+ timer_min.tv_sec = 0;
+ timer_min.tv_usec = 10;
+ }
+ timer_wait = &timer_min;
+ }
+ else
+ timer_wait = NULL;
+
+ if (timer_wait)
+ {
+ *timer_val = timer_wait;
+ return timer_val;
+ }
+ return NULL;
+}
+#else /* ! TIMER_NO_SORT */
+struct timeval *
+thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
+{
+ struct timeval timer_now;
+ struct timeval timer_min;
+
+ if (m->timer.head)
+ {
+ gettimeofday (&timer_now, NULL);
+ timer_min = m->timer.head->u.sands;
+ timer_min = timeval_subtract (timer_min, timer_now);
+ if (timer_min.tv_sec < 0)
+ {
+ timer_min.tv_sec = 0;
+ timer_min.tv_usec = 10;
+ }
+ *timer_val = timer_min;
+ return timer_val;
+ }
+ return NULL;
+}
+#endif /* TIMER_NO_SORT */
+
+struct thread *
+thread_run (struct thread_master *m, struct thread *thread,
+ struct thread *fetch)
+{
+ *fetch = *thread;
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (m, thread);
+ return fetch;
+}
+
+int
+thread_process_fd (struct thread_master *m, struct thread_list *list,
+ fd_set *fdset, fd_set *mfdset)
+{
+ struct thread *thread;
+ struct thread *next;
+ int ready = 0;
+
+ for (thread = list->head; thread; thread = next)
+ {
+ next = thread->next;
+
+ if (FD_ISSET (THREAD_FD (thread), fdset))
+ {
+ assert (FD_ISSET (THREAD_FD (thread), mfdset));
+ FD_CLR(THREAD_FD (thread), mfdset);
+ thread_list_delete (list, thread);
+ thread_list_add (&m->ready, thread);
+ thread->type = THREAD_READY;
+ ready++;
+ }
+ }
+ return ready;
+}
+
+/* Fetch next ready thread. */
+struct thread *
+thread_fetch (struct thread_master *m, struct thread *fetch)
+{
+ int num;
+ int ready;
+ struct thread *thread;
+ fd_set readfd;
+ fd_set writefd;
+ fd_set exceptfd;
+ struct timeval timer_now;
+ struct timeval timer_val;
+ struct timeval *timer_wait;
+ struct timeval timer_nowait;
+
+ timer_nowait.tv_sec = 0;
+ timer_nowait.tv_usec = 0;
+
+ while (1)
+ {
+ /* Normal event is the highest priority. */
+ if ((thread = thread_trim_head (&m->event)) != NULL)
+ return thread_run (m, thread, fetch);
+
+ /* Execute timer. */
+ gettimeofday (&timer_now, NULL);
+
+ for (thread = m->timer.head; thread; thread = thread->next)
+ if (timeval_cmp (timer_now, thread->u.sands) >= 0)
+ {
+ thread_list_delete (&m->timer, thread);
+ return thread_run (m, thread, fetch);
+ }
+
+ /* If there are any ready threads, process top of them. */
+ if ((thread = thread_trim_head (&m->ready)) != NULL)
+ return thread_run (m, thread, fetch);
+
+ /* Structure copy. */
+ readfd = m->readfd;
+ writefd = m->writefd;
+ exceptfd = m->exceptfd;
+
+ /* Calculate select wait timer. */
+ timer_wait = thread_timer_wait (m, &timer_val);
+
+ num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
+
+ if (num == 0)
+ continue;
+
+ if (num < 0)
+ {
+ if (errno == EINTR)
+ continue;
+
+ zlog_warn ("select() error: %s", strerror (errno));
+ return NULL;
+ }
+
+ /* Normal priority read thead. */
+ ready = thread_process_fd (m, &m->read, &readfd, &m->readfd);
+
+ /* Write thead. */
+ ready = thread_process_fd (m, &m->write, &writefd, &m->writefd);
+
+ if ((thread = thread_trim_head (&m->ready)) != NULL)
+ return thread_run (m, thread, fetch);
+ }
+}
+
+static unsigned long
+thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start)
+{
+ unsigned long thread_time;
+
+#ifdef HAVE_RUSAGE
+ /* This is 'user + sys' time. */
+ thread_time = timeval_elapsed (now->ru_utime, start->ru_utime);
+ thread_time += timeval_elapsed (now->ru_stime, start->ru_stime);
+#else
+ /* When rusage is not available, simple elapsed time is used. */
+ thread_time = timeval_elapsed (*now, *start);
+#endif /* HAVE_RUSAGE */
+
+ return thread_time;
+}
+
+/* We should aim to yield after THREAD_YIELD_TIME_SLOT
+ milliseconds. */
+int
+thread_should_yield (struct thread *thread)
+{
+ RUSAGE_T ru;
+
+ GETRUSAGE (&ru);
+
+ if (thread_consumed_time (&ru, &thread->ru) > THREAD_YIELD_TIME_SLOT)
+ return 1;
+ else
+ return 0;
+}
+
+/* We check thread consumed time. If the system has getrusage, we'll
+ use that to get indepth stats on the performance of the thread. If
+ not - we'll use gettimeofday for some guestimation. */
+void
+thread_call (struct thread *thread)
+{
+ unsigned long thread_time;
+ RUSAGE_T ru;
+
+ GETRUSAGE (&thread->ru);
+
+ (*thread->func) (thread);
+
+ GETRUSAGE (&ru);
+
+ thread_time = thread_consumed_time (&ru, &thread->ru);
+
+#ifdef THREAD_CONSUMED_TIME_CHECK
+ if (thread_time > 200000L)
+ {
+ /*
+ * We have a CPU Hog on our hands.
+ * Whinge about it now, so we're aware this is yet another task
+ * to fix.
+ */
+ zlog_err ("CPU HOG task %lx ran for %ldms",
+ /* FIXME: report the name of the function somehow */
+ (unsigned long) thread->func,
+ thread_time / 1000L);
+ }
+#endif /* THREAD_CONSUMED_TIME_CHECK */
+}
+
+/* Execute thread */
+struct thread *
+thread_execute (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int val)
+{
+ struct thread dummy;
+
+ memset (&dummy, 0, sizeof (struct thread));
+
+ dummy.type = THREAD_EVENT;
+ dummy.master = NULL;
+ dummy.func = func;
+ dummy.arg = arg;
+ dummy.u.val = val;
+ thread_call (&dummy);
+
+ return NULL;
+}
diff --git a/isisd/modified/thread.h b/isisd/modified/thread.h
new file mode 100644
index 00000000..c3fac435
--- /dev/null
+++ b/isisd/modified/thread.h
@@ -0,0 +1,141 @@
+/* Thread management routine header.
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_THREAD_H
+#define _ZEBRA_THREAD_H
+
+#ifdef HAVE_RUSAGE
+#define RUSAGE_T struct rusage
+#define GETRUSAGE(X) getrusage (RUSAGE_SELF, X);
+#else
+#define RUSAGE_T struct timeval
+#define GETRUSAGE(X) gettimeofday (X, NULL);
+#endif /* HAVE_RUSAGE */
+
+/* Linked list of thread. */
+struct thread_list
+{
+ struct thread *head;
+ struct thread *tail;
+ int count;
+};
+
+/* Master of the theads. */
+struct thread_master
+{
+ struct thread_list read;
+ struct thread_list write;
+ struct thread_list timer;
+ struct thread_list event;
+ struct thread_list ready;
+ struct thread_list unuse;
+ fd_set readfd;
+ fd_set writefd;
+ fd_set exceptfd;
+ unsigned long alloc;
+};
+
+/* Thread itself. */
+struct thread
+{
+ unsigned char type; /* thread type */
+ struct thread *next; /* next pointer of the thread */
+ struct thread *prev; /* previous pointer of the thread */
+ struct thread_master *master; /* pointer to the struct thread_master. */
+ int (*func) (struct thread *); /* event function */
+ void *arg; /* event argument */
+ union {
+ int val; /* second argument of the event. */
+ int fd; /* file descriptor in case of read/write. */
+ struct timeval sands; /* rest of time sands value. */
+ } u;
+ RUSAGE_T ru; /* Indepth usage info. */
+};
+
+/* Thread types. */
+#define THREAD_READ 0
+#define THREAD_WRITE 1
+#define THREAD_TIMER 2
+#define THREAD_EVENT 3
+#define THREAD_READY 4
+#define THREAD_UNUSED 5
+
+/* Thread yield time. */
+#define THREAD_YIELD_TIME_SLOT 100 * 1000L /* 100ms */
+
+/* Macros. */
+#define THREAD_ARG(X) ((X)->arg)
+#define THREAD_FD(X) ((X)->u.fd)
+#define THREAD_VAL(X) ((X)->u.val)
+
+#define THREAD_READ_ON(master,thread,func,arg,sock) \
+ do { \
+ if (! thread) \
+ thread = thread_add_read (master, func, arg, sock); \
+ } while (0)
+
+#define THREAD_WRITE_ON(master,thread,func,arg,sock) \
+ do { \
+ if (! thread) \
+ thread = thread_add_write (master, func, arg, sock); \
+ } while (0)
+
+#define THREAD_TIMER_ON(master,thread,func,arg,time) \
+ do { \
+ if (! thread) \
+ thread = thread_add_timer (master, func, arg, time); \
+ } while (0)
+
+#define THREAD_OFF(thread) \
+ do { \
+ if (thread) \
+ { \
+ thread_cancel (thread); \
+ thread = NULL; \
+ } \
+ } while (0)
+
+#define THREAD_READ_OFF(thread) THREAD_OFF(thread)
+#define THREAD_WRITE_OFF(thread) THREAD_OFF(thread)
+#define THREAD_TIMER_OFF(thread) THREAD_OFF(thread)
+
+/* Prototypes. */
+struct thread_master *thread_master_create ();
+struct thread *thread_add_read (struct thread_master *,
+ int (*)(struct thread *), void *, int);
+struct thread *thread_add_write (struct thread_master *,
+ int (*)(struct thread *), void *, int);
+struct thread *thread_add_timer (struct thread_master *,
+ int (*)(struct thread *), void *, long);
+struct thread *thread_add_timer_msec (struct thread_master *,
+ int (*)(struct thread *), void *, long);
+struct thread *thread_add_event (struct thread_master *,
+ int (*)(struct thread *), void *, int );
+void thread_cancel (struct thread *);
+void thread_cancel_event (struct thread_master *, void *);
+
+struct thread *thread_fetch (struct thread_master *, struct thread *);
+struct thread *thread_execute (struct thread_master *,
+ int (*)(struct thread *), void *, int);
+void thread_call (struct thread *);
+unsigned long thread_timer_remain_second (struct thread *);
+
+#endif /* _ZEBRA_THREAD_H */
diff --git a/isisd/modified/vty.c b/isisd/modified/vty.c
new file mode 100644
index 00000000..6de0e0da
--- /dev/null
+++ b/isisd/modified/vty.c
@@ -0,0 +1,2786 @@
+/*
+ * Virtual terminal [aka TeletYpe] interface routine.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "buffer.h"
+#include "version.h"
+#include "command.h"
+#include "sockunion.h"
+#include "thread.h"
+#include "memory.h"
+#include "str.h"
+#include "log.h"
+#include "prefix.h"
+#include "filter.h"
+
+/* Vty events */
+enum event
+{
+ VTY_SERV,
+ VTY_READ,
+ VTY_WRITE,
+ VTY_TIMEOUT_RESET,
+#ifdef VTYSH
+ VTYSH_SERV,
+ VTYSH_READ
+#endif /* VTYSH */
+};
+
+static void vty_event (enum event, int, struct vty *);
+
+/* Extern host structure from command.c */
+extern struct host host;
+
+/* Vector which store each vty structure. */
+static vector vtyvec;
+
+/* Vty timeout value. */
+static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+/* Vty access-class command */
+static char *vty_accesslist_name = NULL;
+
+/* Vty access-calss for IPv6. */
+static char *vty_ipv6_accesslist_name = NULL;
+
+/* VTY server thread. */
+vector Vvty_serv_thread;
+
+/* Current directory. */
+char *vty_cwd = NULL;
+
+/* Configure lock. */
+static int vty_config;
+
+/* Login password check. */
+static int no_password_check = 0;
+
+/* Integrated configuration file path */
+char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
+
+
+/* VTY standard output function. */
+int
+vty_out (struct vty *vty, const char *format, ...)
+{
+ va_list args;
+ int len = 0;
+ int size = 1024;
+ char buf[1024];
+ char *p = NULL;
+
+ va_start (args, format);
+
+ if (vty_shell (vty))
+ vprintf (format, args);
+ else
+ {
+ /* Try to write to initial buffer. */
+ len = vsnprintf (buf, sizeof buf, format, args);
+
+ /* Initial buffer is not enough. */
+ if (len < 0 || len >= size)
+ {
+ while (1)
+ {
+ if (len > -1)
+ size = len + 1;
+ else
+ size = size * 2;
+
+ p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
+ if (! p)
+ return -1;
+
+ len = vsnprintf (p, size, format, args);
+
+ if (len > -1 && len < size)
+ break;
+ }
+ }
+
+ /* When initial buffer is enough to store all output. */
+ if (! p)
+ p = buf;
+
+ /* Pointer p must point out buffer. */
+ if (vty_shell_serv (vty))
+ write (vty->fd, (u_char *) p, len);
+ else
+ buffer_write (vty->obuf, (u_char *) p, len);
+
+ /* If p is not different with buf, it is allocated buffer. */
+ if (p != buf)
+ XFREE (MTYPE_VTY_OUT_BUF, p);
+ }
+
+ va_end (args);
+
+ return len;
+}
+
+int
+vty_log_out (struct vty *vty, const char *proto_str, const char *format,
+ va_list va)
+{
+ int len;
+ char buf[1024];
+
+ snprintf (buf, sizeof buf, "%s: ", proto_str);
+ write (vty->fd, buf, strlen (proto_str) + 2);
+
+ len = vsnprintf (buf, sizeof buf, format, va);
+ if (len < 0)
+ return -1;
+ write (vty->fd, (u_char *)buf, len);
+
+ snprintf (buf, sizeof buf, "\r\n");
+ write (vty->fd, buf, 2);
+
+ return len;
+}
+
+/* Output current time to the vty. */
+void
+vty_time_print (struct vty *vty, int cr)
+{
+ time_t clock;
+ struct tm *tm;
+#define TIME_BUF 25
+ char buf [TIME_BUF];
+ int ret;
+
+ time (&clock);
+ tm = localtime (&clock);
+
+ ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
+ if (ret == 0)
+ {
+ zlog (NULL, LOG_INFO, "strftime error");
+ return;
+ }
+ if (cr)
+ vty_out (vty, "%s\n", buf);
+ else
+ vty_out (vty, "%s ", buf);
+
+ return;
+}
+
+/* Say hello to vty interface. */
+void
+vty_hello (struct vty *vty)
+{
+ if (host.motd)
+ vty_out (vty, host.motd);
+}
+
+/* Put out prompt and wait input from user. */
+static void
+vty_prompt (struct vty *vty)
+{
+ struct utsname names;
+ const char*hostname;
+
+ if (vty->type == VTY_TERM)
+ {
+ hostname = host.name;
+ if (!hostname)
+ {
+ uname (&names);
+ hostname = names.nodename;
+ }
+ vty_out (vty, cmd_prompt (vty->node), hostname);
+ }
+}
+
+/* Send WILL TELOPT_ECHO to remote server. */
+void
+vty_will_echo (struct vty *vty)
+{
+ char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+/* Make suppress Go-Ahead telnet option. */
+static void
+vty_will_suppress_go_ahead (struct vty *vty)
+{
+ char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+/* Make don't use linemode over telnet. */
+static void
+vty_dont_linemode (struct vty *vty)
+{
+ char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+/* Use window size. */
+static void
+vty_do_window_size (struct vty *vty)
+{
+ char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+
+#if 0 /* Currently not used. */
+/* Make don't use lflow vty interface. */
+static void
+vty_dont_lflow_ahead (struct vty *vty)
+{
+ char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
+ vty_out (vty, "%s", cmd);
+}
+#endif /* 0 */
+
+/* Allocate new vty struct. */
+struct vty *
+vty_new ()
+{
+ struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
+
+ new->obuf = (struct buffer *) buffer_new (100);
+ new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
+ new->max = VTY_BUFSIZ;
+ new->sb_buffer = NULL;
+
+ return new;
+}
+
+/* Authentication of vty */
+static void
+vty_auth (struct vty *vty, char *buf)
+{
+ char *passwd = NULL;
+ enum node_type next_node = 0;
+ int fail;
+ char *crypt (const char *, const char *);
+
+ switch (vty->node)
+ {
+ case AUTH_NODE:
+ if (host.encrypt)
+ passwd = host.password_encrypt;
+ else
+ passwd = host.password;
+ if (host.advanced)
+ next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
+ else
+ next_node = VIEW_NODE;
+ break;
+ case AUTH_ENABLE_NODE:
+ if (host.encrypt)
+ passwd = host.enable_encrypt;
+ else
+ passwd = host.enable;
+ next_node = ENABLE_NODE;
+ break;
+ }
+
+ if (passwd)
+ {
+ if (host.encrypt)
+ fail = strcmp (crypt(buf, passwd), passwd);
+ else
+ fail = strcmp (buf, passwd);
+ }
+ else
+ fail = 1;
+
+ if (! fail)
+ {
+ vty->fail = 0;
+ vty->node = next_node; /* Success ! */
+ }
+ else
+ {
+ vty->fail++;
+ if (vty->fail >= 3)
+ {
+ if (vty->node == AUTH_NODE)
+ {
+ vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
+ vty->status = VTY_CLOSE;
+ }
+ else
+ {
+ /* AUTH_ENABLE_NODE */
+ vty->fail = 0;
+ vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
+ vty->node = VIEW_NODE;
+ }
+ }
+ }
+}
+
+/* Command execution over the vty interface. */
+int
+vty_command (struct vty *vty, char *buf)
+{
+ int ret;
+ vector vline;
+
+ /* Split readline string up into the vector */
+ vline = cmd_make_strvec (buf);
+
+ if (vline == NULL)
+ return CMD_SUCCESS;
+
+ ret = cmd_execute_command (vline, vty, NULL);
+
+ if (ret != CMD_SUCCESS)
+ switch (ret)
+ {
+ case CMD_WARNING:
+ if (vty->type == VTY_FILE)
+ vty_out (vty, "Warning...%s", VTY_NEWLINE);
+ break;
+ case CMD_ERR_AMBIGUOUS:
+ vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ break;
+ case CMD_ERR_NO_MATCH:
+ vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
+ break;
+ case CMD_ERR_INCOMPLETE:
+ vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
+ break;
+ }
+ cmd_free_strvec (vline);
+
+ return ret;
+}
+
+char telnet_backward_char = 0x08;
+char telnet_space_char = ' ';
+
+/* Basic function to write buffer to vty. */
+static void
+vty_write (struct vty *vty, char *buf, size_t nbytes)
+{
+ if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+ return;
+
+ /* Should we do buffering here ? And make vty_flush (vty) ? */
+ buffer_write (vty->obuf, (u_char *)buf, nbytes);
+}
+
+/* Ensure length of input buffer. Is buffer is short, double it. */
+static void
+vty_ensure (struct vty *vty, int length)
+{
+ if (vty->max <= length)
+ {
+ vty->max *= 2;
+ vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
+ }
+}
+
+/* Basic function to insert character into vty. */
+static void
+vty_self_insert (struct vty *vty, char c)
+{
+ int i;
+ int length;
+
+ vty_ensure (vty, vty->length + 1);
+ length = vty->length - vty->cp;
+ memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
+ vty->buf[vty->cp] = c;
+
+ vty_write (vty, &vty->buf[vty->cp], length + 1);
+ for (i = 0; i < length; i++)
+ vty_write (vty, &telnet_backward_char, 1);
+
+ vty->cp++;
+ vty->length++;
+}
+
+/* Self insert character 'c' in overwrite mode. */
+static void
+vty_self_insert_overwrite (struct vty *vty, char c)
+{
+ vty_ensure (vty, vty->length + 1);
+ vty->buf[vty->cp++] = c;
+
+ if (vty->cp > vty->length)
+ vty->length++;
+
+ if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+ return;
+
+ vty_write (vty, &c, 1);
+}
+
+/* Insert a word into vty interface with overwrite mode. */
+static void
+vty_insert_word_overwrite (struct vty *vty, char *str)
+{
+ int len = strlen (str);
+ vty_write (vty, str, len);
+ strcpy (&vty->buf[vty->cp], str);
+ vty->cp += len;
+ vty->length = vty->cp;
+}
+
+/* Forward character. */
+static void
+vty_forward_char (struct vty *vty)
+{
+ if (vty->cp < vty->length)
+ {
+ vty_write (vty, &vty->buf[vty->cp], 1);
+ vty->cp++;
+ }
+}
+
+/* Backward character. */
+static void
+vty_backward_char (struct vty *vty)
+{
+ if (vty->cp > 0)
+ {
+ vty->cp--;
+ vty_write (vty, &telnet_backward_char, 1);
+ }
+}
+
+/* Move to the beginning of the line. */
+static void
+vty_beginning_of_line (struct vty *vty)
+{
+ while (vty->cp)
+ vty_backward_char (vty);
+}
+
+/* Move to the end of the line. */
+static void
+vty_end_of_line (struct vty *vty)
+{
+ while (vty->cp < vty->length)
+ vty_forward_char (vty);
+}
+
+static void vty_kill_line_from_beginning (struct vty *);
+static void vty_redraw_line (struct vty *);
+
+/* Print command line history. This function is called from
+ vty_next_line and vty_previous_line. */
+static void
+vty_history_print (struct vty *vty)
+{
+ int length;
+
+ vty_kill_line_from_beginning (vty);
+
+ /* Get previous line from history buffer */
+ length = strlen (vty->hist[vty->hp]);
+ memcpy (vty->buf, vty->hist[vty->hp], length);
+ vty->cp = vty->length = length;
+
+ /* Redraw current line */
+ vty_redraw_line (vty);
+}
+
+/* Show next command line history. */
+void
+vty_next_line (struct vty *vty)
+{
+ int try_index;
+
+ if (vty->hp == vty->hindex)
+ return;
+
+ /* Try is there history exist or not. */
+ try_index = vty->hp;
+ if (try_index == (VTY_MAXHIST - 1))
+ try_index = 0;
+ else
+ try_index++;
+
+ /* If there is not history return. */
+ if (vty->hist[try_index] == NULL)
+ return;
+ else
+ vty->hp = try_index;
+
+ vty_history_print (vty);
+}
+
+/* Show previous command line history. */
+void
+vty_previous_line (struct vty *vty)
+{
+ int try_index;
+
+ try_index = vty->hp;
+ if (try_index == 0)
+ try_index = VTY_MAXHIST - 1;
+ else
+ try_index--;
+
+ if (vty->hist[try_index] == NULL)
+ return;
+ else
+ vty->hp = try_index;
+
+ vty_history_print (vty);
+}
+
+/* This function redraw all of the command line character. */
+static void
+vty_redraw_line (struct vty *vty)
+{
+ vty_write (vty, vty->buf, vty->length);
+ vty->cp = vty->length;
+}
+
+/* Forward word. */
+static void
+vty_forward_word (struct vty *vty)
+{
+ while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+ vty_forward_char (vty);
+
+ while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+ vty_forward_char (vty);
+}
+
+/* Backward word without skipping training space. */
+static void
+vty_backward_pure_word (struct vty *vty)
+{
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+ vty_backward_char (vty);
+}
+
+/* Backward word. */
+static void
+vty_backward_word (struct vty *vty)
+{
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+ vty_backward_char (vty);
+
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+ vty_backward_char (vty);
+}
+
+/* When '^D' is typed at the beginning of the line we move to the down
+ level. */
+static void
+vty_down_level (struct vty *vty)
+{
+ vty_out (vty, "%s", VTY_NEWLINE);
+ config_exit (NULL, vty, 0, NULL);
+ vty_prompt (vty);
+ vty->cp = 0;
+}
+
+/* When '^Z' is received from vty, move down to the enable mode. */
+void
+vty_end_config (struct vty *vty)
+{
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ /* Nothing to do. */
+ break;
+ case CONFIG_NODE:
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case BGP_NODE:
+ case BGP_VPNV4_NODE:
+ case BGP_IPV4_NODE:
+ case BGP_IPV4M_NODE:
+ case BGP_IPV6_NODE:
+ case RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case ISIS_NODE:
+ case KEYCHAIN_NODE:
+ case KEYCHAIN_KEY_NODE:
+ case MASC_NODE:
+ case VTY_NODE:
+ vty_config_unlock (vty);
+ vty->node = ENABLE_NODE;
+ break;
+ default:
+ /* Unknown node, we have to ignore it. */
+ break;
+ }
+
+ vty_prompt (vty);
+ vty->cp = 0;
+}
+
+/* Delete a charcter at the current point. */
+static void
+vty_delete_char (struct vty *vty)
+{
+ int i;
+ int size;
+
+ if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+ return;
+
+ if (vty->length == 0)
+ {
+ vty_down_level (vty);
+ return;
+ }
+
+ if (vty->cp == vty->length)
+ return; /* completion need here? */
+
+ size = vty->length - vty->cp;
+
+ vty->length--;
+ memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
+ vty->buf[vty->length] = '\0';
+
+ vty_write (vty, &vty->buf[vty->cp], size - 1);
+ vty_write (vty, &telnet_space_char, 1);
+
+ for (i = 0; i < size; i++)
+ vty_write (vty, &telnet_backward_char, 1);
+}
+
+/* Delete a character before the point. */
+static void
+vty_delete_backward_char (struct vty *vty)
+{
+ if (vty->cp == 0)
+ return;
+
+ vty_backward_char (vty);
+ vty_delete_char (vty);
+}
+
+/* Kill rest of line from current point. */
+static void
+vty_kill_line (struct vty *vty)
+{
+ int i;
+ int size;
+
+ size = vty->length - vty->cp;
+
+ if (size == 0)
+ return;
+
+ for (i = 0; i < size; i++)
+ vty_write (vty, &telnet_space_char, 1);
+ for (i = 0; i < size; i++)
+ vty_write (vty, &telnet_backward_char, 1);
+
+ memset (&vty->buf[vty->cp], 0, size);
+ vty->length = vty->cp;
+}
+
+/* Kill line from the beginning. */
+static void
+vty_kill_line_from_beginning (struct vty *vty)
+{
+ vty_beginning_of_line (vty);
+ vty_kill_line (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_forward_kill_word (struct vty *vty)
+{
+ while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+ vty_delete_char (vty);
+ while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+ vty_delete_char (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_backward_kill_word (struct vty *vty)
+{
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+ vty_delete_backward_char (vty);
+ while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+ vty_delete_backward_char (vty);
+}
+
+/* Transpose chars before or at the point. */
+static void
+vty_transpose_chars (struct vty *vty)
+{
+ char c1, c2;
+
+ /* If length is short or point is near by the beginning of line then
+ return. */
+ if (vty->length < 2 || vty->cp < 1)
+ return;
+
+ /* In case of point is located at the end of the line. */
+ if (vty->cp == vty->length)
+ {
+ c1 = vty->buf[vty->cp - 1];
+ c2 = vty->buf[vty->cp - 2];
+
+ vty_backward_char (vty);
+ vty_backward_char (vty);
+ vty_self_insert_overwrite (vty, c1);
+ vty_self_insert_overwrite (vty, c2);
+ }
+ else
+ {
+ c1 = vty->buf[vty->cp];
+ c2 = vty->buf[vty->cp - 1];
+
+ vty_backward_char (vty);
+ vty_self_insert_overwrite (vty, c1);
+ vty_self_insert_overwrite (vty, c2);
+ }
+}
+
+/* Do completion at vty interface. */
+static void
+vty_complete_command (struct vty *vty)
+{
+ int i;
+ int ret;
+ char **matched = NULL;
+ vector vline;
+
+ if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+ return;
+
+ vline = cmd_make_strvec (vty->buf);
+ if (vline == NULL)
+ return;
+
+ /* In case of 'help \t'. */
+ if (isspace ((int) vty->buf[vty->length - 1]))
+ vector_set (vline, '\0');
+
+ matched = cmd_complete_command (vline, vty, &ret);
+
+ cmd_free_strvec (vline);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ switch (ret)
+ {
+ case CMD_ERR_AMBIGUOUS:
+ vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ case CMD_ERR_NO_MATCH:
+ /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ case CMD_COMPLETE_FULL_MATCH:
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ vty_backward_pure_word (vty);
+ vty_insert_word_overwrite (vty, matched[0]);
+ vty_self_insert (vty, ' ');
+ XFREE (MTYPE_TMP, matched[0]);
+ break;
+ case CMD_COMPLETE_MATCH:
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ vty_backward_pure_word (vty);
+ vty_insert_word_overwrite (vty, matched[0]);
+ XFREE (MTYPE_TMP, matched[0]);
+ vector_only_index_free (matched);
+ return;
+ break;
+ case CMD_COMPLETE_LIST_MATCH:
+ for (i = 0; matched[i] != NULL; i++)
+ {
+ if (i != 0 && ((i % 6) == 0))
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-10s ", matched[i]);
+ XFREE (MTYPE_TMP, matched[i]);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ case CMD_ERR_NOTHING_TODO:
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ break;
+ default:
+ break;
+ }
+ if (matched)
+ vector_only_index_free (matched);
+}
+
+void
+vty_describe_fold (struct vty *vty, int cmd_width,
+ int desc_width, struct desc *desc)
+{
+ char *buf, *cmd, *p;
+ int pos;
+
+ cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
+
+ if (desc_width <= 0)
+ {
+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
+ return;
+ }
+
+ buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
+
+ for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
+ {
+ for (pos = desc_width; pos > 0; pos--)
+ if (*(p + pos) == ' ')
+ break;
+
+ if (pos == 0)
+ break;
+
+ strncpy (buf, p, pos);
+ buf[pos] = '\0';
+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
+
+ cmd = "";
+ }
+
+ vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
+
+ XFREE (MTYPE_TMP, buf);
+}
+
+/* Describe matched command function. */
+static void
+vty_describe_command (struct vty *vty)
+{
+ int ret;
+ vector vline;
+ vector describe;
+ int i, width, desc_width;
+ struct desc *desc, *desc_cr = NULL;
+
+ vline = cmd_make_strvec (vty->buf);
+
+ /* In case of '> ?'. */
+ if (vline == NULL)
+ {
+ vline = vector_init (1);
+ vector_set (vline, '\0');
+ }
+ else
+ if (isspace ((int) vty->buf[vty->length - 1]))
+ vector_set (vline, '\0');
+
+ describe = cmd_describe_command (vline, vty, &ret);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ /* Ambiguous error. */
+ switch (ret)
+ {
+ case CMD_ERR_AMBIGUOUS:
+ cmd_free_strvec (vline);
+ vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ return;
+ break;
+ case CMD_ERR_NO_MATCH:
+ cmd_free_strvec (vline);
+ vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+ return;
+ break;
+ }
+
+ /* Get width of command string. */
+ width = 0;
+ for (i = 0; i < vector_max (describe); i++)
+ if ((desc = vector_slot (describe, i)) != NULL)
+ {
+ int len;
+
+ if (desc->cmd[0] == '\0')
+ continue;
+
+ len = strlen (desc->cmd);
+ if (desc->cmd[0] == '.')
+ len--;
+
+ if (width < len)
+ width = len;
+ }
+
+ /* Get width of description string. */
+ desc_width = vty->width - (width + 6);
+
+ /* Print out description. */
+ for (i = 0; i < vector_max (describe); i++)
+ if ((desc = vector_slot (describe, i)) != NULL)
+ {
+ if (desc->cmd[0] == '\0')
+ continue;
+
+ if (strcmp (desc->cmd, "<cr>") == 0)
+ {
+ desc_cr = desc;
+ continue;
+ }
+
+ if (!desc->str)
+ vty_out (vty, " %-s%s",
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ VTY_NEWLINE);
+ else if (desc_width >= strlen (desc->str))
+ vty_out (vty, " %-*s %s%s", width,
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ desc->str, VTY_NEWLINE);
+ else
+ vty_describe_fold (vty, width, desc_width, desc);
+
+#if 0
+ vty_out (vty, " %-*s %s%s", width
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ desc->str ? desc->str : "", VTY_NEWLINE);
+#endif /* 0 */
+ }
+
+ if ((desc = desc_cr))
+ {
+ if (!desc->str)
+ vty_out (vty, " %-s%s",
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ VTY_NEWLINE);
+ else if (desc_width >= strlen (desc->str))
+ vty_out (vty, " %-*s %s%s", width,
+ desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+ desc->str, VTY_NEWLINE);
+ else
+ vty_describe_fold (vty, width, desc_width, desc);
+ }
+
+ cmd_free_strvec (vline);
+ vector_free (describe);
+
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+}
+
+void
+vty_clear_buf (struct vty *vty)
+{
+ memset (vty->buf, 0, vty->max);
+}
+
+/* ^C stop current input and do not add command line to the history. */
+static void
+vty_stop_input (struct vty *vty)
+{
+ vty->cp = vty->length = 0;
+ vty_clear_buf (vty);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ switch (vty->node)
+ {
+ case VIEW_NODE:
+ case ENABLE_NODE:
+ /* Nothing to do. */
+ break;
+ case CONFIG_NODE:
+ case INTERFACE_NODE:
+ case ZEBRA_NODE:
+ case RIP_NODE:
+ case RIPNG_NODE:
+ case BGP_NODE:
+ case RMAP_NODE:
+ case OSPF_NODE:
+ case OSPF6_NODE:
+ case ISIS_NODE:
+ case KEYCHAIN_NODE:
+ case KEYCHAIN_KEY_NODE:
+ case MASC_NODE:
+ case VTY_NODE:
+ vty_config_unlock (vty);
+ vty->node = ENABLE_NODE;
+ break;
+ default:
+ /* Unknown node, we have to ignore it. */
+ break;
+ }
+ vty_prompt (vty);
+
+ /* Set history pointer to the latest one. */
+ vty->hp = vty->hindex;
+}
+
+/* Add current command line to the history buffer. */
+static void
+vty_hist_add (struct vty *vty)
+{
+ int index;
+
+ if (vty->length == 0)
+ return;
+
+ index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
+
+ /* Ignore the same string as previous one. */
+ if (vty->hist[index])
+ if (strcmp (vty->buf, vty->hist[index]) == 0)
+ {
+ vty->hp = vty->hindex;
+ return;
+ }
+
+ /* Insert history entry. */
+ if (vty->hist[vty->hindex])
+ XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
+ vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
+
+ /* History index rotation. */
+ vty->hindex++;
+ if (vty->hindex == VTY_MAXHIST)
+ vty->hindex = 0;
+
+ vty->hp = vty->hindex;
+}
+
+/* #define TELNET_OPTION_DEBUG */
+
+/* Get telnet window size. */
+static int
+vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
+{
+#ifdef TELNET_OPTION_DEBUG
+ int i;
+
+ for (i = 0; i < nbytes; i++)
+ {
+ switch (buf[i])
+ {
+ case IAC:
+ vty_out (vty, "IAC ");
+ break;
+ case WILL:
+ vty_out (vty, "WILL ");
+ break;
+ case WONT:
+ vty_out (vty, "WONT ");
+ break;
+ case DO:
+ vty_out (vty, "DO ");
+ break;
+ case DONT:
+ vty_out (vty, "DONT ");
+ break;
+ case SB:
+ vty_out (vty, "SB ");
+ break;
+ case SE:
+ vty_out (vty, "SE ");
+ break;
+ case TELOPT_ECHO:
+ vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
+ break;
+ case TELOPT_SGA:
+ vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
+ break;
+ case TELOPT_NAWS:
+ vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, "%x ", buf[i]);
+ break;
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+#endif /* TELNET_OPTION_DEBUG */
+
+ switch (buf[0])
+ {
+ case SB:
+ buffer_reset(vty->sb_buffer);
+ vty->iac_sb_in_progress = 1;
+ return 0;
+ break;
+ case SE:
+ {
+ char *buffer = (char *)vty->sb_buffer->head->data;
+ int length = vty->sb_buffer->length;
+
+ if (buffer == NULL)
+ return 0;
+
+ if (!vty->iac_sb_in_progress)
+ return 0;
+
+ if (buffer[0] == '\0')
+ {
+ vty->iac_sb_in_progress = 0;
+ return 0;
+ }
+ switch (buffer[0])
+ {
+ case TELOPT_NAWS:
+ if (length < 5)
+ break;
+ vty->width = buffer[2];
+ vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
+ break;
+ }
+ vty->iac_sb_in_progress = 0;
+ return 0;
+ break;
+ }
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Execute current command line. */
+static int
+vty_execute (struct vty *vty)
+{
+ int ret;
+
+ ret = CMD_SUCCESS;
+
+ switch (vty->node)
+ {
+ case AUTH_NODE:
+ case AUTH_ENABLE_NODE:
+ vty_auth (vty, vty->buf);
+ break;
+ default:
+ ret = vty_command (vty, vty->buf);
+ if (vty->type == VTY_TERM)
+ vty_hist_add (vty);
+ break;
+ }
+
+ /* Clear command line buffer. */
+ vty->cp = vty->length = 0;
+ vty_clear_buf (vty);
+
+ if (vty->status != VTY_CLOSE
+ && vty->status != VTY_START
+ && vty->status != VTY_CONTINUE)
+ vty_prompt (vty);
+
+ return ret;
+}
+
+#define CONTROL(X) ((X) - '@')
+#define VTY_NORMAL 0
+#define VTY_PRE_ESCAPE 1
+#define VTY_ESCAPE 2
+
+/* Escape character command map. */
+static void
+vty_escape_map (unsigned char c, struct vty *vty)
+{
+ switch (c)
+ {
+ case ('A'):
+ vty_previous_line (vty);
+ break;
+ case ('B'):
+ vty_next_line (vty);
+ break;
+ case ('C'):
+ vty_forward_char (vty);
+ break;
+ case ('D'):
+ vty_backward_char (vty);
+ break;
+ default:
+ break;
+ }
+
+ /* Go back to normal mode. */
+ vty->escape = VTY_NORMAL;
+}
+
+/* Quit print out to the buffer. */
+static void
+vty_buffer_reset (struct vty *vty)
+{
+ buffer_reset (vty->obuf);
+ vty_prompt (vty);
+ vty_redraw_line (vty);
+}
+
+/* Read data via vty socket. */
+static int
+vty_read (struct thread *thread)
+{
+ int i;
+ int ret;
+ int nbytes;
+ unsigned char buf[VTY_READ_BUFSIZ];
+
+ int vty_sock = THREAD_FD (thread);
+ struct vty *vty = THREAD_ARG (thread);
+ vty->t_read = NULL;
+
+ /* Read raw data from socket */
+ nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
+ if (nbytes <= 0)
+ vty->status = VTY_CLOSE;
+
+ for (i = 0; i < nbytes; i++)
+ {
+ if (buf[i] == IAC)
+ {
+ if (!vty->iac)
+ {
+ vty->iac = 1;
+ continue;
+ }
+ else
+ {
+ vty->iac = 0;
+ }
+ }
+
+ if (vty->iac_sb_in_progress && !vty->iac)
+ {
+ buffer_putc(vty->sb_buffer, buf[i]);
+ continue;
+ }
+
+ if (vty->iac)
+ {
+ /* In case of telnet command */
+ ret = vty_telnet_option (vty, buf + i, nbytes - i);
+ vty->iac = 0;
+ i += ret;
+ continue;
+ }
+
+ if (vty->status == VTY_MORE)
+ {
+ switch (buf[i])
+ {
+ case CONTROL('C'):
+ case 'q':
+ case 'Q':
+ if (vty->output_func)
+ (*vty->output_func) (vty, 1);
+ vty_buffer_reset (vty);
+ break;
+ default:
+ if (vty->output_func)
+ (*vty->output_func) (vty, 0);
+ break;
+ }
+ continue;
+ }
+
+ /* Escape character. */
+ if (vty->escape == VTY_ESCAPE)
+ {
+ vty_escape_map (buf[i], vty);
+ continue;
+ }
+
+ /* Pre-escape status. */
+ if (vty->escape == VTY_PRE_ESCAPE)
+ {
+ switch (buf[i])
+ {
+ case '[':
+ vty->escape = VTY_ESCAPE;
+ break;
+ case 'b':
+ vty_backward_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ case 'f':
+ vty_forward_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ case 'd':
+ vty_forward_kill_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ case CONTROL('H'):
+ case 0x7f:
+ vty_backward_kill_word (vty);
+ vty->escape = VTY_NORMAL;
+ break;
+ default:
+ vty->escape = VTY_NORMAL;
+ break;
+ }
+ continue;
+ }
+
+ switch (buf[i])
+ {
+ case CONTROL('A'):
+ vty_beginning_of_line (vty);
+ break;
+ case CONTROL('B'):
+ vty_backward_char (vty);
+ break;
+ case CONTROL('C'):
+ vty_stop_input (vty);
+ break;
+ case CONTROL('D'):
+ vty_delete_char (vty);
+ break;
+ case CONTROL('E'):
+ vty_end_of_line (vty);
+ break;
+ case CONTROL('F'):
+ vty_forward_char (vty);
+ break;
+ case CONTROL('H'):
+ case 0x7f:
+ vty_delete_backward_char (vty);
+ break;
+ case CONTROL('K'):
+ vty_kill_line (vty);
+ break;
+ case CONTROL('N'):
+ vty_next_line (vty);
+ break;
+ case CONTROL('P'):
+ vty_previous_line (vty);
+ break;
+ case CONTROL('T'):
+ vty_transpose_chars (vty);
+ break;
+ case CONTROL('U'):
+ vty_kill_line_from_beginning (vty);
+ break;
+ case CONTROL('W'):
+ vty_backward_kill_word (vty);
+ break;
+ case CONTROL('Z'):
+ vty_end_config (vty);
+ break;
+ case '\n':
+ case '\r':
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_execute (vty);
+ break;
+ case '\t':
+ vty_complete_command (vty);
+ break;
+ case '?':
+ if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+ vty_self_insert (vty, buf[i]);
+ else
+ vty_describe_command (vty);
+ break;
+ case '\033':
+ if (i + 1 < nbytes && buf[i + 1] == '[')
+ {
+ vty->escape = VTY_ESCAPE;
+ i++;
+ }
+ else
+ vty->escape = VTY_PRE_ESCAPE;
+ break;
+ default:
+ if (buf[i] > 31 && buf[i] < 127)
+ vty_self_insert (vty, buf[i]);
+ break;
+ }
+ }
+
+ /* Check status. */
+ if (vty->status == VTY_CLOSE)
+ vty_close (vty);
+ else
+ {
+ vty_event (VTY_WRITE, vty_sock, vty);
+ vty_event (VTY_READ, vty_sock, vty);
+ }
+ return 0;
+}
+
+/* Flush buffer to the vty. */
+static int
+vty_flush (struct thread *thread)
+{
+ int erase;
+ int dont_more;
+ int vty_sock = THREAD_FD (thread);
+ struct vty *vty = THREAD_ARG (thread);
+ vty->t_write = NULL;
+
+ /* Tempolary disable read thread. */
+ if (vty->lines == 0)
+ if (vty->t_read)
+ {
+ thread_cancel (vty->t_read);
+ vty->t_read = NULL;
+ }
+
+ /* Function execution continue. */
+ if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
+ {
+ if (vty->status == VTY_CONTINUE)
+ erase = 1;
+ else
+ erase = 0;
+
+ if (vty->output_func == NULL)
+ dont_more = 1;
+ else
+ dont_more = 0;
+
+ if (vty->lines == 0)
+ {
+ erase = 0;
+ dont_more = 1;
+ }
+
+ buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
+
+ if (vty->status == VTY_CLOSE)
+ {
+ vty_close (vty);
+ return 0;
+ }
+
+ if (vty->output_func == NULL)
+ {
+ vty->status = VTY_NORMAL;
+ vty_prompt (vty);
+ vty_event (VTY_WRITE, vty_sock, vty);
+ }
+ else
+ vty->status = VTY_MORE;
+
+ if (vty->lines == 0)
+ {
+ if (vty->output_func == NULL)
+ vty_event (VTY_READ, vty_sock, vty);
+ else
+ {
+ if (vty->output_func)
+ (*vty->output_func) (vty, 0);
+ vty_event (VTY_WRITE, vty_sock, vty);
+ }
+ }
+ }
+ else
+ {
+ if (vty->status == VTY_MORE)
+ erase = 1;
+ else
+ erase = 0;
+
+ if (vty->lines == 0)
+ buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
+ else
+ buffer_flush_window (vty->obuf, vty->fd, vty->width,
+ vty->lines >= 0 ? vty->lines : vty->height,
+ erase, 0);
+
+ if (buffer_empty (vty->obuf))
+ {
+ if (vty->status == VTY_CLOSE)
+ vty_close (vty);
+ else
+ {
+ vty->status = VTY_NORMAL;
+
+ if (vty->lines == 0)
+ vty_event (VTY_READ, vty_sock, vty);
+ }
+ }
+ else
+ {
+ vty->status = VTY_MORE;
+
+ if (vty->lines == 0)
+ vty_event (VTY_WRITE, vty_sock, vty);
+ }
+ }
+
+ return 0;
+}
+
+/* Create new vty structure. */
+struct vty *
+vty_create (int vty_sock, union sockunion *su)
+{
+ struct vty *vty;
+
+ /* Allocate new vty structure and set up default values. */
+ vty = vty_new ();
+ vty->fd = vty_sock;
+ vty->type = VTY_TERM;
+ vty->address = sockunion_su2str (su);
+ if (no_password_check)
+ {
+ if (host.advanced)
+ vty->node = ENABLE_NODE;
+ else
+ vty->node = VIEW_NODE;
+ }
+ else
+ vty->node = AUTH_NODE;
+ vty->fail = 0;
+ vty->cp = 0;
+ vty_clear_buf (vty);
+ vty->length = 0;
+ memset (vty->hist, 0, sizeof (vty->hist));
+ vty->hp = 0;
+ vty->hindex = 0;
+ vector_set_index (vtyvec, vty_sock, vty);
+ vty->status = VTY_NORMAL;
+ vty->v_timeout = vty_timeout_val;
+ if (host.lines >= 0)
+ vty->lines = host.lines;
+ else
+ vty->lines = -1;
+ vty->iac = 0;
+ vty->iac_sb_in_progress = 0;
+ vty->sb_buffer = buffer_new (1024);
+
+ if (! no_password_check)
+ {
+ /* Vty is not available if password isn't set. */
+ if (host.password == NULL && host.password_encrypt == NULL)
+ {
+ vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+ vty->status = VTY_CLOSE;
+ vty_close (vty);
+ return NULL;
+ }
+ }
+
+ /* Say hello to the world. */
+ vty_hello (vty);
+ if (! no_password_check)
+ vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+ /* Setting up terminal. */
+ vty_will_echo (vty);
+ vty_will_suppress_go_ahead (vty);
+
+ vty_dont_linemode (vty);
+ vty_do_window_size (vty);
+ /* vty_dont_lflow_ahead (vty); */
+
+ vty_prompt (vty);
+
+ /* Add read/write thread. */
+ vty_event (VTY_WRITE, vty_sock, vty);
+ vty_event (VTY_READ, vty_sock, vty);
+
+ return vty;
+}
+
+/* Accept connection from the network. */
+static int
+vty_accept (struct thread *thread)
+{
+ int vty_sock;
+ struct vty *vty;
+ union sockunion su;
+ int ret;
+ unsigned int on;
+ int accept_sock;
+ struct prefix *p = NULL;
+ struct access_list *acl = NULL;
+
+ accept_sock = THREAD_FD (thread);
+
+ /* We continue hearing vty socket. */
+ vty_event (VTY_SERV, accept_sock, NULL);
+
+ memset (&su, 0, sizeof (union sockunion));
+
+ /* We can handle IPv4 or IPv6 socket. */
+ vty_sock = sockunion_accept (accept_sock, &su);
+ if (vty_sock < 0)
+ {
+ zlog_warn ("can't accept vty socket : %s", strerror (errno));
+ return -1;
+ }
+
+ p = sockunion2hostprefix (&su);
+
+ /* VTY's accesslist apply. */
+ if (p->family == AF_INET && vty_accesslist_name)
+ {
+ if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
+ (access_list_apply (acl, p) == FILTER_DENY))
+ {
+ char *buf;
+ zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+ (buf = sockunion_su2str (&su)));
+ free (buf);
+ close (vty_sock);
+
+ /* continue accepting connections */
+ vty_event (VTY_SERV, accept_sock, NULL);
+
+ prefix_free (p);
+
+ return 0;
+ }
+ }
+
+#ifdef HAVE_IPV6
+ /* VTY's ipv6 accesslist apply. */
+ if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
+ {
+ if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
+ (access_list_apply (acl, p) == FILTER_DENY))
+ {
+ char *buf;
+ zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+ (buf = sockunion_su2str (&su)));
+ free (buf);
+ close (vty_sock);
+
+ /* continue accepting connections */
+ vty_event (VTY_SERV, accept_sock, NULL);
+
+ prefix_free (p);
+
+ return 0;
+ }
+ }
+#endif /* HAVE_IPV6 */
+
+ prefix_free (p);
+
+ on = 1;
+ ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *) &on, sizeof (on));
+ if (ret < 0)
+ zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s",
+ strerror (errno));
+
+ vty = vty_create (vty_sock, &su);
+
+ return 0;
+}
+
+#if defined(HAVE_IPV6) && !defined(NRL)
+void
+vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
+{
+ int ret;
+ struct addrinfo req;
+ struct addrinfo *ainfo;
+ struct addrinfo *ainfo_save;
+ int sock;
+ char port_str[BUFSIZ];
+
+ memset (&req, 0, sizeof (struct addrinfo));
+ req.ai_flags = AI_PASSIVE;
+ req.ai_family = AF_UNSPEC;
+ req.ai_socktype = SOCK_STREAM;
+ sprintf (port_str, "%d", port);
+ port_str[sizeof (port_str) - 1] = '\0';
+
+ ret = getaddrinfo (hostname, port_str, &req, &ainfo);
+
+ if (ret != 0)
+ {
+ fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
+ exit (1);
+ }
+
+ ainfo_save = ainfo;
+
+ do
+ {
+ if (ainfo->ai_family != AF_INET
+#ifdef HAVE_IPV6
+ && ainfo->ai_family != AF_INET6
+#endif /* HAVE_IPV6 */
+ )
+ continue;
+
+ sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
+ if (sock < 0)
+ continue;
+
+ sockopt_reuseaddr (sock);
+ sockopt_reuseport (sock);
+
+ ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
+ if (ret < 0)
+ {
+ close (sock); /* Avoid sd leak. */
+ continue;
+ }
+
+ ret = listen (sock, 3);
+ if (ret < 0)
+ {
+ close (sock); /* Avoid sd leak. */
+ continue;
+ }
+
+ vty_event (VTY_SERV, sock, NULL);
+ }
+ while ((ainfo = ainfo->ai_next) != NULL);
+
+ freeaddrinfo (ainfo_save);
+}
+#endif /* HAVE_IPV6 && ! NRL */
+
+/* Make vty server socket. */
+void
+vty_serv_sock_family (unsigned short port, int family)
+{
+ int ret;
+ union sockunion su;
+ int accept_sock;
+
+ memset (&su, 0, sizeof (union sockunion));
+ su.sa.sa_family = family;
+
+ /* Make new socket. */
+ accept_sock = sockunion_stream_socket (&su);
+ if (accept_sock < 0)
+ return;
+
+ /* This is server, so reuse address. */
+ sockopt_reuseaddr (accept_sock);
+ sockopt_reuseport (accept_sock);
+
+ /* Bind socket to universal address and given port. */
+ ret = sockunion_bind (accept_sock, &su, port, NULL);
+ if (ret < 0)
+ {
+ close (accept_sock); /* Avoid sd leak. */
+ return;
+ }
+
+ /* Listen socket under queue 3. */
+ ret = listen (accept_sock, 3);
+ if (ret < 0)
+ {
+ zlog (NULL, LOG_WARNING, "can't listen socket");
+ close (accept_sock); /* Avoid sd leak. */
+ return;
+ }
+
+ /* Add vty server event. */
+ vty_event (VTY_SERV, accept_sock, NULL);
+}
+
+#ifdef VTYSH
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+/* VTY shell UNIX domain socket. */
+void
+vty_serv_un (char *path)
+{
+ int ret;
+ int sock, len;
+ struct sockaddr_un serv;
+ mode_t old_mask;
+
+ /* First of all, unlink existing socket */
+ unlink (path);
+
+ /* Set umask */
+ old_mask = umask (0077);
+
+ /* Make UNIX domain socket. */
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror ("sock");
+ return;
+ }
+
+ /* Make server socket. */
+ memset (&serv, 0, sizeof (struct sockaddr_un));
+ serv.sun_family = AF_UNIX;
+ strncpy (serv.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+ len = serv.sun_len = SUN_LEN(&serv);
+#else
+ len = sizeof (serv.sun_family) + strlen (serv.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+ ret = bind (sock, (struct sockaddr *) &serv, len);
+ if (ret < 0)
+ {
+ perror ("bind");
+ close (sock); /* Avoid sd leak. */
+ return;
+ }
+
+ ret = listen (sock, 5);
+ if (ret < 0)
+ {
+ perror ("listen");
+ close (sock); /* Avoid sd leak. */
+ return;
+ }
+
+ umask (old_mask);
+
+ vty_event (VTYSH_SERV, sock, NULL);
+}
+
+/* #define VTYSH_DEBUG 1 */
+
+static int
+vtysh_accept (struct thread *thread)
+{
+ int accept_sock;
+ int sock;
+ int client_len;
+ struct sockaddr_un client;
+ struct vty *vty;
+
+ accept_sock = THREAD_FD (thread);
+
+ vty_event (VTYSH_SERV, accept_sock, NULL);
+
+ memset (&client, 0, sizeof (struct sockaddr_un));
+ client_len = sizeof (struct sockaddr_un);
+
+ sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
+
+ if (sock < 0)
+ {
+ zlog_warn ("can't accept vty socket : %s", strerror (errno));
+ return -1;
+ }
+
+#ifdef VTYSH_DEBUG
+ printf ("VTY shell accept\n");
+#endif /* VTYSH_DEBUG */
+
+ vty = vty_new ();
+ vty->fd = sock;
+ vty->type = VTY_SHELL_SERV;
+ vty->node = VIEW_NODE;
+
+ vty_event (VTYSH_READ, sock, vty);
+
+ return 0;
+}
+
+static int
+vtysh_read (struct thread *thread)
+{
+ int ret;
+ int sock;
+ int nbytes;
+ struct vty *vty;
+ unsigned char buf[VTY_READ_BUFSIZ];
+ u_char header[4] = {0, 0, 0, 0};
+
+ sock = THREAD_FD (thread);
+ vty = THREAD_ARG (thread);
+ vty->t_read = NULL;
+
+ nbytes = read (sock, buf, VTY_READ_BUFSIZ);
+ if (nbytes <= 0)
+ {
+ vty_close (vty);
+#ifdef VTYSH_DEBUG
+ printf ("close vtysh\n");
+#endif /* VTYSH_DEBUG */
+ return 0;
+ }
+
+#ifdef VTYSH_DEBUG
+ printf ("line: %s\n", buf);
+#endif /* VTYSH_DEBUG */
+
+ vty_ensure (vty, nbytes);
+ memcpy (vty->buf, buf, nbytes);
+
+ /* Pass this line to parser. */
+ ret = vty_execute (vty);
+
+ vty_clear_buf (vty);
+
+ /* Return result. */
+#ifdef VTYSH_DEBUG
+ printf ("result: %d\n", ret);
+ printf ("vtysh node: %d\n", vty->node);
+#endif /* VTYSH_DEBUG */
+
+ header[3] = ret;
+ write (vty->fd, header, 4);
+
+ vty_event (VTYSH_READ, sock, vty);
+
+ return 0;
+}
+#endif /* VTYSH */
+
+/* Determine address family to bind. */
+void
+vty_serv_sock (const char *hostname, unsigned short port, char *path)
+{
+ /* If port is set to 0, do not listen on TCP/IP at all! */
+ if (port)
+ {
+
+#ifdef HAVE_IPV6
+#ifdef NRL
+ vty_serv_sock_family (port, AF_INET);
+ vty_serv_sock_family (port, AF_INET6);
+#else /* ! NRL */
+ vty_serv_sock_addrinfo (hostname, port);
+#endif /* NRL*/
+#else /* ! HAVE_IPV6 */
+ vty_serv_sock_family (port, AF_INET);
+#endif /* HAVE_IPV6 */
+ }
+
+#ifdef VTYSH
+ vty_serv_un (path);
+#endif /* VTYSH */
+}
+
+/* Close vty interface. */
+void
+vty_close (struct vty *vty)
+{
+ int i;
+
+ /* Cancel threads.*/
+ if (vty->t_read)
+ thread_cancel (vty->t_read);
+ if (vty->t_write)
+ thread_cancel (vty->t_write);
+ if (vty->t_timeout)
+ thread_cancel (vty->t_timeout);
+ if (vty->t_output)
+ thread_cancel (vty->t_output);
+
+ /* Flush buffer. */
+ if (! buffer_empty (vty->obuf))
+ buffer_flush_all (vty->obuf, vty->fd);
+
+ /* Free input buffer. */
+ buffer_free (vty->obuf);
+
+ /* Free SB buffer. */
+ if (vty->sb_buffer)
+ buffer_free (vty->sb_buffer);
+
+ /* Free command history. */
+ for (i = 0; i < VTY_MAXHIST; i++)
+ if (vty->hist[i])
+ XFREE (MTYPE_VTY_HIST, vty->hist[i]);
+
+ /* Unset vector. */
+ vector_unset (vtyvec, vty->fd);
+
+ /* Close socket. */
+ if (vty->fd > 0)
+ close (vty->fd);
+
+ if (vty->address)
+ XFREE (0, vty->address);
+ if (vty->buf)
+ XFREE (MTYPE_VTY, vty->buf);
+
+ /* Check configure. */
+ vty_config_unlock (vty);
+
+ /* OK free vty. */
+ XFREE (MTYPE_VTY, vty);
+}
+
+/* When time out occur output message then close connection. */
+static int
+vty_timeout (struct thread *thread)
+{
+ struct vty *vty;
+
+ vty = THREAD_ARG (thread);
+ vty->t_timeout = NULL;
+ vty->v_timeout = 0;
+
+ /* Clear buffer*/
+ buffer_reset (vty->obuf);
+ vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
+
+ /* Close connection. */
+ vty->status = VTY_CLOSE;
+ vty_close (vty);
+
+ return 0;
+}
+
+/* Read up configuration file from file_name. */
+static void
+vty_read_file (FILE *confp)
+{
+ int ret;
+ struct vty *vty;
+
+ vty = vty_new ();
+ vty->fd = 0; /* stdout */
+ vty->type = VTY_TERM;
+ vty->node = CONFIG_NODE;
+
+ /* Execute configuration file */
+ ret = config_from_file (vty, confp);
+
+ if (ret != CMD_SUCCESS)
+ {
+ switch (ret)
+ {
+ case CMD_ERR_AMBIGUOUS:
+ fprintf (stderr, "Ambiguous command.\n");
+ break;
+ case CMD_ERR_NO_MATCH:
+ fprintf (stderr, "There is no such command.\n");
+ break;
+ }
+ fprintf (stderr, "Error occured during reading below line.\n%s\n",
+ vty->buf);
+ vty_close (vty);
+ exit (1);
+ }
+
+ vty_close (vty);
+}
+
+FILE *
+vty_use_backup_config (char *fullpath)
+{
+ char *fullpath_sav, *fullpath_tmp;
+ FILE *ret = NULL;
+ struct stat buf;
+ int tmp, sav;
+ int c;
+ char buffer[512];
+
+ fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
+ strcpy (fullpath_sav, fullpath);
+ strcat (fullpath_sav, CONF_BACKUP_EXT);
+ if (stat (fullpath_sav, &buf) == -1)
+ {
+ free (fullpath_sav);
+ return NULL;
+ }
+
+ fullpath_tmp = malloc (strlen (fullpath) + 8);
+ sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
+
+ /* Open file to configuration write. */
+ tmp = mkstemp (fullpath_tmp);
+ if (tmp < 0)
+ {
+ free (fullpath_sav);
+ free (fullpath_tmp);
+ return NULL;
+ }
+
+ sav = open (fullpath_sav, O_RDONLY);
+ if (sav < 0)
+ {
+ free (fullpath_sav);
+ free (fullpath_tmp);
+ unlink (fullpath_tmp);
+ return NULL;
+ }
+
+ while((c = read (sav, buffer, 512)) > 0)
+ write (tmp, buffer, c);
+
+ close (sav);
+ close (tmp);
+
+ if (link (fullpath_tmp, fullpath) == 0)
+ ret = fopen (fullpath, "r");
+
+ unlink (fullpath_tmp);
+
+ free (fullpath_sav);
+ free (fullpath_tmp);
+ return fopen (fullpath, "r");
+}
+
+/* Read up configuration file from file_name. */
+void
+vty_read_config (char *config_file,
+ char *config_current_dir,
+ char *config_default_dir)
+{
+ char *cwd;
+ FILE *confp = NULL;
+ char *fullpath;
+
+ /* If -f flag specified. */
+ if (config_file != NULL)
+ {
+ if (! IS_DIRECTORY_SEP (config_file[0]))
+ {
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (config_file) + 2);
+ sprintf (fullpath, "%s/%s", cwd, config_file);
+ }
+ else
+ fullpath = config_file;
+
+ confp = fopen (fullpath, "r");
+
+ if (confp == NULL)
+ {
+ confp = vty_use_backup_config (fullpath);
+ if (confp)
+ fprintf (stderr, "WARNING: using backup configuration file!\n");
+ else
+ {
+ fprintf (stderr, "can't open configuration file [%s]\n",
+ config_file);
+ exit(1);
+ }
+ }
+ }
+ else
+ {
+ /* Relative path configuration file open. */
+ if (config_current_dir)
+ {
+ confp = fopen (config_current_dir, "r");
+ if (confp == NULL)
+ {
+ confp = vty_use_backup_config (config_current_dir);
+ if (confp)
+ fprintf (stderr, "WARNING: using backup configuration file!\n");
+ }
+ }
+
+ /* If there is no relative path exists, open system default file. */
+ if (confp == NULL)
+ {
+#ifdef VTYSH
+ int ret;
+ struct stat conf_stat;
+
+ /* !!!!PLEASE LEAVE!!!!
+ This is NEEDED for use with vtysh -b, or else you can get
+ a real configuration food fight with a lot garbage in the
+ merged configuration file it creates coming from the per
+ daemon configuration files. This also allows the daemons
+ to start if there default configuration file is not
+ present or ignore them, as needed when using vtysh -b to
+ configure the daemons at boot - MAG */
+
+ /* Stat for vtysh Zebra.conf, if found startup and wait for
+ boot configuration */
+
+ if ( strstr(config_default_dir, "vtysh") == NULL)
+ {
+ ret = stat (integrate_default, &conf_stat);
+ if (ret >= 0)
+ {
+ return;
+ }
+ }
+#endif /* VTYSH */
+
+ confp = fopen (config_default_dir, "r");
+ if (confp == NULL)
+ {
+ confp = vty_use_backup_config (config_default_dir);
+ if (confp)
+ {
+ fprintf (stderr, "WARNING: using backup configuration file!\n");
+ fullpath = config_default_dir;
+ }
+ else
+ {
+ fprintf (stderr, "can't open configuration file [%s]\n",
+ config_default_dir);
+ exit (1);
+ }
+ }
+ else
+ fullpath = config_default_dir;
+ }
+ else
+ {
+ /* Rleative path configuration file. */
+ cwd = getcwd (NULL, MAXPATHLEN);
+ fullpath = XMALLOC (MTYPE_TMP,
+ strlen (cwd) + strlen (config_current_dir) + 2);
+ sprintf (fullpath, "%s/%s", cwd, config_current_dir);
+ }
+ }
+ vty_read_file (confp);
+
+ fclose (confp);
+
+ host_config_set (fullpath);
+}
+
+/* Small utility function which output log to the VTY. */
+void
+vty_log (const char *proto_str, const char *format, va_list va)
+{
+ int i;
+ struct vty *vty;
+
+ for (i = 0; i < vector_max (vtyvec); i++)
+ if ((vty = vector_slot (vtyvec, i)) != NULL)
+ if (vty->monitor)
+ vty_log_out (vty, proto_str, format, va);
+}
+
+int
+vty_config_lock (struct vty *vty)
+{
+ if (vty_config == 0)
+ {
+ vty->config = 1;
+ vty_config = 1;
+ }
+ return vty->config;
+}
+
+int
+vty_config_unlock (struct vty *vty)
+{
+ if (vty_config == 1 && vty->config == 1)
+ {
+ vty->config = 0;
+ vty_config = 0;
+ }
+ return vty->config;
+}
+
+/* Master of the threads. */
+extern struct thread_master *master;
+/* struct thread_master *master; */
+
+static void
+vty_event (enum event event, int sock, struct vty *vty)
+{
+ struct thread *vty_serv_thread;
+
+ switch (event)
+ {
+ case VTY_SERV:
+ vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
+ vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
+ break;
+#ifdef VTYSH
+ case VTYSH_SERV:
+ thread_add_read (master, vtysh_accept, vty, sock);
+ break;
+ case VTYSH_READ:
+ thread_add_read (master, vtysh_read, vty, sock);
+ break;
+#endif /* VTYSH */
+ case VTY_READ:
+ vty->t_read = thread_add_read (master, vty_read, vty, sock);
+
+ /* Time out treatment. */
+ if (vty->v_timeout)
+ {
+ if (vty->t_timeout)
+ thread_cancel (vty->t_timeout);
+ vty->t_timeout =
+ thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+ }
+ break;
+ case VTY_WRITE:
+ if (! vty->t_write)
+ vty->t_write = thread_add_write (master, vty_flush, vty, sock);
+ break;
+ case VTY_TIMEOUT_RESET:
+ if (vty->t_timeout)
+ {
+ thread_cancel (vty->t_timeout);
+ vty->t_timeout = NULL;
+ }
+ if (vty->v_timeout)
+ {
+ vty->t_timeout =
+ thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+ }
+ break;
+ }
+}
+
+DEFUN (config_who,
+ config_who_cmd,
+ "who",
+ "Display who is on vty\n")
+{
+ int i;
+ struct vty *v;
+
+ for (i = 0; i < vector_max (vtyvec); i++)
+ if ((v = vector_slot (vtyvec, i)) != NULL)
+ vty_out (vty, "%svty[%d] connected from %s.%s",
+ v->config ? "*" : " ",
+ i, v->address, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+/* Move to vty configuration mode. */
+DEFUN (line_vty,
+ line_vty_cmd,
+ "line vty",
+ "Configure a terminal line\n"
+ "Virtual terminal\n")
+{
+ vty->node = VTY_NODE;
+ return CMD_SUCCESS;
+}
+
+/* Set time out value. */
+int
+exec_timeout (struct vty *vty, char *min_str, char *sec_str)
+{
+ unsigned long timeout = 0;
+
+ /* min_str and sec_str are already checked by parser. So it must be
+ all digit string. */
+ if (min_str)
+ {
+ timeout = strtol (min_str, NULL, 10);
+ timeout *= 60;
+ }
+ if (sec_str)
+ timeout += strtol (sec_str, NULL, 10);
+
+ vty_timeout_val = timeout;
+ vty->v_timeout = timeout;
+ vty_event (VTY_TIMEOUT_RESET, 0, vty);
+
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (exec_timeout_min,
+ exec_timeout_min_cmd,
+ "exec-timeout <0-35791>",
+ "Set timeout value\n"
+ "Timeout value in minutes\n")
+{
+ return exec_timeout (vty, argv[0], NULL);
+}
+
+DEFUN (exec_timeout_sec,
+ exec_timeout_sec_cmd,
+ "exec-timeout <0-35791> <0-2147483>",
+ "Set the EXEC timeout\n"
+ "Timeout in minutes\n"
+ "Timeout in seconds\n")
+{
+ return exec_timeout (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_exec_timeout,
+ no_exec_timeout_cmd,
+ "no exec-timeout",
+ NO_STR
+ "Set the EXEC timeout\n")
+{
+ return exec_timeout (vty, NULL, NULL);
+}
+
+/* Set vty access class. */
+DEFUN (vty_access_class,
+ vty_access_class_cmd,
+ "access-class WORD",
+ "Filter connections based on an IP access list\n"
+ "IP access list\n")
+{
+ if (vty_accesslist_name)
+ XFREE(MTYPE_VTY, vty_accesslist_name);
+
+ vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+/* Clear vty access class. */
+DEFUN (no_vty_access_class,
+ no_vty_access_class_cmd,
+ "no access-class [WORD]",
+ NO_STR
+ "Filter connections based on an IP access list\n"
+ "IP access list\n")
+{
+ if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
+ {
+ vty_out (vty, "Access-class is not currently applied to vty%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ XFREE(MTYPE_VTY, vty_accesslist_name);
+
+ vty_accesslist_name = NULL;
+
+ return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Set vty access class. */
+DEFUN (vty_ipv6_access_class,
+ vty_ipv6_access_class_cmd,
+ "ipv6 access-class WORD",
+ IPV6_STR
+ "Filter connections based on an IP access list\n"
+ "IPv6 access list\n")
+{
+ if (vty_ipv6_accesslist_name)
+ XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+
+ vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+/* Clear vty access class. */
+DEFUN (no_vty_ipv6_access_class,
+ no_vty_ipv6_access_class_cmd,
+ "no ipv6 access-class [WORD]",
+ NO_STR
+ IPV6_STR
+ "Filter connections based on an IP access list\n"
+ "IPv6 access list\n")
+{
+ if (! vty_ipv6_accesslist_name ||
+ (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
+ {
+ vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+
+ vty_ipv6_accesslist_name = NULL;
+
+ return CMD_SUCCESS;
+}
+#endif /* HAVE_IPV6 */
+
+/* vty login. */
+DEFUN (vty_login,
+ vty_login_cmd,
+ "login",
+ "Enable password checking\n")
+{
+ no_password_check = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_vty_login,
+ no_vty_login_cmd,
+ "no login",
+ NO_STR
+ "Enable password checking\n")
+{
+ no_password_check = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (service_advanced_vty,
+ service_advanced_vty_cmd,
+ "service advanced-vty",
+ "Set up miscellaneous service\n"
+ "Enable advanced mode vty interface\n")
+{
+ host.advanced = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_service_advanced_vty,
+ no_service_advanced_vty_cmd,
+ "no service advanced-vty",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Enable advanced mode vty interface\n")
+{
+ host.advanced = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (terminal_monitor,
+ terminal_monitor_cmd,
+ "terminal monitor",
+ "Set terminal line parameters\n"
+ "Copy debug output to the current terminal line\n")
+{
+ vty->monitor = 1;
+ return CMD_SUCCESS;
+}
+
+DEFUN (terminal_no_monitor,
+ terminal_no_monitor_cmd,
+ "terminal no monitor",
+ "Set terminal line parameters\n"
+ NO_STR
+ "Copy debug output to the current terminal line\n")
+{
+ vty->monitor = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_history,
+ show_history_cmd,
+ "show history",
+ SHOW_STR
+ "Display the session command history\n")
+{
+ int index;
+
+ for (index = vty->hindex + 1; index != vty->hindex;)
+ {
+ if (index == VTY_MAXHIST)
+ {
+ index = 0;
+ continue;
+ }
+
+ if (vty->hist[index] != NULL)
+ vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
+
+ index++;
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Display current configuration. */
+int
+vty_config_write (struct vty *vty)
+{
+ vty_out (vty, "line vty%s", VTY_NEWLINE);
+
+ if (vty_accesslist_name)
+ vty_out (vty, " access-class %s%s",
+ vty_accesslist_name, VTY_NEWLINE);
+
+ if (vty_ipv6_accesslist_name)
+ vty_out (vty, " ipv6 access-class %s%s",
+ vty_ipv6_accesslist_name, VTY_NEWLINE);
+
+ /* exec-timeout */
+ if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
+ vty_out (vty, " exec-timeout %ld %ld%s",
+ vty_timeout_val / 60,
+ vty_timeout_val % 60, VTY_NEWLINE);
+
+ /* login */
+ if (no_password_check)
+ vty_out (vty, " no login%s", VTY_NEWLINE);
+
+ vty_out (vty, "!%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+struct cmd_node vty_node =
+{
+ VTY_NODE,
+ "%s(config-line)# ",
+};
+
+/* Reset all VTY status. */
+void
+vty_reset ()
+{
+ int i;
+ struct vty *vty;
+ struct thread *vty_serv_thread;
+
+ for (i = 0; i < vector_max (vtyvec); i++)
+ if ((vty = vector_slot (vtyvec, i)) != NULL)
+ {
+ buffer_reset (vty->obuf);
+ vty->status = VTY_CLOSE;
+ vty_close (vty);
+ }
+
+ for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+ if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+ {
+ thread_cancel (vty_serv_thread);
+ vector_slot (Vvty_serv_thread, i) = NULL;
+ close (i);
+ }
+
+ vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+ if (vty_accesslist_name)
+ {
+ XFREE(MTYPE_VTY, vty_accesslist_name);
+ vty_accesslist_name = NULL;
+ }
+
+ if (vty_ipv6_accesslist_name)
+ {
+ XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+ vty_ipv6_accesslist_name = NULL;
+ }
+}
+
+/* for ospf6d easy temprary reload function */
+/* vty_reset + close accept socket */
+void
+vty_finish ()
+{
+ int i;
+ struct vty *vty;
+ struct thread *vty_serv_thread;
+
+ for (i = 0; i < vector_max (vtyvec); i++)
+ if ((vty = vector_slot (vtyvec, i)) != NULL)
+ {
+ buffer_reset (vty->obuf);
+ vty->status = VTY_CLOSE;
+ vty_close (vty);
+ }
+
+ for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+ if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+ {
+ thread_cancel (vty_serv_thread);
+ vector_slot (Vvty_serv_thread, i) = NULL;
+ close (i);
+ }
+
+ vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+ if (vty_accesslist_name)
+ {
+ XFREE(MTYPE_VTY, vty_accesslist_name);
+ vty_accesslist_name = NULL;
+ }
+
+ if (vty_ipv6_accesslist_name)
+ {
+ XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+ vty_ipv6_accesslist_name = NULL;
+ }
+}
+
+void
+vty_save_cwd ()
+{
+ char *cwd;
+
+ cwd = getcwd (NULL, MAXPATHLEN);
+
+ vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
+ strcpy (vty_cwd, cwd);
+}
+
+char *
+vty_get_cwd ()
+{
+ return vty_cwd;
+}
+
+int
+vty_shell (struct vty *vty)
+{
+ return vty->type == VTY_SHELL ? 1 : 0;
+}
+
+int
+vty_shell_serv (struct vty *vty)
+{
+ return vty->type == VTY_SHELL_SERV ? 1 : 0;
+}
+
+void
+vty_init_vtysh ()
+{
+ vtyvec = vector_init (VECTOR_MIN_SIZE);
+}
+
+/* Install vty's own commands like `who' command. */
+void
+vty_init ()
+{
+ /* For further configuration read, preserve current directory. */
+ vty_save_cwd ();
+
+ vtyvec = vector_init (VECTOR_MIN_SIZE);
+
+ /* Initilize server thread vector. */
+ Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
+
+ /* Install bgp top node. */
+ install_node (&vty_node, vty_config_write);
+
+ install_element (VIEW_NODE, &config_who_cmd);
+ install_element (VIEW_NODE, &show_history_cmd);
+ install_element (ENABLE_NODE, &config_who_cmd);
+ install_element (CONFIG_NODE, &line_vty_cmd);
+ install_element (CONFIG_NODE, &service_advanced_vty_cmd);
+ install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
+ install_element (CONFIG_NODE, &show_history_cmd);
+ install_element (ENABLE_NODE, &terminal_monitor_cmd);
+ install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
+ install_element (ENABLE_NODE, &show_history_cmd);
+
+ install_default (VTY_NODE);
+ install_element (VTY_NODE, &exec_timeout_min_cmd);
+ install_element (VTY_NODE, &exec_timeout_sec_cmd);
+ install_element (VTY_NODE, &no_exec_timeout_cmd);
+ install_element (VTY_NODE, &vty_access_class_cmd);
+ install_element (VTY_NODE, &no_vty_access_class_cmd);
+ install_element (VTY_NODE, &vty_login_cmd);
+ install_element (VTY_NODE, &no_vty_login_cmd);
+#ifdef HAVE_IPV6
+ install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
+ install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
+#endif /* HAVE_IPV6 */
+}
diff --git a/isisd/modified/zebra.h b/isisd/modified/zebra.h
new file mode 100644
index 00000000..989e882d
--- /dev/null
+++ b/isisd/modified/zebra.h
@@ -0,0 +1,313 @@
+/* Zebra common header.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _ZEBRA_H
+#define _ZEBRA_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef SUNOS_5
+#define _XPG4_2
+#define __EXTENSIONS__
+#endif /* SUNOS_5 */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif /* HAVE_STROPTS_H */
+#include <sys/fcntl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif /* HAVE_SYS_SYSCTL_H */
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_CONF_H
+#include <sys/conf.h>
+#endif /* HAVE_SYS_CONF_H */
+#ifdef HAVE_SYS_KSYM_H
+#include <sys/ksym.h>
+#endif /* HAVE_SYS_KSYM_H */
+#include <syslog.h>
+#include <time.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+#ifdef HAVE_RUSAGE
+#include <sys/resource.h>
+#endif /* HAVE_RUSAGE */
+
+/* machine dependent includes */
+#ifdef SUNOS_5
+#include <limits.h>
+#include <strings.h>
+#endif /* SUNOS_5 */
+
+/* machine dependent includes */
+#ifdef HAVE_LINUX_VERSION_H
+#include <linux/version.h>
+#endif /* HAVE_LINUX_VERSION_H */
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif /* HAVE_ASM_TYPES_H */
+
+/* misc include group */
+#include <stdarg.h>
+#include <assert.h>
+
+/* network include group */
+
+#include <sys/socket.h>
+
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif /* HAVE_SYS_SOCKIO_H */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#ifdef HAVE_NET_NETOPT_H
+#include <net/netopt.h>
+#endif /* HAVE_NET_NETOPT_H */
+
+#include <net/if.h>
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif /* HAVE_NET_IF_DL_H */
+
+#ifdef HAVE_NET_IF_VAR_H
+#include <net/if_var.h>
+#endif /* HAVE_NET_IF_VAR_H */
+
+#include <net/route.h>
+
+#ifdef HAVE_NETLINK
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#else
+#define RT_TABLE_MAIN 0
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+
+#include <arpa/inet.h>
+#include <arpa/telnet.h>
+
+#ifdef HAVE_INET_ND_H
+#include <inet/nd.h>
+#endif /* HAVE_INET_ND_H */
+
+#ifdef HAVE_NETINET_IN_VAR_H
+#include <netinet/in_var.h>
+#endif /* HAVE_NETINET_IN_VAR_H */
+
+#ifdef HAVE_NETINET_IN6_VAR_H
+#include <netinet/in6_var.h>
+#endif /* HAVE_NETINET_IN6_VAR_H */
+
+#ifdef HAVE_NETINET6_IN_H
+#include <netinet6/in.h>
+#endif /* HAVE_NETINET6_IN_H */
+
+
+#ifdef HAVE_NETINET6_IP6_H
+#include <netinet6/ip6.h>
+#endif /* HAVE_NETINET6_IP6_H */
+
+#ifdef HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif /* HAVE_NETINET_ICMP6_H */
+
+#ifdef HAVE_NETINET6_ND6_H
+#include <netinet6/nd6.h>
+#endif /* HAVE_NETINET6_ND6_H */
+
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif /* HAVE_LIBUTIL_H */
+
+#ifdef BSDI_NRL
+
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif /* HAVE_NETINET6_IN6_H */
+
+#ifdef NRL
+#include <netinet6/in6.h>
+#endif /* NRL */
+
+#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
+
+/* BSD/OS 4.0 has lost belows defines, it should appear at
+ /usr/include/sys/socket.h. */
+#define CMSG_ALIGN(n) (((n) + 3) & ~3)
+#define CMSG_SPACE(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l))
+#define CMSG_LEN(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l))
+
+#endif /* BSDI_NRL */
+
+/* The definition of struct in_pktinfo is missing in old version of
+ GLIBC 2.1 (Redhat 6.1). */
+#if defined (GNU_LINUX) && ! defined (HAVE_INPKTINFO)
+struct in_pktinfo
+{
+ int ipi_ifindex;
+ struct in_addr ipi_spec_dst;
+ struct in_addr ipi_addr;
+};
+#endif
+
+/* For old definition. */
+#ifndef IN6_ARE_ADDR_EQUAL
+#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
+#endif /* IN6_ARE_ADDR_EQUAL */
+
+/* Zebra message types. */
+#define ZEBRA_INTERFACE_ADD 1
+#define ZEBRA_INTERFACE_DELETE 2
+#define ZEBRA_INTERFACE_ADDRESS_ADD 3
+#define ZEBRA_INTERFACE_ADDRESS_DELETE 4
+#define ZEBRA_INTERFACE_UP 5
+#define ZEBRA_INTERFACE_DOWN 6
+#define ZEBRA_IPV4_ROUTE_ADD 7
+#define ZEBRA_IPV4_ROUTE_DELETE 8
+#define ZEBRA_IPV6_ROUTE_ADD 9
+#define ZEBRA_IPV6_ROUTE_DELETE 10
+#define ZEBRA_REDISTRIBUTE_ADD 11
+#define ZEBRA_REDISTRIBUTE_DELETE 12
+#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13
+#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14
+#define ZEBRA_IPV4_NEXTHOP_LOOKUP 15
+#define ZEBRA_IPV6_NEXTHOP_LOOKUP 16
+#define ZEBRA_IPV4_IMPORT_LOOKUP 17
+#define ZEBRA_IPV6_IMPORT_LOOKUP 18
+#define ZEBRA_MESSAGE_MAX 19
+
+/* Zebra route's types. */
+#define ZEBRA_ROUTE_SYSTEM 0
+#define ZEBRA_ROUTE_KERNEL 1
+#define ZEBRA_ROUTE_CONNECT 2
+#define ZEBRA_ROUTE_STATIC 3
+#define ZEBRA_ROUTE_RIP 4
+#define ZEBRA_ROUTE_RIPNG 5
+#define ZEBRA_ROUTE_OSPF 6
+#define ZEBRA_ROUTE_OSPF6 7
+#define ZEBRA_ROUTE_ISIS 8
+#define ZEBRA_ROUTE_BGP 9
+#define ZEBRA_ROUTE_MAX 10
+
+/* Zebra's family types. */
+#define ZEBRA_FAMILY_IPV4 1
+#define ZEBRA_FAMILY_IPV6 2
+#define ZEBRA_FAMILY_MAX 3
+
+/* Error codes of zebra. */
+#define ZEBRA_ERR_RTEXIST -1
+#define ZEBRA_ERR_RTUNREACH -2
+#define ZEBRA_ERR_EPERM -3
+#define ZEBRA_ERR_RTNOEXIST -4
+
+/* Zebra message flags */
+#define ZEBRA_FLAG_INTERNAL 0x01
+#define ZEBRA_FLAG_SELFROUTE 0x02
+#define ZEBRA_FLAG_BLACKHOLE 0x04
+#define ZEBRA_FLAG_IBGP 0x08
+#define ZEBRA_FLAG_SELECTED 0x10
+#define ZEBRA_FLAG_CHANGED 0x20
+#define ZEBRA_FLAG_STATIC 0x40
+
+/* Zebra nexthop flags. */
+#define ZEBRA_NEXTHOP_IFINDEX 1
+#define ZEBRA_NEXTHOP_IFNAME 2
+#define ZEBRA_NEXTHOP_IPV4 3
+#define ZEBRA_NEXTHOP_IPV4_IFINDEX 4
+#define ZEBRA_NEXTHOP_IPV4_IFNAME 5
+#define ZEBRA_NEXTHOP_IPV6 6
+#define ZEBRA_NEXTHOP_IPV6_IFINDEX 7
+#define ZEBRA_NEXTHOP_IPV6_IFNAME 8
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
+#endif
+
+/* Address family numbers from RFC1700. */
+#define AFI_IP 1
+#define AFI_IP6 2
+#define AFI_MAX 3
+
+/* Subsequent Address Family Identifier. */
+#define SAFI_UNICAST 1
+#define SAFI_MULTICAST 2
+#define SAFI_UNICAST_MULTICAST 3
+#define SAFI_MPLS_VPN 4
+#define SAFI_MAX 5
+
+/* Filter direction. */
+#define FILTER_IN 0
+#define FILTER_OUT 1
+#define FILTER_MAX 2
+
+/* Default Administrative Distance of each protocol. */
+#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0
+#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0
+#define ZEBRA_STATIC_DISTANCE_DEFAULT 1
+#define ZEBRA_RIP_DISTANCE_DEFAULT 120
+#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120
+#define ZEBRA_OSPF_DISTANCE_DEFAULT 110
+#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110
+#define ZEBRA_ISIS_DISTANCE_DEFAULT 115
+#define ZEBRA_IBGP_DISTANCE_DEFAULT 200
+#define ZEBRA_EBGP_DISTANCE_DEFAULT 20
+
+/* Flag manipulation macros. */
+#define CHECK_FLAG(V,F) ((V) & (F))
+#define SET_FLAG(V,F) (V) = (V) | (F)
+#define UNSET_FLAG(V,F) (V) = (V) & ~(F)
+
+/* AFI and SAFI type. */
+typedef u_int16_t afi_t;
+typedef u_char safi_t;
+
+/* Zebra types. */
+typedef u_int16_t zebra_size_t;
+typedef u_int8_t zebra_command_t;
+
+#endif /* _ZEBRA_H */
diff --git a/isisd/topology/Makefile.am b/isisd/topology/Makefile.am
new file mode 100644
index 00000000..045c15c8
--- /dev/null
+++ b/isisd/topology/Makefile.am
@@ -0,0 +1,23 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+
+noinst_LIBRARIES = libtopology.a
+
+libtopology_a_SOURCES = \
+ spgrid.c
+
+libtopology_a_DEPENDENCIES = @LIB_REGEX@
+
+libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.a
+
+noinst_HEADERS = \
+ spgrid.h
+
+EXTRA_DIST = regex.c regex-gnu.h
+
+depend:
+ @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c
+
+## File dependency.
diff --git a/isisd/topology/random.c b/isisd/topology/random.c
new file mode 100644
index 00000000..d4ef9950
--- /dev/null
+++ b/isisd/topology/random.c
@@ -0,0 +1,154 @@
+/*********************************************************************/
+/* */
+/* current processor time in seconds */
+/* difference between two calls is processor time spent by your code */
+/* needs: <sys/types.h>, <sys/times.h> */
+/* depends on compiler and OS */
+/* */
+/*********************************************************************/
+
+#include <sys/types.h>
+#include <sys/times.h>
+
+float timer()
+ { struct tms hold;
+
+ times(&hold);
+ return (float)(hold.tms_utime) / 60.0;
+ }
+
+
+/*********************************************************************/
+/* */
+/* Family of random number generators */
+/* */
+/* Initialisation: */
+/* void init_rand ( seed ); */
+/* long seed - any positive number */
+/* if seed<=0 init_rand takes time */
+/* from timer instead of seed */
+/* */
+/* Whole number uniformly distributed on [0,n): */
+/* long nrand (n); */
+/* long n */
+/* */
+/* Real number uniformly distributed on [0,1] */
+/* double rand01(); */
+/* */
+/* Real number with Gauss(0,1) disitribution: */
+/* double randg01(); */
+/* */
+/* Algorithm: */
+/* x(n+1) = (x(n) * 5^13) mod 2^31 */
+/* */
+/*********************************************************************/
+
+unsigned long internal_seed;
+
+void init_rand ( init_seed )
+
+long init_seed;
+
+{ internal_seed = ( init_seed > 0 )
+ ? (unsigned long) init_seed
+ : (unsigned long) timer();
+
+
+ /* only odd numbers are acceptable */
+ if ( internal_seed % 2 == 0 ) internal_seed --;
+}
+
+/*********************************************************************/
+/* */
+/* Internal function irand may depend on OS and compiler */
+/* */
+/* irand assumption: */
+/* unsigned long i,j; */
+/* if i*j > max(unsigned long) */
+/* 1. No overflow interruption */
+/* 2. i*j = i*j mod max(unsigned long) */
+/* */
+/* This assumption is true for a lot of computers. */
+/* If your computer fails: */
+/* rename: irand <---> xrand */
+/* */
+/*********************************************************************/
+
+#define A 1220703125
+#define B 2147483647
+#define BF 2147483647.
+
+static long irand ()
+
+{ internal_seed = ( internal_seed * A ) & B;
+ return (long) internal_seed ;
+}
+
+/*********************************************************************/
+/* */
+/* computer independent variant of irand */
+/* */
+/*********************************************************************/
+
+
+#define T15 32768
+#define T16 65536
+#define A1 37252
+#define A2 29589
+
+static long xrand()
+
+{ unsigned long is1, is2;
+
+ is1 = internal_seed / T15;
+ is2 = internal_seed % T15;
+
+ internal_seed = ( (((is2 * A1) + (is1 * A2))% T16 )* T15 + (is2 * A2) ) & B;
+ return (long) ( internal_seed ) ;
+}
+
+
+/*********************************************************************/
+
+
+double rand01()
+
+{ return (double) irand() / BF ;
+}
+
+/*********************************************************************/
+
+#define NK 12
+
+double randg01()
+
+{ int i;
+ double sum = 0;
+
+ for ( i = 0; i < NK; i++ ) sum += rand01();
+ return sum - 6.;
+
+ /* if NK != 12 then you must return (12/NK)*sum - (NK/2) */
+}
+
+#undef NK
+
+
+/*********************************************************************/
+
+long nrand ( n )
+
+long n;
+
+{ return (long) ( rand01() * (double) n );
+}
+
+/*********************************************************************/
+
+#undef A
+#undef A1
+#undef A2
+#undef B
+#undef BF
+#undef T15
+#undef T16
diff --git a/isisd/topology/spacyc.c b/isisd/topology/spacyc.c
new file mode 100644
index 00000000..85314473
--- /dev/null
+++ b/isisd/topology/spacyc.c
@@ -0,0 +1,483 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <values.h>
+
+#include "random.c"
+
+#define DASH '-'
+#define VERY_FAR 100000000
+
+
+/* generator of acyclic random networks for the shortest paths problem;
+ extended DIMACS format for output */
+
+main ( argc, argv )
+
+int argc;
+char* argv[];
+
+{
+
+char args[30];
+
+long n,
+ n0,
+ source,
+ i,
+ i0,
+ j,
+ dij;
+
+long m,
+ m0,
+ mc,
+ k;
+
+long *p,
+ p_t,
+ l,
+ lx;
+
+long seed,
+ seed1,
+ seed2;
+
+int ext=0;
+
+FILE *fout;
+
+/* variables for lengths generating */
+/* initialized by default values */
+int l_f = 0, ll_f = 0, lm_f = 0, ln_f = 0, ls_f = 0;
+long ll = 10000, /* upper bound of the interval */
+ lm = 0; /* lower bound of the interval */
+double ln = 0, /* l += ln * |i-j| */
+ ls = 0; /* l += ls * |i-j|^2 */
+
+/* variables for connecting path(s) */
+int c_f = 0, cl_f = 0, ch_f = 0, c_rand = 1;
+long cl = 1; /* length of path arc */
+long ch; /* number of arcs in the path
+ n - by default */
+
+/* variables for artifical source */
+int s_f = 0, sl_f = 0, sm_f = 0;
+long sl = VERY_FAR, /* upper bound of artifical arc */
+ sm, /* lower bound of artifical arc */
+ s;
+
+/* variables for potentials */
+int p_f = 0, pl_f = 0, pm_f = 0, pn_f = 0, ps_f = 0,
+ pa_f = 0, pap_f = 0, pac_f = 0;
+long pl, /* upper bound of the interval */
+ pm; /* lower bound of the interval */
+double pn = 0, /* l += ln * |i-j| */
+ ps = 0, /* l += ls * |i-j|^2 */
+ pap = 0, /* part of nodes with alternative dustribution */
+ pac = -1; /* multiplier for alternative distribution */
+
+int np; /* number of parameter parsing now */
+
+#define PRINT_ARC( i, j, length )\
+{\
+l = length;\
+if ( p_f ) l += ( p[i] - p[j] );\
+printf ("a %8ld %8ld %12ld\n", i, j, l );\
+}
+
+ /* parsing parameters */
+
+if ( argc < 2 ) goto usage;
+
+np = 0;
+
+strcpy ( args, argv[1] );
+
+ if ( ( args[0] == DASH ) && ( args[1] == 'h')
+ )
+ goto help;
+
+if ( argc < 4 ) goto usage;
+
+/* first parameter - number of nodes */
+np = 1;
+if ( ( n = atoi ( argv[1] ) ) < 2 ) goto usage;
+
+/* second parameter - number of arcs */
+np = 2;
+if ( ( m = atoi ( argv[2] ) ) < n ) goto usage;
+
+/* third parameter - seed */
+np=3;
+if ( ( seed = atoi ( argv[3] ) ) <= 0 ) goto usage;
+
+/* other parameters */
+
+for ( np = 4; np < argc; np ++ )
+ {
+ strcpy ( args, argv[np] );
+ if ( args[0] != DASH ) goto usage;
+
+ switch ( args[1] )
+ {
+
+ case 'l' : /* an interval for arc length */
+ l_f = 1;
+ switch ( args[2] )
+ {
+ case 'l': /* length of the interval */
+ ll_f = 1;
+ ll = (long) atof ( &args[3] );
+ break;
+ case 'm': /* minimal bound */
+ lm_f = 1;
+ lm = (long ) atof ( &args[3] );
+ break;
+ case 'n': /* additional length: l*|i-j| */
+ ln_f = 1;
+ ln = atof ( &args[3] );
+ break;
+ case 's': /* additional length: l*|i-j|^2 */
+ ls_f = 1;
+ ls = atof ( &args[3] );
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ break;
+
+ case 'c' : /* connecting path(s) */
+ c_f = 1;
+ switch ( args[2] )
+ {
+ case 'l': /* length of path arc */
+ c_rand = 0; /* fixed arc length */
+ cl_f = 1;
+ cl = (long) atof ( &args[3] );
+ break;
+ case 'h': /* number of arcs in connecting path */
+ ch_f = 1;
+ ch = (long) atof ( &args[3] );
+ if ( ch < 1 || ch > n ) goto usage;
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ break;
+
+ case 's' : /* additional source */
+ s_f = 1;
+ if ( strlen ( args ) > 2 )
+ {
+ switch ( args[2] )
+ {
+ case 'l': /* upper bound of art. arc */
+ sl_f = 1;
+ sl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound of art. arc */
+ sm_f = 1;
+ sm = (long) atof ( &args[3] );
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ }
+ break;
+
+ case 'p' : /* potentials */
+ p_f = 1;
+ if ( strlen ( args ) > 2 )
+ {
+ switch ( args[2] )
+ {
+ case 'l': /* length of the interval */
+ pl_f = 1;
+ pl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* minimal bound */
+ pm_f = 1;
+ pm = (long ) atof ( &args[3] );
+ break;
+ case 'n': /* additional length: l*|i-j| */
+ pn_f = 1;
+ pn = atof ( &args[3] );
+ break;
+ case 's': /* additional length: l*|i-j|^2 */
+ ps_f = 1;
+ ps = atof ( &args[3] );
+ break;
+ case 'a': /* bipolar distribution */
+ pa_f = 1;
+ switch ( args[3] )
+ {
+ case 'p': /* % of alternative potentials */
+ pap_f = 1;
+ pap = atof ( &args[4] );
+ if ( pap < 0 ) pap = 0;
+ if ( pap > 100 ) pap = 100;
+ pap /= 100;
+ break;
+ case 'c': /* multiplier */
+ pac_f = 1;
+ pac = atof ( &args[4] );
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ }
+ break;
+
+ default : /* unknoun case */
+ goto usage;
+ }
+ }
+
+/* ----- ajusting parameters ----- */
+
+n0 = n; m0 = m;
+
+/* length parameters */
+if ( ll < lm ) { lx = ll; ll = lm; lm = lx; }
+
+/* potential parameters */
+if ( p_f )
+ {
+ if ( ! pl_f ) pl = ll;
+ if ( ! pm_f ) pm = lm;
+ if ( pl < pm ) { lx = pl; pl = pm; pm = lx; }
+ }
+
+/* path(s) parameters */
+if ( ! ch_f ) ch = n - 1;
+mc = n - 1;
+
+ /* artifical source parameters */
+if ( s_f )
+ { m0 += n; n0 ++ ;
+ if ( ! sm_f ) sm = sl;
+ if ( sl < sm ) { lx = sl; sl = sm; sm = lx; }
+ }
+
+/*----- printing title -----*/
+
+printf ("c acyclic network for shortest paths problem\n");
+printf ("c extended DIMACS format\nc\n" );
+
+
+/* name of the problem */
+printf ("t ac_%ld_%ld_%ld_", n, m, seed );
+if ( l_f )
+ printf ("%c", 'l');
+if ( c_f )
+ printf ("%c", 'c');
+if ( s_f )
+ printf ("%c", 's');
+if ( p_f )
+ printf ("%c", 'p');
+printf ("\nc\n");
+
+/* printing additional information */
+if ( l_f )
+ printf ("c length -> min: %ld max: %ld k1: %.2f k2: %.2f\n",
+ lm, ll, ln, ls );
+if ( c_f )
+ printf ("c path(s) -> number of arcs: %ld arc length: %ld\n",
+ ch, cl );
+if ( s_f )
+ printf ("c length of arcs from artifical source -> min: %ld max: %ld\n",
+ sm, sl );
+if ( p_f )
+ {
+ printf ("c potentials -> min: %ld max: %ld k1: %.2f k2: %.2f\n",
+ pm, pl, pn, ps );
+ if ( pa_f )
+ printf ("c potentials -> part of alternative distribution: %.2f k: %.2f\n",
+ pap, pac );
+ }
+printf ("c\n" );
+
+printf ("p sp %8ld %8ld\nc\n", n0, m0 );
+
+source = ( s_f ) ? n0 : 1;
+printf ("n %8ld\nc\n", source );
+
+
+if ( p_f ) /* generating potentials */
+ {
+ seed1 = 2*seed + 1;
+ p = (long*) calloc ( n+2, sizeof (long) );
+ init_rand ( seed1);
+ pl = pl - pm + 1;
+
+ for ( i = 0; i <= n; i ++ )
+ {
+ p_t = pm + nrand ( pl );
+ if ( pn_f ) p_t += (long) ( i * pn );
+ if ( ps_f ) p_t += (long) ( i * ( i * ps ));
+ if ( pap_f )
+ if ( rand01() < pap )
+ p_t = (long) ( p_t * pac );
+ p[i] = p_t;
+ }
+ p[n+1] = 0;
+ }
+
+
+if ( s_f ) /* additional arcs from artifical source */
+ {
+ seed2 = 3*seed + 1;
+ init_rand ( seed2 );
+ sl = sl - sm + 1;
+
+ for ( i = n; i > 1; i -- )
+ {
+ s = sm + nrand ( sl );
+ PRINT_ARC ( n0, i, s )
+ }
+
+ PRINT_ARC ( n0, 1, 0 )
+ }
+
+/* initialize random number generator */
+init_rand ( seed );
+ll = ll - lm + 1;
+
+/* generating connecting path(s) */
+for ( i = 1; i < n; i ++ )
+ {
+ if ( ( (i-1) % ch ) != 0 )
+ i0 = i;
+ else
+ i0 = 1;
+
+ if (c_rand)
+ cl = lm + nrand(ll);
+ PRINT_ARC ( i0, i+1, cl )
+ }
+
+/* generating random arcs */
+
+
+for ( k = 1; k <= m - mc; k ++ )
+ {
+ i = 1 + nrand ( n );
+
+ do
+ j = 1 + nrand ( n );
+ while ( j == i );
+
+ if ( i > j )
+ { i0 = i; i = j; j = i0; }
+
+ dij = j - i;
+ l = lm + nrand ( ll );
+ if ( ln_f ) l += (long) ( dij * ln );
+ if ( ls_f ) l += (long) ( dij * ( dij * ls ) );
+ PRINT_ARC ( i, j, l );
+ }
+
+/* all is done */
+exit (ext);
+
+/* ----- wrong usage ----- */
+
+ usage:
+fprintf ( stderr,
+"\nusage: %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\
+help: %s -h\n\n", argv[0], argv[0] );
+
+if ( np > 0 )
+ fprintf ( stderr, "error in parameter # %d\n\n", np );
+exit (4);
+
+/* ---- help ---- */
+
+ help:
+
+if ( args[2] == 'h') goto hhelp;
+
+fprintf ( stderr,
+"\n'%s' - acyclic network generator for shortest paths problem.\n\
+Generates problems in extended DIMACS format.\n\
+\n\
+ %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\
+ %s -hh\n\
+\n\
+ #i - integer number #f - real number\n\
+\n\
+-ll#i - #i is the upper bound on arc lengths (default 10000)\n\
+-lm#i - #i is the lower bound on arc lengths (default 0)\n\
+-cl#i - #i is length of arcs in connecting path(s) (default random)\n\
+-p - generate potentials \n\
+-pl#i - #i is the upper bound on potentials (default ll)\n\
+-pm#i - #i is the lower bound on potentials (default lm)\n\
+\n\
+-hh - extended help \n\n",
+argv[0], argv[0], argv[0] );
+
+exit (0);
+
+/* --------- sophisticated help ------------ */
+ hhelp:
+
+if ( argc < 3 )
+ fout = stderr;
+else
+ fout = fopen ( argv[2], "w" );
+
+if ( fout == NULL )
+{ fprintf ( stderr, "\nCan't open file '%s' for writing help\n\n", argv[2] );
+ exit ( 2 );
+}
+
+fprintf (fout,
+"\n'%s' - acyclic network generator for shortest paths problem.\n\
+Generates problems in extended DIMACS format.\n\
+\n\
+ %s n m seed [ -ll#i -lm#i -ln#f -ls#f\n\
+ -p -pl#i -pm#i -pn#f -ps#f -pap#i -pac#f\n\
+ -cl#i -ch#i\n\
+ -s -sl#i -sm#i\n\
+ ]\n\
+ %s -hh file_name\n\
+\n\
+ #i - integer number #f - real number\n\
+\n\
+ Arc length parameters:\n\
+-ll#i - #i is the upper bound on arc lengths (default 10000)\n\
+-lm#i - #i is the lower bound on arc lengths (default 0)\n\
+-ln#f - multipliy l(i, j) by #f * |i-j| (default 0)\n\
+-ls#f - multipliy l(i, j) by #f * |i-j|^2 (default 0)\n\
+\n\
+ Potential parameters:\n\
+-p - generate potentials \n\
+-pl#i - #i is the upper bound on potentials (default ll)\n\
+-pm#i - #i is the lower bound on potentials (default lm)\n\
+-pn#f - multiply p(i) by #f * i (default 0)\n\
+-ps#f - multiply p(i) by #f * i^2 (default 0)\n\
+-pap#i - percentage of alternative potential nodes (default 0)\n\
+-pac#f - if i is alternative, multiply p(i) by #f (default -1)\n\
+\n\
+ Connecting path(s) parameters:\n\
+-cl#i - #i is length of arcs in connecting path(s) (default random)\n\
+-ch#i - #i is length of connecting path(s) (default n-1)\n\
+\n\
+ Artificial source parameters:\n\
+-s - generate artificial source with default connecting arc lengths\n\
+-sl#i - #i is the upper bound on art. arc lengths (default 100000000)\n\
+-sm#i - #i is the lower bound on art. arc lengths (default sl)\n\
+\n\
+-hh file_name - save this help in the file 'file_name'\n\n",
+argv[0], argv[0], argv[0] );
+
+exit (0);
+}
+
+
+
diff --git a/isisd/topology/spgrid.c b/isisd/topology/spgrid.c
new file mode 100644
index 00000000..22d3a804
--- /dev/null
+++ b/isisd/topology/spgrid.c
@@ -0,0 +1,729 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <values.h>
+
+#include "random.c"
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "vty.h"
+#include "log.h"
+#include "linklist.h"
+
+#include "spgrid.h"
+
+
+#define DASH '-'
+#define VERY_FAR 100000000
+
+#define DOUBLE_CYCLE 0
+#define CYCLE 1
+#define PATH 2
+
+#define NO 0
+#define YES 1
+
+#define NODE( x, y ) (x*Y + y + 1)
+
+char *graph_type[] = {
+ "double cycle",
+ "cycle",
+ "path"
+};
+
+struct arc *arc;
+
+char args[30];
+
+long X, /* horizontal size of grid */
+ Y; /* vertical size of grid */
+
+long x,
+ y,
+ y1, y2, yp,
+ dl, dx, xn, yn, count,
+ *mess;
+
+double n;
+long n0,
+ source,
+ i,
+ i0,
+ j,
+ dij;
+
+double m;
+long m0,
+ mc,
+ k;
+
+long *p,
+ p_t,
+ l,
+ lx;
+
+long seed,
+ seed1,
+ seed2;
+
+int ext=0;
+
+/* initialized by default values */
+
+/* variables for generating one layer */
+
+/* variables for generating spanning graph */
+int c_f = 0, cw_f = 0, cm_f = 0, cl_f = 0;
+
+int cw = DOUBLE_CYCLE; /* type of spanning graph */
+long cm = 0, /* lower bound of the interval */
+ cl = 100; /* upper bound of the interval */
+
+/* variables for generating additional arcs */
+int a_f = 0, ax_f = 0, am_f = 0, al_f = 0;
+
+long ax = 0, /* number of additional arcs */
+ am = 0, /* lower bound of the interval */
+ al = 100; /* upper bound of the interval */
+
+/* variables for inter-layer arcs */
+int i_f = 0, ip_f = 0, ix_f = 0, ih_f = 0,
+ im_f = 0, il_f = 0, in_f = 0, is_f = 0;
+
+int ip = NO; /* to mess or not to mess */
+long ix = 1, /* number of interlayered arcs in a NODE */
+ ih = 1, /* step between two layeres */
+ il = 10000, /* upper bound of the interval */
+ im = 1000; /* lower bound of the interval */
+double in = 1, /* l *= in * |x1-x2| */
+ is = 0; /* l *= is * |x1-x2|^2 */
+
+/* variables for artifical source */
+int s_f = 0, sl_f = 0, sm_f = 0;
+long sl = VERY_FAR, /* upper bound of artifical arc */
+ sm, /* lower bound of artifical arc */
+ s;
+
+/* variables for potentials */
+int p_f = 0, pl_f = 0, pm_f = 0, pn_f = 0, ps_f = 0;
+
+long pl, /* upper bound of the interval */
+ pm; /* lower bound of the interval */
+double pn = 0, /* p += ln * (x+1) */
+ ps = 0; /* p += ls * (x+1)^2 */
+
+int np; /* number of parameter parsing now */
+
+
+void
+free_arc (void *val) {
+ free(val);
+}
+
+void
+print_arc (struct vty *vty, struct list *topology, long i, long j, long length)
+{
+ struct arc *myarc;
+
+ l = length;
+ if ( p_f ) l += ( p[i] - p[j] );
+// vty_out (vty,"a %8ld %8ld %12ld%s", i, j, l ,VTY_NEWLINE);
+ myarc = malloc (sizeof(struct arc));
+ myarc->from_node = i;
+ myarc->to_node = j;
+ myarc->distance = l;
+ topology->del = free_arc;
+ listnode_add (topology, myarc);
+}
+
+/* ---- help ---- */
+void
+help (struct vty *vty) {
+// if ( args[2] == 'h') hhelp (vty);
+ vty_out (vty,"grid network generator for shortest paths problem.%s",VTY_NEWLINE);
+ vty_out (vty,"Generates problems in extended DIMACS format.%s",VTY_NEWLINE);
+ vty_out (vty,"X Y seed [ -cl#i -cm#i -c{c|d|p} -ip -il#i -im#i -p -pl#i -pm#i... ]%s",VTY_NEWLINE);
+ vty_out (vty,"#i - integer number%s",VTY_NEWLINE);
+ vty_out (vty,"-cl#i - #i is the upper bound on layer arc lengths (default 100)%s",VTY_NEWLINE);
+ vty_out (vty,"-cm#i - #i is the lower bound on layer arc lengths (default 0)%s",VTY_NEWLINE);
+ vty_out (vty,"-c#t - #t is the type of connecting graph: { c | d | p }%s",VTY_NEWLINE);
+ vty_out (vty," c - cycle, d - double cycle, p - path (default d)%s",VTY_NEWLINE);
+ vty_out (vty,"-ip - shuffle inter-layer arcs (default NO)%s",VTY_NEWLINE);
+ vty_out (vty,"-il#i - #i is the upper bound on inter-layer arc lengths (default 10000)%s",VTY_NEWLINE);
+ vty_out (vty,"-im#i - #i is the lower bound on inter-layer arc lengths (default 1000)%s",VTY_NEWLINE);
+ vty_out (vty,"-p - generate potentials%s",VTY_NEWLINE);
+ vty_out (vty,"-pl#i - #i is the upper bound on potentials (default il)%s",VTY_NEWLINE);
+ vty_out (vty,"-pm#i - #i is the lower bound on potentials (default im)%s",VTY_NEWLINE);
+ vty_out (vty,"%s",VTY_NEWLINE);
+ vty_out (vty,"-hh - extended help%s",VTY_NEWLINE);
+}
+
+/* --------- sophisticated help ------------ */
+void
+hhelp (struct vty *vty) {
+/*
+zlog_info (
+"\n'%s' - grid network generator for shortest paths problem.\n\
+Generates problems in extended DIMACS format.\n\
+\n\
+ %s X Y seed [ -cl#i -cm#i -c{c|d|p}\n\
+ -ax#i -al#i -am#i\n\
+ -ip -il#i -im#i -in#i -is#i -ix#i -ih#i\n\
+ -p -pl#i -pm#i -pn#f -ps#f\n\
+ -s -sl#i -sm#i\n\
+ ]\n\
+ %s -hh file_name\n\
+\n\
+ #i - integer number #f - real number\n\
+\n\
+ Parameters of connecting arcs within one layer:\n\
+-cl#i - #i is the upper bound on arc lengths (default 100)\n\
+-cm#i - #i is the lower bound on arc lengths (default 0)\n\
+-c#t - #t is the type of connecting graph: { c | d | p }\n\
+ c - cycle, d - double cycle, p - path (default d)\n\
+\n\
+ Parameters of additional arcs within one layer:\n\
+-ax#i - #i is the number of additional arcs (default 0)\n\
+-al#i - #i is the upper bound on arc lengths (default 100)\n\
+-am#i - #i is the lower bound on arc lengths (default 0)\n\
+\n\
+ Interlayerd arc parameters:\n\
+-ip - shuffle inter-layer arcs (default NO)\n\
+-il#i - #i is the upper bound on arc lengths (default 10000)\n\
+-im#i - #i is the lower bound on arc lengths (default 1000)\n\
+-in#f - multiply l(i, j) by #f * x(j)-x(i) (default 1)\n\
+ if #f=0 - don't multiply\n\
+-is#f - multiply l(i, j) by #f * (x(j)-x(i))^2 (default NO)\n\
+-ix#i - #i - is the number of arcs from a node (default 1)\n\
+-ih#i - #i - is the step between connected layers (default 1)\n\
+\n\
+ Potential parameters:\n\
+-p - generate potentials \n\
+-pl#i - #i is the upper bound on potentials (default ll)\n\
+-pm#i - #i is the lower bound on potentials (default lm)\n\
+-pn#f - multiply p(i) by #f * x(i) (default NO)\n\
+-ps#f - multiply p(i) by #f * x(i)^2 (default NO)\n\
+\n");
+zlog_info (
+" Artificial source parameters:\n\
+-s - generate artificial source with default connecting arc lengths\n\
+-sl#i - #i is the upper bound on art. arc lengths (default 100000000)\n\
+-sm#i - #i is the lower bound on art. arc lengths (default sl)\n\"
+);*/
+}
+
+/* ----- wrong usage ----- */
+void
+usage (struct vty *vty) {
+ vty_out (vty,"usage: X Y seed [-ll#i -lm#i -cl#i -p -pl#i -pm#i ...]%s",VTY_NEWLINE);
+ vty_out (vty,"help: -h or -hh%s",VTY_NEWLINE);
+
+ if ( np > 0 )
+ zlog_err ("error in parameter # %d\n\n", np );
+}
+
+
+/* parsing parameters */
+/* checks the validity of incoming parameters */
+int
+spgrid_check_params ( struct vty *vty, int argc, char **argv)
+{
+/* initialized by default values */
+ ext=0;
+
+/* variables for generating one layer */
+
+/* variables for generating spanning graph */
+ c_f = 0;
+ cw_f = 0;
+ cm_f = 0;
+ cl_f = 0;
+
+ cw = PATH; /* type of spanning graph */
+ cm = 0; /* lower bound of the interval */
+ cl = 63; /* upper bound of the interval */
+
+/* variables for generating additional arcs */
+ a_f = 0;
+ ax_f = 0;
+ am_f = 0;
+ al_f = 0;
+
+ ax = 0; /* number of additional arcs */
+ am = 0; /* lower bound of the interval */
+ al = 63; /* upper bound of the interval */
+
+/* variables for inter-layer arcs */
+ i_f = 0;
+ ip_f = 0;
+ ix_f = 0;
+ ih_f = 0;
+ im_f = 0;
+ il_f = 0;
+ in_f = 0;
+ is_f = 0;
+
+ ip = NO; /* to mess or not to mess */
+ ix = 1; /* number of interlayered arcs in a NODE */
+ ih = 1; /* step between two layeres */
+ il = 63; //was 10000; /* upper bound of the interval */
+ im = 0; //was 1000; /* lower bound of the interval */
+ in = 1; /* l *= in * |x1-x2| */
+ is = 0; /* l *= is * |x1-x2|^2 */
+
+/* variables for artifical source */
+ s_f = 0;
+ sl_f = 0;
+ sm_f = 0;
+ sl = VERY_FAR; /* upper bound of artifical arc */
+
+/* variables for potentials */
+ p_f = 0;
+ pl_f = 0;
+ pm_f = 0;
+ pn_f = 0;
+ ps_f = 0;
+
+ pn = 0; /* p += ln * (x+1) */
+ ps = 0; /* p += ls * (x+1)^2 */
+
+
+ if ( argc < 1 ) {
+ usage (vty);
+ return 1;
+ }
+
+ np = 0;
+
+ strcpy ( args, argv[0] );
+
+ if ((args[0] == DASH) && (args[1] == 'h'))
+ help (vty);
+
+ if ( argc < 3 ) {
+ usage (vty);
+ return 1;
+ }
+
+ /* first parameter - horizontal size */
+ np = 1;
+ if ( ( X = atoi ( argv[0] ) ) < 1 ) {
+ usage (vty);
+ return 1;
+ }
+
+ /* second parameter - vertical size */
+ np = 2;
+ if ( ( Y = atoi ( argv[1] ) ) < 1 ) {
+ usage (vty);
+ return 1;
+ }
+
+ /* third parameter - seed */
+ np=3;
+ if ( ( seed = atoi ( argv[2] ) ) <= 0 ) {
+ usage (vty);
+ return 1;
+ }
+
+ /* other parameters */
+ for ( np = 3; np < argc; np ++ ) {
+ strcpy ( args, argv[np] );
+ if ( args[0] != DASH ) {
+ usage (vty);
+ return 1;
+ }
+
+ switch ( args[1] ) {
+ case 'c' : /* spanning graph in one layer */
+ c_f = 1;
+ switch ( args[2] ) {
+ case 'l': /* upper bound of the interval */
+ cl_f = 1;
+ cl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound */
+ cm_f = 1;
+ cm = (long ) atof ( &args[3] );
+ break;
+ case 'c': /* type - cycle */
+ cw_f = 1;
+ cw = CYCLE;
+ break;
+ case 'd': /* type - double cycle */
+ cw_f = 1;
+ cw = DOUBLE_CYCLE;
+ break;
+ case 'p': /* type - path */
+ cw_f = 1;
+ cw = PATH;
+ break;
+
+ default: /* unknown switch value */
+ usage (vty);
+ return 1;
+ }
+ break;
+
+ case 'a' : /* additional arcs in one layer */
+ a_f = 1;
+ switch ( args[2] )
+ {
+ case 'l': /* upper bound of the interval */
+ al_f = 1;
+ al = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound */
+ am_f = 1;
+ am = (long ) atof ( &args[3] );
+ break;
+ case 'x': /* number of additional arcs */
+ ax_f = 1;
+ ax = (long ) atof ( &args[3] );
+ if ( ax < 0 )
+ {
+ usage (vty);
+ return 1;
+ }
+ break;
+
+ default: /* unknown switch value */
+ {
+ usage (vty);
+ return 1;
+ }
+ }
+ break;
+
+
+ case 'i' : /* interlayered arcs */
+ i_f = 1;
+
+ switch ( args[2] )
+ {
+ case 'l': /* upper bound */
+ il_f = 1;
+ il = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound */
+ im_f = 1;
+ im = (long ) atof ( &args[3] );
+ break;
+ case 'n': /* additional length: l *= in*|i1-i2| */
+ in_f = 1;
+ in = atof ( &args[3] );
+ break;
+ case 's': /* additional length: l *= is*|i1-i2|^2 */
+ is_f = 1;
+ is = atof ( &args[3] );
+ break;
+ case 'p': /* mess interlayered arcs */
+ ip_f = 1;
+ ip = YES;
+ break;
+ case 'x': /* number of interlayered arcs */
+ ix_f = 1;
+ ix = atof ( &args[3] );
+ if ( ix < 1 ) {
+ usage (vty);
+ return 1;
+ }
+ break;
+ case 'h': /* step between two layeres */
+ ih_f = 1;
+ ih = atof ( &args[3] );
+ if ( ih < 1 ) {
+ usage (vty);
+ return 1;
+ }
+ break;
+ default: /* unknown switch value */
+ usage (vty);
+ return 1;
+ }
+ break;
+
+ case 's' : /* additional source */
+ s_f = 1;
+ if ( strlen ( args ) > 2 )
+ {
+ switch ( args[2] )
+ {
+ case 'l': /* upper bound of art. arc */
+ sl_f = 1;
+ sl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound of art. arc */
+ sm_f = 1;
+ sm = (long) atof ( &args[3] );
+ break;
+ default: /* unknown switch value */
+ usage (vty);
+ return 1;
+ }
+ }
+ break;
+
+ case 'p' : /* potentials */
+ p_f = 1;
+ if ( strlen ( args ) > 2 )
+ {
+ switch ( args[2] )
+ {
+ case 'l': /* upper bound */
+ pl_f = 1;
+ pl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound */
+ pm_f = 1;
+ pm = (long ) atof ( &args[3] );
+ break;
+ case 'n': /* additional: p *= pn*(x+1) */
+ pn_f = 1;
+ pn = atof ( &args[3] );
+ break;
+ case 's': /* additional: p = ps* (x+1)^2 */
+ ps_f = 1;
+ ps = atof ( &args[3] );
+ break;
+ default: /* unknown switch value */
+ usage (vty);
+ return 1;
+ }
+ }
+ break;
+
+ default: /* unknoun case */
+ usage (vty);
+ return 1;
+ }
+ }
+
+
+ return 0;
+}
+
+
+/* generator of layered networks for the shortest paths problem;
+ extended DIMACS format for output */
+int
+gen_spgrid_topology (struct vty *vty, struct list *topology)
+{
+ /* ----- ajusting parameters ----- */
+
+ /* spanning */
+ if ( cl < cm ) { lx = cl; cl = cm; cm = lx; }
+
+ /* additional arcs */
+ if ( al < am ) { lx = al; al = am; am = lx; }
+
+ /* interlayered arcs */
+ if ( il < im ) { lx = il; il = im; im = lx; }
+
+ /* potential parameters */
+ if ( p_f )
+ {
+ if ( ! pl_f ) pl = il;
+ if ( ! pm_f ) pm = im;
+ if ( pl < pm ) { lx = pl; pl = pm; pm = lx; }
+ }
+
+ /* number of nodes and arcs */
+
+ n = (double)X *(double)Y + 1;
+
+ m = (double)Y; /* arcs from source */
+
+ switch ( cw )
+ {
+ case PATH:
+ mc = (double)Y - 1;
+ break;
+ case CYCLE:
+ mc = (double)Y;
+ break;
+ case DOUBLE_CYCLE:
+ mc = 2*(double)Y;
+ }
+
+ m += (double)X * (double)mc; /* spanning arcs */
+ m += (double)X * (double)ax; /* additional arcs */
+
+ /* interlayered arcs */
+ for ( x = 0; x < X; x ++ )
+ {
+ dl = ( ( X - x - 1 ) + ( ih - 1 ) ) / ih;
+ if ( dl > ix ) dl = ix;
+ m += (double)Y * (double)dl;
+ }
+
+ /* artifical source parameters */
+ if ( s_f ) {
+ m += n; n ++ ;
+ if ( ! sm_f ) sm = sl;
+ if ( sl < sm ) { lx = sl; sl = sm; sm = lx; }
+ }
+
+ if ( n >= (double)MAXLONG || m >= (double)MAXLONG )
+ {
+ zlog_err ("Too large problem. It can't be generated\n");
+ exit (4);
+ }
+ else
+ {
+ n0 = (long)n; m0 = (long)m;
+ }
+
+ if ( ip_f )
+ mess = (long*) calloc ( Y, sizeof ( long ) );
+
+ /* printing title */
+ zlog_info ("Generating topology for ISIS");
+
+ source = ( s_f ) ? n0-1 : n0;
+
+ if ( p_f ) /* generating potentials */ {
+ p = (long*) calloc ( n0+1, sizeof (long) );
+ seed1 = 2*seed + 1;
+ init_rand ( seed1);
+ pl = pl - pm + 1;
+
+ for ( x = 0; x < X; x ++ )
+ for ( y = 0; y < Y; y ++ ) {
+ p_t = pm + nrand ( pl );
+ if ( pn_f ) p_t *= (long) ( (1 + x) * pn );
+ if ( ps_f ) p_t *= (long) ( (1 + x) * ( (1 + x) * ps ));
+
+ p[ NODE ( x, y ) ] = p_t;
+ }
+ p[n0] = 0;
+ if ( s_f ) p[n0-1] = 0;
+ }
+
+ if ( s_f ) /* additional arcs from artifical source */
+ {
+ seed2 = 3*seed + 1;
+ init_rand ( seed2 );
+ sl = sl - sm + 1;
+
+ for ( x = X - 1; x >= 0; x -- )
+ for ( y = Y - 1; y >= 0; y -- )
+ {
+ i = NODE ( x, y );
+ s = sm + nrand ( sl );
+ print_arc (vty, topology, n0, i, s );
+ }
+
+ print_arc (vty, topology, n0, n0-1, 0 );
+ }
+
+
+ /* ----- generating arcs within layers ----- */
+
+ init_rand ( seed );
+ cl = cl - cm + 1;
+ al = al - am + 1;
+
+ for ( x = 0; x < X; x ++ )
+ {
+ /* generating arcs within one layer */
+ for ( y = 0; y < Y-1; y ++ )
+ {
+ /* generating spanning graph */
+ i = NODE ( x, y );
+ j = NODE ( x, y+1 );
+ l = cm + nrand ( cl );
+ print_arc (vty, topology, i, j, l );
+
+ if ( cw == DOUBLE_CYCLE )
+ {
+ l = cm + nrand ( cl );
+ print_arc (vty, topology, j, i, l );
+ }
+ }
+
+ if ( cw <= CYCLE )
+ {
+ i = NODE ( x, Y-1 );
+ j = NODE ( x, 0 );
+ l = cm + nrand ( cl );
+ print_arc (vty, topology, i, j, l );
+
+ if ( cw == DOUBLE_CYCLE )
+ {
+ l = cm + nrand ( cl );
+ print_arc (vty, topology, j, i, l );
+ }
+ }
+
+ /* generating additional arcs */
+
+ for ( k = ax; k > 0; k -- )
+ {
+ y1 = nrand ( Y );
+ do
+ y2 = nrand ( Y );
+ while ( y2 == y1 );
+ i = NODE ( x, y1 );
+ j = NODE ( x, y2 );
+ l = am + nrand ( al );
+ print_arc (vty, topology, i, j, l );
+ }
+ }
+
+ /* ----- generating interlayered arcs ------ */
+
+ il = il - im + 1;
+
+ /* arcs from the source */
+
+ for ( y = 0; y < Y; y ++ )
+ {
+ l = im + nrand ( il );
+ i = NODE ( 0, y );
+ print_arc (vty, topology, source, i, l );
+ }
+
+ for ( x = 0; x < X-1; x ++ )
+ {
+ /* generating arcs from one layer */
+ for ( count = 0, xn = x + 1;
+ count < ix && xn < X;
+ count ++, xn += ih )
+ {
+ if ( ip_f )
+ for ( y = 0; y < Y; y ++ )
+ mess[y] = y;
+
+ for ( y = 0; y < Y; y ++ )
+ {
+ i = NODE ( x, y );
+ dx = xn - x;
+ if ( ip_f )
+ {
+ yp = nrand(Y-y);
+ yn = mess[ yp ];
+ mess[ yp ] = mess[ Y - y - 1 ];
+ }
+ else
+ yn = y;
+ j = NODE ( xn, yn );
+ l = im + nrand ( il );
+ if ( in != 0 )
+ l *= (long) ( in * dx );
+ if ( is_f )
+ l *= (long) ( ( is * dx ) * dx );
+ print_arc (vty, topology, i, j, l );
+ }
+ }
+ }
+ /* all is done */
+ return ext;
+
+return 0;
+}
+
+
+
diff --git a/isisd/topology/spgrid.h b/isisd/topology/spgrid.h
new file mode 100644
index 00000000..f96c00f3
--- /dev/null
+++ b/isisd/topology/spgrid.h
@@ -0,0 +1,45 @@
+/*
+ * IS-IS Rout(e)ing protocol - topology/spgrid.h
+ Routines for manipulation of SSN and SRM flags
+ * Copyright (C) 2001 Sampo Saaristo, Ofer Wald
+ *
+ * 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.
+ */
+
+/*
+ * Based on:
+ * SPLIB Copyright C 1994 by Cherkassky, Goldberg, and Radzik
+ *
+ */
+#ifndef _ZEBRA_ISIS_TOPOLOGY_SPGRID_H
+#define _ZEBRA_ISIS_TOPOLOGY_SPGRID_H
+
+struct arc {
+ long from_node;
+ long to_node;
+ long distance;
+};
+
+int gen_spgrid_topology (struct vty *vty, struct list *topology);
+int spgrid_check_params (struct vty *vty, int argc, char **argv);
+
+
+#endif /* _ZEBRA_ISIS_TOPOLOGY_SPGRID_H */
+
+
+
+
+
+
diff --git a/isisd/topology/sprand.c b/isisd/topology/sprand.c
new file mode 100644
index 00000000..28b58b30
--- /dev/null
+++ b/isisd/topology/sprand.c
@@ -0,0 +1,499 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <values.h>
+
+#include "random.c"
+
+#define DASH '-'
+#define VERY_FAR 100000000
+
+/* generator of random networks for the shortest paths problem;
+ extended DIMACS format for output */
+
+main ( argc, argv )
+
+int argc;
+char* argv[];
+
+{
+
+char args[30];
+
+long n,
+ n0,
+ source,
+ i,
+ i0,
+ j,
+ dij;
+
+long m,
+ m0,
+ mc,
+ k;
+
+long *p,
+ p_t,
+ l,
+ lx;
+
+long seed,
+ seed1,
+ seed2;
+
+int ext=0;
+
+FILE *fout;
+
+/* variables for lengths generating */
+/* initialized by default values */
+int l_f = 0, ll_f = 0, lm_f = 0, ln_f = 0, ls_f = 0;
+long ll = 10000, /* length of the interval */
+ lm = 0; /* minimal bound of the interval */
+double ln = 0, /* l += ln * |i-j| */
+ ls = 0; /* l += ls * |i-j|^2 */
+
+/* variables for connecting cycle(s) */
+int c_f = 0, cl_f = 0, ch_f = 0, c_random = 1;
+long cl = 1; /* length of cycle arc */
+long ch; /* number of arcs in the cycle
+ n - by default */
+
+/* variables for artifical source */
+int s_f = 0, sl_f = 0, sm_f = 0;
+long sl = VERY_FAR, /* upper bound of artifical arc */
+ sm, /* lower bound of artifical arc */
+ s;
+
+/* variables for potentials */
+int p_f = 0, pl_f = 0, pm_f = 0, pn_f = 0, ps_f = 0,
+ pa_f = 0, pap_f = 0, pac_f = 0;
+long pl, /* length of the interval */
+ pm; /* minimal bound of the interval */
+double pn = 0, /* l += ln * |i-j| */
+ ps = 0, /* l += ls * |i-j|^2 */
+ pap = 0, /* part of nodes with alternative dustribution */
+ pac = -1; /* multiplier for alternative distribution */
+
+int np; /* number of parameter parsing now */
+
+#define PRINT_ARC( i, j, length )\
+{\
+l = length;\
+if ( p_f ) l += ( p[i] - p[j] );\
+printf ("a %8ld %8ld %12ld\n", i, j, l );\
+}
+
+ /* parsing parameters */
+
+if ( argc < 2 ) goto usage;
+
+np = 0;
+
+strcpy ( args, argv[1] );
+
+ if ( ( args[0] == DASH ) && ( args[1] == 'h')
+ )
+ goto help;
+
+if ( argc < 4 ) goto usage;
+
+/* first parameter - number of nodes */
+np = 1;
+if ( ( n = atoi ( argv[1] ) ) < 2 ) goto usage;
+
+/* second parameter - number of arcs */
+np = 2;
+if ( ( m = atoi ( argv[2] ) ) < n ) goto usage;
+
+/* third parameter - seed */
+np=3;
+if ( ( seed = atoi ( argv[3] ) ) <= 0 ) goto usage;
+
+/* other parameters */
+
+for ( np = 4; np < argc; np ++ )
+ {
+ strcpy ( args, argv[np] );
+ if ( args[0] != DASH ) goto usage;
+
+ switch ( args[1] )
+ {
+
+ case 'l' : /* an interval for arc length */
+ l_f = 1;
+ switch ( args[2] )
+ {
+ case 'l': /* length of the interval */
+ ll_f = 1;
+ ll = (long) atof ( &args[3] );
+ break;
+ case 'm': /* minimal bound */
+ lm_f = 1;
+ lm = (long ) atof ( &args[3] );
+ break;
+ case 'n': /* additional length: l*|i-j| */
+ ln_f = 1;
+ ln = atof ( &args[3] );
+ break;
+ case 's': /* additional length: l*|i-j|^2 */
+ ls_f = 1;
+ ls = atof ( &args[3] );
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ break;
+
+ case 'c' : /* connecting cycle(s) */
+ c_f = 1;
+ switch ( args[2] )
+ {
+ case 'l':
+ c_random = 0;
+ cl_f = 1;
+ cl = (long) atof ( &args[3] );
+ if ( cl < 0 ) goto usage;
+ break;
+ case 'h':
+ ch_f = 1;
+ ch = (long) atof ( &args[3] );
+ if ( ch < 2 || ch > n ) goto usage;
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ break;
+
+ case 's' : /* additional source */
+ s_f = 1;
+ if ( strlen ( args ) > 2 )
+ {
+ switch ( args[2] )
+ {
+ case 'l': /* upper bound of art. arc */
+ sl_f = 1;
+ sl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* lower bound of art. arc */
+ sm_f = 1;
+ sm = (long) atof ( &args[3] );
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ }
+ break;
+
+ case 'p' : /* potentials */
+ p_f = 1;
+ if ( strlen ( args ) > 2 )
+ {
+ switch ( args[2] )
+ {
+ case 'l': /* length of the interval */
+ pl_f = 1;
+ pl = (long) atof ( &args[3] );
+ break;
+ case 'm': /* minimal bound */
+ pm_f = 1;
+ pm = (long ) atof ( &args[3] );
+ break;
+ case 'n': /* additional length: l*|i-j| */
+ pn_f = 1;
+ pn = atof ( &args[3] );
+ break;
+ case 's': /* additional length: l*|i-j|^2 */
+ ps_f = 1;
+ ps = atof ( &args[3] );
+ break;
+ case 'a': /* bipolar distribution */
+ pa_f = 1;
+ switch ( args[3] )
+ {
+ case 'p': /* % of alternative potentials */
+ pap_f = 1;
+ pap = atof ( &args[4] );
+ if ( pap < 0 ) pap = 0;
+ if ( pap > 100 ) pap = 100;
+ pap /= 100;
+ break;
+ case 'c': /* multiplier */
+ pac_f = 1;
+ pac = atof ( &args[4] );
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ break;
+ default: /* unknown switch value */
+ goto usage;
+ }
+ }
+ break;
+
+ default : /* unknoun case */
+ goto usage;
+ }
+ }
+
+
+/* ----- ajusting parameters ----- */
+
+n0 = n; m0 = m;
+
+/* length parameters */
+if ( ll < lm ) { lx = ll; ll = lm; lm = lx; }
+
+/* potential parameters */
+if ( p_f )
+ {
+ if ( ! pl_f ) pl = ll;
+ if ( ! pm_f ) pm = lm;
+ if ( pl < pm ) { lx = pl; pl = pm; pm = lx; }
+ }
+
+/* path(s) parameters */
+if ( ! ch_f ) ch = n;
+
+mc = n + (n-2) / (ch-1);
+if ( mc > m )
+ { fprintf ( stderr,
+ "Error: not enough arcs for generating connecting cycle(s)\n" );
+ exit (4);
+ }
+
+ /* artifical source parameters */
+if ( s_f )
+ { m0 += n; n0 ++ ;
+ if ( ! sm_f ) sm = sl;
+ if ( sl < sm ) { lx = sl; sl = sm; sm = lx; }
+ }
+
+/* printing title */
+printf ("c random network for shortest paths problem\n");
+printf ("c extended DIMACS format\nc\n" );
+
+/* name of the problem */
+printf ("t rd_%ld_%ld_%ld_", n, m, seed );
+if ( l_f )
+ printf ("%c", 'l');
+if ( c_f )
+ printf ("%c", 'c');
+if ( s_f )
+ printf ("%c", 's');
+if ( p_f )
+ printf ("%c", 'p');
+printf ("\nc\n");
+
+/* printing additional information */
+if ( l_f )
+ printf ("c length -> min: %ld max: %ld k1: %.2f k2: %.2f\n",
+ lm, ll, ln, ls );
+if ( c_f )
+ {
+ if ( c_random )
+ printf ("c cycle -> number of arcs: %ld arc length: random\n", ch);
+ else
+ printf ("c cycle -> number of arcs: %ld arc length: %ld\n",
+ ch, cl );
+ }
+if ( s_f )
+ printf ("c length of arcs from artifical source -> min: %ld max: %ld\n",
+ sm, sl );
+if ( p_f )
+ {
+ printf ("c potentials -> min: %ld max: %ld k1: %.2f k2: %.2f\n",
+ pm, pl, pn, ps );
+ if ( pa_f )
+ printf ("c potentials -> part of alternative distribution: %.2f k: %.2f\n",
+ pap, pac );
+ }
+printf ("c\n" );
+
+
+printf ("p sp %8ld %8ld\nc\n", n0, m0 );
+
+source = ( s_f ) ? n0 : 1;
+printf ("n %8ld\nc\n", source );
+
+if ( p_f ) /* generating potentials */
+ {
+ p = (long*) calloc ( n+2, sizeof (long) );
+ seed1 = 2*seed + 1;
+ init_rand ( seed1);
+ pl = pl - pm + 1;
+
+ for ( i = 0; i <= n; i ++ )
+ {
+ p_t = pm + nrand ( pl );
+ if ( pn_f ) p_t += (long) ( i * pn );
+ if ( ps_f ) p_t += (long) ( i * ( i * ps ));
+ if ( pap_f )
+ if ( rand01() < pap )
+ p_t = (long) ( p_t * pac );
+ p[i] = p_t;
+ }
+ p[n+1] = 0;
+ }
+
+
+if ( s_f ) /* additional arcs from artifical source */
+ {
+ seed2 = 3*seed + 1;
+ init_rand ( seed2 );
+ sl = sl - sm + 1;
+
+ for ( i = n; i > 1; i -- )
+ {
+ s = sm + nrand ( sl );
+ PRINT_ARC ( n0, i, s )
+ }
+
+ PRINT_ARC ( n0, 1, 0 )
+ }
+
+/* initialize random number generator */
+init_rand ( seed );
+ll = ll - lm + 1;
+
+/* generating connecting cycle(s) */
+if (c_random)
+ cl = lm + nrand ( ll );
+PRINT_ARC ( 1, 2, cl )
+if (c_random)
+ cl = lm + nrand ( ll );
+PRINT_ARC ( n, 1, cl )
+
+for ( i = 2; i < n; i ++ )
+ {
+ if (c_random)
+ cl = lm + nrand ( ll );
+
+ if ( ( (i-1) % (ch-1) ) != 0 )
+ PRINT_ARC ( i, i+1, cl )
+ else
+ { PRINT_ARC ( i, 1, cl )
+ if (c_random)
+ cl = lm + nrand ( ll );
+ PRINT_ARC ( 1, i+1, cl )
+ }
+ }
+
+/* generating random arcs */
+
+for ( k = 1; k <= m - mc; k ++ )
+ {
+ i = 1 + nrand ( n );
+
+ do
+ j = 1 + nrand ( n );
+ while ( j == i );
+
+ dij = ( i > j ) ? ( i - j ) : ( j - i );
+ l = lm + nrand ( ll );
+ if ( ln_f ) l += (long) ( dij * ln );
+ if ( ls_f ) l += (long) ( dij * ( dij * ls ) );
+ PRINT_ARC ( i, j, l );
+ }
+
+/* all is done */
+exit (ext);
+
+/* ----- wrong usage ----- */
+
+ usage:
+fprintf ( stderr,
+"\nusage: %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\
+help: %s -h\n\n", argv[0], argv[0] );
+
+if ( np > 0 )
+ fprintf ( stderr, "error in parameter # %d\n\n", np );
+exit (4);
+
+/* ---- help ---- */
+
+ help:
+
+if ( args[2] == 'h') goto hhelp;
+
+fprintf ( stderr,
+"\n'%s' - random network generator for shortest paths problem.\n\
+Generates problems in extended DIMACS format.\n\
+\n\
+ %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\
+ %s -hh\n\
+\n\
+ #i - integer number #f - real number\n\
+\n\
+-ll#i - #i is the upper bound on arc lengths (default 10000)\n\
+-lm#i - #i is the lower bound on arc lengths (default 0)\n\
+-cl#i - #i is length of arcs in connecting cycle(s) (default random)\n\
+-p - generate potentials \n\
+-pl#i - #i is the upper bound on potentials (default ll)\n\
+-pm#i - #i is the lower bound on potentials (default lm)\n\
+\n\
+-hh - extended help \n\n",
+argv[0], argv[0], argv[0] );
+
+exit (0);
+
+/* --------- sophisticated help ------------ */
+ hhelp:
+
+if ( argc < 3 )
+ fout = stderr;
+else
+ fout = fopen ( argv[2], "w" );
+
+if ( fout == NULL )
+{ fprintf ( stderr, "\nCan't open file '%s' for writing help\n\n", argv[2] );
+ exit ( 2 );
+}
+
+fprintf (fout,
+"\n'%s' - random network generator for shortest paths problem.\n\
+Generates problems in extended DIMACS format.\n\
+\n\
+ %s n m seed [ -ll#i -lm#i -ln#f -ls#f\n\
+ -p -pl#i -pm#i -pn#f -ps#f -pap#i -pac#f\n\
+ -cl#i -ch#i\n\
+ -s -sl#i -sm#i\n\
+ ]\n\
+ %s -hh file_name\n\
+\n\
+ #i - integer number #f - real number\n\
+\n\
+ Arc length parameters:\n\
+-ll#i - #i is the upper bound on arc lengths (default 10000)\n\
+-lm#i - #i is the lower bound on arc lengths (default 0)\n\
+-ln#f - multipliy l(i, j) by #f * |i-j| (default 0)\n\
+-ls#f - multipliy l(i, j) by #f * |i-j|^2 (default 0)\n\
+\n\
+ Potential parameters:\n\
+-p - generate potentials \n\
+-pl#i - #i is the upper bound on potentials (default ll)\n\
+-pm#i - #i is the lower bound on potentials (default lm)\n\
+-pn#f - multiply p(i) by #f * i (default 0)\n\
+-ps#f - multiply p(i) by #f * i^2 (default 0)\n\
+-pap#i - percentage of alternative potential nodes (default 0)\n\
+-pac#f - if i is alternative, multiply p(i) by #f (default -1)\n\
+\n\
+ Connecting cycle(s) parameters:\n\
+-cl#i - #i is length of arcs in connecting cycle(s) (default random)\n\
+-ch#i - #i is length of connecting cycles (default n)\n\
+\n\
+ Artificial source parameters:\n\
+-s - generate artificial source with default connecting arc lengths\n\
+-sl#i - #i is the upper bound on art. arc lengths (default 100000000)\n\
+-sm#i - #i is the lower bound on art. arc lengths (default sl)\n\
+\n\
+-hh file_name - save this help in the file 'file_name'\n\n",
+argv[0], argv[0], argv[0] );
+
+exit (0);
+}
+
+
+