diff options
| author | jardin <jardin> | 2003-12-23 08:09:43 +0000 | 
|---|---|---|
| committer | jardin <jardin> | 2003-12-23 08:09:43 +0000 | 
| commit | eb5d44eb8dcf25a1b328e57d1eabb1f89e3bc59b (patch) | |
| tree | 2973e8563fcbd4a8cf901d211ff4f8de00c36381 /isisd | |
| parent | 3dbf99698a3be2e920871c3127ea089e061a127c (diff) | |
Initial revision
Diffstat (limited to 'isisd')
76 files changed, 45393 insertions, 0 deletions
diff --git a/isisd/AUTHORS b/isisd/AUTHORS new file mode 100644 index 0000000000..d9f98b22aa --- /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 0000000000..08d6e50ed7 --- /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 0000000000..78580ea1c2 --- /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 0000000000..c9843915d6 --- /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 0000000000..b9a0c7cb44 --- /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 0000000000..46aae735ce --- /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 0000000000..6e2198dcc9 --- /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 0000000000..e3c1352e6d --- /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 0000000000..4c787ac589 --- /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 0000000000..2977a90f34 --- /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 0000000000..6bc3d25721 --- /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 0000000000..ded864e6a6 --- /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 0000000000..714b42d6f8 --- /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 0000000000..8079bd17b5 --- /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 0000000000..5c0772cc43 --- /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 0000000000..f37c314e15 --- /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 0000000000..7163c5b99a --- /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 0000000000..951e6371b1 --- /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 0000000000..c5b59aa30b --- /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 0000000000..2282bbc85c --- /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 0000000000..23cc21508c --- /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 0000000000..5b7d23e6da --- /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 0000000000..73d9cd38c8 --- /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 0000000000..9e151d0aba --- /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 0000000000..2a7f3ec961 --- /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 0000000000..aada395dce --- /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 0000000000..75dd92e8bc --- /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 0000000000..716bee0546 --- /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 0000000000..66b94848da --- /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 0000000000..6bfb0fd40f --- /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 0000000000..71a75089aa --- /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 0000000000..baf5f38d4e --- /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 0000000000..763ae2434f --- /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 0000000000..0e219c658f --- /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 0000000000..d22f3dd8a6 --- /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 0000000000..7633f9e015 --- /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 0000000000..8d636b30c8 --- /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 0000000000..9940368015 --- /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 0000000000..74231adc6e --- /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 0000000000..7137948eb2 --- /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 0000000000..4df983d2b6 --- /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 0000000000..d6949817ac --- /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 0000000000..59e4b6b51e --- /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 0000000000..b51cee91cf --- /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 0000000000..79c0c46f46 --- /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 0000000000..d9179f9144 --- /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 0000000000..fabf720059 --- /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 0000000000..8794a12cc8 --- /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 0000000000..9e08778e8f --- /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 0000000000..67bf8d63bf --- /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 0000000000..d0bb8a75d5 --- /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 0000000000..cf600a86e2 --- /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 0000000000..65ba16bf0f --- /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 0000000000..6e1361788c --- /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 0000000000..0b29953276 --- /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 0000000000..002666ba42 --- /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 0000000000..5c18fd9475 --- /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, ©_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 0000000000..d407c5a9ee --- /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 0000000000..c06839ef4d --- /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 0000000000..e4bf6d4f9e --- /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 0000000000..49b508bc44 --- /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 0000000000..385fb38f1b --- /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 0000000000..8948ea00bf --- /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 0000000000..49ff321395 --- /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 0000000000..d80cdf5f0e --- /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 0000000000..39a7690b1b --- /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 0000000000..af954b838d --- /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 0000000000..c3fac4350a --- /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 0000000000..6de0e0dae4 --- /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 0000000000..989e882d54 --- /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 0000000000..045c15c840 --- /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 0000000000..d4ef995005 --- /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 0000000000..8531447374 --- /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 0000000000..22d3a80419 --- /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 0000000000..f96c00f346 --- /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 0000000000..28b58b30e7 --- /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); +} + + +  | 
