aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2013-01-04 21:55:57 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2013-01-04 21:55:57 -0800
commit1736fa987eb6b66b6eaedbc1cd3df4f48b873721 (patch)
treefab9a0cf0d8a8bfbabf131ae0e3209fed30f98b0
parent96abbc571f9645e14ba9d9faf549ebcb4df40036 (diff)
parent0315bd568b78bcae16e368cfce9311891b05e686 (diff)
downloadandroid_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.tar.gz
android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.tar.bz2
android_external_brctl-1736fa987eb6b66b6eaedbc1cd3df4f48b873721.zip
Merge "Merge remote-tracking branch 'origin/caf/kernel-bridge-utils/master'"
-rw-r--r--.gitignore35
-rw-r--r--AUTHORS2
-rw-r--r--COPYING340
-rw-r--r--ChangeLog133
-rw-r--r--Makefile.in35
-rw-r--r--README45
-rw-r--r--THANKS40
-rw-r--r--TODO30
-rw-r--r--brctl/Makefile.in44
-rw-r--r--brctl/brctl.c87
-rw-r--r--brctl/brctl.h39
-rw-r--r--brctl/brctl_cmd.c493
-rw-r--r--brctl/brctl_disp.c148
-rw-r--r--bridge-utils.spec.in76
-rw-r--r--configure.in27
-rw-r--r--doc/FAQ2
-rw-r--r--doc/FIREWALL38
-rw-r--r--doc/HOWTO105
-rw-r--r--doc/Makefile.in21
-rw-r--r--doc/PROJECTS2
-rw-r--r--doc/RPM-GPG-KEY30
-rw-r--r--doc/SMPNOTES21
-rw-r--r--doc/WISHLIST25
-rw-r--r--doc/brctl.8172
-rwxr-xr-xinstall-sh251
-rw-r--r--libbridge/.gitignore2
-rw-r--r--libbridge/Makefile.in41
-rw-r--r--libbridge/config.h.in79
-rw-r--r--libbridge/libbridge.h119
-rw-r--r--libbridge/libbridge_devif.c449
-rw-r--r--libbridge/libbridge_if.c117
-rw-r--r--libbridge/libbridge_init.c224
-rw-r--r--libbridge/libbridge_misc.c50
-rw-r--r--libbridge/libbridge_private.h56
-rw-r--r--tests/README14
-rwxr-xr-xtests/busybr23
-rwxr-xr-xtests/functest171
-rwxr-xr-xtests/mkbr13
-rwxr-xr-xtests/rmbr11
-rwxr-xr-xtests/showme10
-rwxr-xr-xtests/stresstest66
41 files changed, 3686 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8f0342b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.so
+
+# Generated by configure
+Makefile
+bridge-utils.spec
+configure
+config.*
+
+#
+# Top-level generic files
+#
+tags
+TAGS
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+
+*.orig
+*.rej
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..ba644c7
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Stephen Hemminger <shemminger@vyatta.com>
+Lennert Buytenhek <buytenh@gnu.org>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..2b7b643
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..435d2f5
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,133 @@
+2006-05-31 Stephen Hemminger <shemminger@zqx3.pdx.osdl.net>
+
+ * Fixed bug where setting port priority set path cost instead
+
+2006-01-31 Stephen Hemminger <shemminger@osdl.org>
+
+ * Released bridge-utils 1.1
+ * Change to use libsysfs 2.0
+
+2005-03-16 Stephen Hemminger <shemminger@osdl.org>
+
+ * Released bridge-utils 1.0.6
+ * Fix for libsys detection (for FC)
+ * Update autoconf usage
+ * Allow multiple interfaces for addif,delif
+
+2004-12-02 Stephen Hemminger <shemminger@osdl.org>
+
+ * Released bridge-utils 1.0.5
+ * Remove brctld out of date, buggy not used
+ * Cleanup command line help and error messages
+ * Fix segv with wrong # of args to 'brctl stp'
+
+
+20040601 Stephen Hemminger <shemminger@osdl.org>
+ * Released bridge-utils 1.0.4
+ - should build with out sysfs now.
+ - report errors on foreach_port failing
+ - more build cleanup
+
+20040525 Stephen Hemminger <shemminger@osdl.org>
+ * Released bridge-utils 1.0.1
+ - Change configure option
+ from --with-linux=<path>
+ to --with-linux-headers=<path>
+ so options match help message.
+ - Fix so utilities work with earlier 2.6 kernels that
+ have sysfs but not new ioctl's or directories yet.
+ - Build spec file from template.
+
+20040524 Stephen Hemminger <shemminger@osdl.org>
+ * Released bridge-utils 1.0
+ - Use sysfs to control bridge parameters
+ - Add new ioctl syntax to handle mixed 32/64 bit mode
+ (Earlier method would not work on all platforms).
+ - Change libbbridge API to do work as needed, rather
+ than reading all bridges/ports at startup. Old way
+ would not scale with 1000's of entries
+ - Minor cleanups.
+
+20040401 Stephen Hemminger <shemminger@osdl.org>
+ * Releases bridge-utils 0.9.7
+ - add -V option
+ - support 100's of bridge ports
+ - minor bug fixes
+
+20021002 Lennert Buytenhek <buytenh@gnu.org>
+
+ * Released bridge-utils 0.9.6.
+
+20020403 Lennert Buytenhek <buytenh@gnu.org>
+
+ * autoconfization by Andreas Hofmeister.
+
+20020116 Lennert Buytenhek <buytenh@gnu.org>
+
+ * On sparc, try to detect 32/64-bitness of the kernel at runtime.
+
+ * Released bridge-utils 0.9.5.
+
+20020106 Lennert Buytenhek <buytenh@gnu.org>
+
+ * Remove 'tap'.
+
+ * Added TODO list.
+
+ * Added extra check for argument count to brctl
+
+ * Added error message for circular bridge dev enslavement to brctl.
+
+ * Get rid of some compiler warnings.
+
+ * Steal Red Hat rawhide spec file.
+
+ * Added 'how to use libbridge_compat.c' explanation by Serge Caron.
+
+ * Try to work around sparc64 brokenness (FUCK ARGHH FUCK FUCK FUCK)
+
+ * Release bridge-utils 0.9.4.
+
+20011107 Lennert Buytenhek <buytenh@gnu.org>
+
+ * Moved FAQ to the website.
+
+ * Updated docs for 2.4 firewalling.
+
+ * Add out-of-date notice to the THANKS file.
+
+???????? Lennert Buytenhek <buytenh@gnu.org>
+
+ * Fixed brctl timeout 42.94s wrap buglet.
+
+ * Cleanup some docs.
+
+ * Released bridge-utils 0.9.3.
+
+20001002 Lennert Buytenhek <buytenh@gnu.org>
+
+ * Incorporated two cleanup patches from H. J. Lu (one splits
+ the CC define into CC and CFLAGS, the other one changes a few
+ occurances of __close into the libc5 compatibility stub to
+ close).
+
+ * Removed all RCS tags.
+
+ * Removed sample scripts dir.
+
+ * Tweaked THANKS file a bit (it needs updating as well..)
+
+ * Made 'show' command show an interface list.
+
+ * Changed the 'showbr' command to 'showstp'
+
+ * Tweaked FAQ.
+
+ * Added explanation for iptables firewalling.
+
+ * Released bridge-utils 0.9.2.
+
+20000905 Lennert Buytenhek <buytenh@gnu.org>
+
+ * Incorporated Roger Venning's patch to tap which will let you
+ specify a local address to be used for the 'tunnel'.
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..6028513
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,35 @@
+
+DESTDIR=
+KERNEL_HEADERS=-I@KERNEL_HEADERS@
+
+INSTALL=@INSTALL@
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+mandir=@mandir@
+distdir = $(PACKAGE)-$(VERSION)
+
+SUBDIRS=libbridge brctl doc
+
+all:
+ for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x ; done
+
+clean:
+ for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x clean ; done
+
+distclean: clean
+ rm -f config.log
+ rm -f config.cache
+ rm -f config.status
+
+maintainer-clean: distclean
+ rm -f Makefile
+ rm -f brctl/Makefile
+ rm -f libbridge/Makefile
+ rm -f doc/Makefile
+
+install:
+ for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x install; done
+
diff --git a/README b/README
new file mode 100644
index 0000000..3062956
--- /dev/null
+++ b/README
@@ -0,0 +1,45 @@
+This version of the bridge utilities is for Linux 2.4 and 2.6,
+it uses the sysfs interface if possible on Linux 2.6.
+
+The code repository is:
+ git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git
+
+Advantages of the new code are:
+- Support for multiple bridge port groups (i.e. multiple independent
+ bridges in one machine).
+- Each bridge is seen as a logical device, which allows you to do
+ firewalling between port groups for example.
+- Everything is dynamic; bridges are created dynamically using the
+ userspace configuration tool, ports are 'enslaved' dynamically, etc.
+- It is being actively maintained.
+- It uses a hash table for MAC addresses, not an AVL tree.
+- It's small (currently 4 pages of i386 code) and modular.
+- The source isn't a mess.
+- It works as a module.
+
+
+If you have any comments, questions or suggestions, please send email to
+the mailing list bridge@linux-foundation.org
+--------------------------
+
+Files in this package:
+
+AUTHORS Authors of this package
+
+COPYING The GNU General Public License.
+
+Makefile Recursive Makefile.
+
+README This file.
+
+brctl/ The userspace bridge configuration tool.
+
+bridge-utils.spec
+ A .spec file for Red Hat package building. "rpm -tb
+ <tar.gz file>" ought to give you a .RPM file.
+
+doc/ Some documentation files.
+
+libbridge/ The bridge configuration interface library.
+
+misc/ Miscellaneous utilities.
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..a9d8dd8
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,40 @@
+Thanks go to (this list is REALLY out-of-date):
+
+F. Nicolaas Benders <benders@pinpoint.com>
+Lars Bohn <lars-erik-christian.bohn@student.uni-ulm.de>
+Jim Chapman <jim.chapman@iname.com>
+Robert Collier <rob@lspace.org>
+Steven Dewinter <steven@zeus.rug.ac.be>
+Arne Fitzenreiter <arne.fitzenreiter@gmx.de>
+Alejando Garcia <alexgc@edu.aytolacoruna.es>
+Matthew Grant <grantma@anathoth.gen.nz>
+Mark Hahn <hahn@coffee.psychology.mcmaster.ca>
+Andreas Hofmeister <Andreas.Hofmeister@pyramid.de>
+Oskari Jaaskelainen <osi@fyslab.hut.fi>
+Joshua Jensen <joshua@redhat.com>
+Jason Lambert <jlambert@lambert-comm.net>
+Christoph Lameter <christoph@lameter.com>
+Miles Lane <miles@amazon.com>
+Janne Liimatainen <liimjann@trade.hamkk.fi>
+Benoit Locher <themagpie@wanadoo.fr>
+Daniel Lopez <daniel@rawbyte.com>
+Stuart Lynne <sdjl@fireplug.net>
+Andrew McRory <amacc@iron-bridge.net>
+David S. Miller <davem@redhat.com>
+Philippe Moutarlier <philippe@kscable.com>
+Petr Novopashenniy <pety@au.ru>
+Monte Ohrt <monte@ispi.net>
+Joachim Ott <ott@ardala.han.de>
+Kristian Rietveld <kristian@planet.nl>
+Jacob Schroeder <jacob@quantec.de>
+Bart de Schuymer <bart.de.schuymer@pandora.be>
+Heikki Vatiainen <hessu@cs.tut.fi>
+Ernest Yik <ernestyik@cuhk.edu.hk>
+
+and everyone else I forgot. Thanks also go to Leiden University
+for letting me use their equipment and allowing me to work on this
+during work hours.
+
+
+I would also like to express my thanks and eternal gratitude to
+Margaret Suda. I hope you'll read this some day.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..4784984
--- /dev/null
+++ b/TODO
@@ -0,0 +1,30 @@
+main code
+---------
+Add netlink based API?
+we have a tiny deviation from IEEE 802.1d: we don't kill the awaiting-tx skb
+ queue when a port leaves the FORWARDING state
+RH initscripts for setting up bridge interfaces automatically
+bridge ID change notifications
+
+move the spanning tree code to userspace
+to be MLT (Nortel Multi Link Trunking) compatible: send bpdu's on all
+ interfaces in the bonding bundle
+
+faster switch to forward mode
+ per-port STP disabling
+ 'fast start': listening->learning->forwarding in 2*hello instead of 2*fd
+
+enslaved devs same MAC (like tap), then one changes
+
+managerial
+----------
+improve documentation..
+
+netfilter patch
+---------------
+sync MAC addresses DNAT/SNAT
+make src mac substitution configurable
+br_nf_pre_routing: ip_route_output -> output_key
+check: don't send unreachables
+stp state delay
+kernel panic on REDIRECT on bridge device w/o IP address
diff --git a/brctl/Makefile.in b/brctl/Makefile.in
new file mode 100644
index 0000000..e1956d6
--- /dev/null
+++ b/brctl/Makefile.in
@@ -0,0 +1,44 @@
+
+KERNEL_HEADERS=-I@KERNEL_HEADERS@
+
+CC=@CC@
+CFLAGS= -Wall @CFLAGS@
+LDFLAGS=@LDFLAGS@
+INCLUDE=-I../libbridge $(KERNEL_HEADERS)
+LIBS= -L ../libbridge -lbridge @LIBS@
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+mandir=@mandir@
+
+INSTALL=@INSTALL@
+
+
+common_SOURCES= brctl_cmd.c brctl_disp.c
+brctl_SOURCES= brctl.c $(common_SOURCES)
+
+common_OBJECTS= $(common_SOURCES:.c=.o)
+brctl_OBJECTS= $(brctl_SOURCES:.c=.o)
+
+OBJECTS= $(common_OBJECTS) $(brctl_OBJECTS)
+
+PROGRAMS= brctl
+
+
+all: $(PROGRAMS)
+
+install: $(PROGRAMS)
+ mkdir -p $(DESTDIR)$(sbindir)
+ $(INSTALL) -m 755 $(PROGRAMS) $(DESTDIR)$(sbindir)
+
+brctl: $(brctl_OBJECTS) ../libbridge/libbridge.a
+ $(CC) $(LDFLAGS) $(brctl_OBJECTS) $(LIBS) -o brctl
+
+%.o: %.c brctl.h
+ $(CC) $(CFLAGS) $(INCLUDE) -c $<
+
+clean:
+ rm -f *.o brctl core
+
diff --git a/brctl/brctl.c b/brctl/brctl.c
new file mode 100644
index 0000000..46ca352
--- /dev/null
+++ b/brctl/brctl.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <getopt.h>
+
+#include "libbridge.h"
+#include "config.h"
+
+#include "brctl.h"
+
+static void help()
+{
+ printf("Usage: brctl [commands]\n");
+ printf("commands:\n");
+ command_helpall();
+}
+
+int main(int argc, char *const* argv)
+{
+ const struct command *cmd;
+ int f;
+ static const struct option options[] = {
+ { .name = "help", .val = 'h' },
+ { .name = "version", .val = 'V' },
+ { 0 }
+ };
+
+ while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
+ switch(f) {
+ case 'h':
+ help();
+ return 0;
+ case 'V':
+ printf("%s, %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ return 0;
+ default:
+ fprintf(stderr, "Unknown option '%c'\n", f);
+ goto help;
+ }
+
+ if (argc == optind)
+ goto help;
+
+ if (br_init()) {
+ fprintf(stderr, "can't setup bridge control: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ argc -= optind;
+ argv += optind;
+ if ((cmd = command_lookup(*argv)) == NULL) {
+ fprintf(stderr, "never heard of command [%s]\n", *argv);
+ goto help;
+ }
+
+ if (argc < cmd->nargs + 1) {
+ printf("Incorrect number of arguments for command\n");
+ printf("Usage: brctl %s %s\n", cmd->name, cmd->help);
+ return 1;
+ }
+
+ return cmd->func(argc, argv);
+
+help:
+ help();
+ return 1;
+}
diff --git a/brctl/brctl.h b/brctl/brctl.h
new file mode 100644
index 0000000..55b7897
--- /dev/null
+++ b/brctl/brctl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#ifndef _BRCTL_H
+#define _BRCTL_H
+
+struct command
+{
+ int nargs;
+ const char *name;
+ int (*func)(int argc, char *const* argv);
+ const char *help;
+};
+
+const struct command *command_lookup(const char *cmd);
+void command_help(const struct command *);
+void command_helpall(void);
+
+void br_dump_bridge_id(const unsigned char *x);
+void br_show_timer(const struct timeval *tv);
+void br_dump_interface_list(const char *br);
+void br_dump_info(const char *br, const struct bridge_info *bri);
+
+#endif
diff --git a/brctl/brctl_cmd.c b/brctl/brctl_cmd.c
new file mode 100644
index 0000000..b4ed104
--- /dev/null
+++ b/brctl/brctl_cmd.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <asm/param.h>
+#include "libbridge.h"
+#include "brctl.h"
+
+static int strtotimeval(struct timeval *tv, const char *time)
+{
+ double secs;
+ if (sscanf(time, "%lf", &secs) != 1)
+ return -1;
+ tv->tv_sec = secs;
+ tv->tv_usec = 1000000 * (secs - tv->tv_sec);
+ return 0;
+}
+
+static int br_cmd_addbr(int argc, char*const* argv)
+{
+ int err;
+
+ switch (err = br_add_bridge(argv[1])) {
+ case 0:
+ return 0;
+
+ case EEXIST:
+ fprintf(stderr, "device %s already exists; can't create "
+ "bridge with the same name\n", argv[1]);
+ return 1;
+ default:
+ fprintf(stderr, "add bridge failed: %s\n",
+ strerror(err));
+ return 1;
+ }
+}
+
+static int br_cmd_delbr(int argc, char*const* argv)
+{
+ int err;
+
+ switch (err = br_del_bridge(argv[1])){
+ case 0:
+ return 0;
+
+ case ENXIO:
+ fprintf(stderr, "bridge %s doesn't exist; can't delete it\n",
+ argv[1]);
+ return 1;
+
+ case EBUSY:
+ fprintf(stderr, "bridge %s is still up; can't delete it\n",
+ argv[1]);
+ return 1;
+
+ default:
+ fprintf(stderr, "can't delete bridge %s: %s\n",
+ argv[1], strerror(err));
+ return 1;
+ }
+}
+
+static int br_cmd_addif(int argc, char *const* argv)
+{
+ const char *brname;
+ int err;
+
+ argc -= 2;
+ brname = *++argv;
+
+ while (argc-- > 0) {
+ const char *ifname = *++argv;
+ err = br_add_interface(brname, ifname);
+
+ switch(err) {
+ case 0:
+ continue;
+
+ case ENODEV:
+ if (if_nametoindex(ifname) == 0)
+ fprintf(stderr, "interface %s does not exist!\n", ifname);
+ else
+ fprintf(stderr, "bridge %s does not exist!\n", brname);
+ break;
+
+ case EBUSY:
+ fprintf(stderr, "device %s is already a member of a bridge; "
+ "can't enslave it to bridge %s.\n", ifname,
+ brname);
+ break;
+
+ case ELOOP:
+ fprintf(stderr, "device %s is a bridge device itself; "
+ "can't enslave a bridge device to a bridge device.\n",
+ ifname);
+ break;
+
+ default:
+ fprintf(stderr, "can't add %s to bridge %s: %s\n",
+ ifname, brname, strerror(err));
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int br_cmd_delif(int argc, char *const* argv)
+{
+ const char *brname;
+ int err;
+
+ argc -= 2;
+ brname = *++argv;
+
+ while (argc-- > 0) {
+ const char *ifname = *++argv;
+ err = br_del_interface(brname, ifname);
+ switch (err) {
+ case 0:
+ continue;
+
+ case ENODEV:
+ if (if_nametoindex(ifname) == 0)
+ fprintf(stderr, "interface %s does not exist!\n", ifname);
+ else
+ fprintf(stderr, "bridge %s does not exist!\n", brname);
+ break;
+
+ case EINVAL:
+ fprintf(stderr, "device %s is not a slave of %s\n",
+ ifname, brname);
+ break;
+
+ default:
+ fprintf(stderr, "can't delete %s from %s: %s\n",
+ ifname, brname, strerror(err));
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int br_cmd_setageing(int argc, char *const* argv)
+{
+ int err;
+ struct timeval tv;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad ageing time value\n");
+ return 1;
+ }
+
+ err = br_set_ageing_time(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set ageing time failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_setbridgeprio(int argc, char *const* argv)
+{
+ int prio;
+ int err;
+
+ if (sscanf(argv[2], "%i", &prio) != 1) {
+ fprintf(stderr,"bad priority\n");
+ return 1;
+ }
+
+ err = br_set_bridge_priority(argv[1], prio);
+ if (err)
+ fprintf(stderr, "set bridge priority failed: %s\n",
+ strerror(err));
+ return err != 0;
+}
+
+static int br_cmd_setfd(int argc, char *const* argv)
+{
+ struct timeval tv;
+ int err;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad forward delay value\n");
+ return 1;
+ }
+
+ err = br_set_bridge_forward_delay(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set forward delay failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_sethello(int argc, char *const* argv)
+{
+ struct timeval tv;
+ int err;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad hello timer value\n");
+ return 1;
+ }
+
+ err = br_set_bridge_hello_time(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set hello timer failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_setmaxage(int argc, char *const* argv)
+{
+ struct timeval tv;
+ int err;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad max age value\n");
+ return 1;
+ }
+ err = br_set_bridge_max_age(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set max age failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_setpathcost(int argc, char *const* argv)
+{
+ int cost, err;
+
+ if (sscanf(argv[3], "%i", &cost) != 1) {
+ fprintf(stderr, "bad path cost value\n");
+ return 1;
+ }
+
+ err = br_set_path_cost(argv[1], argv[2], cost);
+ if (err)
+ fprintf(stderr, "set path cost failed: %s\n",
+ strerror(err));
+ return err != 0;
+}
+
+static int br_cmd_setportprio(int argc, char *const* argv)
+{
+ int cost, err;
+
+ if (sscanf(argv[3], "%i", &cost) != 1) {
+ fprintf(stderr, "bad path priority value\n");
+ return 1;
+ }
+
+ err = br_set_port_priority(argv[1], argv[2], cost);
+ if (err)
+ fprintf(stderr, "set port priority failed: %s\n",
+ strerror(errno));
+
+ return err != 0;
+}
+
+static int br_cmd_stp(int argc, char *const* argv)
+{
+ int stp, err;
+
+ if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes")
+ || !strcmp(argv[2], "1"))
+ stp = 1;
+ else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no")
+ || !strcmp(argv[2], "0"))
+ stp = 0;
+ else {
+ fprintf(stderr, "expect on/off for argument\n");
+ return 1;
+ }
+
+ err = br_set_stp_state(argv[1], stp);
+ if (err)
+ fprintf(stderr, "set stp status failed: %s\n",
+ strerror(errno));
+ return err != 0;
+}
+
+static int br_cmd_showstp(int argc, char *const* argv)
+{
+ struct bridge_info info;
+
+ if (br_get_bridge_info(argv[1], &info)) {
+ fprintf(stderr, "%s: can't get info %s\n", argv[1],
+ strerror(errno));
+ return 1;
+ }
+
+ br_dump_info(argv[1], &info);
+ return 0;
+}
+
+static int show_bridge(const char *name, void *arg)
+{
+ struct bridge_info info;
+
+ printf("%s\t\t", name);
+ fflush(stdout);
+
+ if (br_get_bridge_info(name, &info)) {
+ fprintf(stderr, "can't get info %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ br_dump_bridge_id((unsigned char *)&info.bridge_id);
+ printf("\t%s\t\t", info.stp_enabled?"yes":"no");
+
+ br_dump_interface_list(name);
+ return 0;
+}
+
+static int br_cmd_show(int argc, char *const* argv)
+{
+ int i;
+
+ printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+ if (argc == 1)
+ br_foreach_bridge(show_bridge, NULL);
+ else
+ for(i = 2; i <= argc; i++)
+ show_bridge(argv[i - 1], NULL);
+
+ return 0;
+}
+
+static int compare_fdbs(const void *_f0, const void *_f1)
+{
+ const struct fdb_entry *f0 = _f0;
+ const struct fdb_entry *f1 = _f1;
+
+ return memcmp(f0->mac_addr, f1->mac_addr, 6);
+}
+
+static int br_cmd_showmacs(int argc, char *const* argv)
+{
+ const char *brname = argv[1];
+#define CHUNK 128
+ int i, n;
+ struct fdb_entry *fdb = NULL;
+ int offset = 0;
+
+ for(;;) {
+ fdb = realloc(fdb, (offset + CHUNK) * sizeof(struct fdb_entry));
+ if (!fdb) {
+ fprintf(stderr, "Out of memory\n");
+ return 1;
+ }
+
+ n = br_read_fdb(brname, fdb+offset, offset, CHUNK);
+ if (n == 0)
+ break;
+
+ if (n < 0) {
+ fprintf(stderr, "read of forward table failed: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ offset += n;
+ }
+
+ qsort(fdb, offset, sizeof(struct fdb_entry), compare_fdbs);
+
+ printf("port no\tmac addr\t\tis local?\tageing timer\n");
+ for (i = 0; i < offset; i++) {
+ const struct fdb_entry *f = fdb + i;
+ printf("%3i\t", f->port_no);
+ printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t",
+ f->mac_addr[0], f->mac_addr[1], f->mac_addr[2],
+ f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]);
+ printf("%s\t\t", f->is_local?"yes":"no");
+ br_show_timer(&f->ageing_timer_value);
+ printf("\n");
+ }
+ return 0;
+}
+
+static int br_cmd_hairpin(int argc, char *const* argv)
+{
+ int hairpin, err;
+ const char *brname = *++argv;
+ const char *ifname = *++argv;
+ const char *hpmode = *++argv;
+
+ if (!strcmp(hpmode, "on") || !strcmp(hpmode, "yes")
+ || !strcmp(hpmode, "1"))
+ hairpin = 1;
+ else if (!strcmp(hpmode, "off") || !strcmp(hpmode, "no")
+ || !strcmp(hpmode, "0"))
+ hairpin = 0;
+ else {
+ fprintf(stderr, "expect on/off for argument\n");
+ return 1;
+ }
+ if (if_nametoindex(ifname) == 0) {
+ fprintf(stderr, "interface %s does not exist!\n",
+ ifname);
+ return 1;
+ } else if (if_nametoindex(brname) == 0) {
+ fprintf(stderr, "bridge %s does not exist!\n",
+ brname);
+ return 1;
+ }
+
+ err = br_set_hairpin_mode(brname, ifname, hairpin);
+
+ if (err) {
+ fprintf(stderr, "can't set %s to hairpin on bridge %s: %s\n",
+ ifname, brname, strerror(err));
+ }
+ return err != 0;
+}
+
+static const struct command commands[] = {
+ { 1, "addbr", br_cmd_addbr, "<bridge>\t\tadd bridge" },
+ { 1, "delbr", br_cmd_delbr, "<bridge>\t\tdelete bridge" },
+ { 2, "addif", br_cmd_addif,
+ "<bridge> <device>\tadd interface to bridge" },
+ { 2, "delif", br_cmd_delif,
+ "<bridge> <device>\tdelete interface from bridge" },
+ { 3, "hairpin", br_cmd_hairpin,
+ "<bridge> <port> {on|off}\tturn hairpin on/off" },
+ { 2, "setageing", br_cmd_setageing,
+ "<bridge> <time>\t\tset ageing time" },
+ { 2, "setbridgeprio", br_cmd_setbridgeprio,
+ "<bridge> <prio>\t\tset bridge priority" },
+ { 2, "setfd", br_cmd_setfd,
+ "<bridge> <time>\t\tset bridge forward delay" },
+ { 2, "sethello", br_cmd_sethello,
+ "<bridge> <time>\t\tset hello time" },
+ { 2, "setmaxage", br_cmd_setmaxage,
+ "<bridge> <time>\t\tset max message age" },
+ { 3, "setpathcost", br_cmd_setpathcost,
+ "<bridge> <port> <cost>\tset path cost" },
+ { 3, "setportprio", br_cmd_setportprio,
+ "<bridge> <port> <prio>\tset port priority" },
+ { 0, "show", br_cmd_show,
+ "[ <bridge> ]\t\tshow a list of bridges" },
+ { 1, "showmacs", br_cmd_showmacs,
+ "<bridge>\t\tshow a list of mac addrs"},
+ { 1, "showstp", br_cmd_showstp,
+ "<bridge>\t\tshow bridge stp info"},
+ { 2, "stp", br_cmd_stp,
+ "<bridge> {on|off}\tturn stp on/off" },
+};
+
+const struct command *command_lookup(const char *cmd)
+{
+ int i;
+
+ for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
+ if (!strcmp(cmd, commands[i].name))
+ return &commands[i];
+ }
+
+ return NULL;
+}
+
+void command_helpall(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
+ printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
+ }
+}
diff --git a/brctl/brctl_disp.c b/brctl/brctl_disp.c
new file mode 100644
index 0000000..3e81241
--- /dev/null
+++ b/brctl/brctl_disp.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "libbridge.h"
+#include "brctl.h"
+
+void br_dump_bridge_id(const unsigned char *x)
+{
+ printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", x[0], x[1], x[2], x[3],
+ x[4], x[5], x[6], x[7]);
+}
+
+void br_show_timer(const struct timeval *tv)
+{
+ printf("%4i.%.2i", (int)tv->tv_sec, (int)tv->tv_usec/10000);
+}
+
+static int first;
+
+static int dump_interface(const char *b, const char *p, void *arg)
+{
+
+ if (first)
+ first = 0;
+ else
+ printf("\n\t\t\t\t\t\t\t");
+
+ printf("%s", p);
+
+ return 0;
+}
+
+void br_dump_interface_list(const char *br)
+{
+ int err;
+
+ first = 1;
+ err = br_foreach_port(br, dump_interface, NULL);
+ if (err < 0)
+ printf(" can't get port info: %s\n", strerror(-err));
+ else
+ printf("\n");
+}
+
+static int dump_port_info(const char *br, const char *p, void *arg)
+{
+ struct port_info pinfo;
+
+ if (br_get_port_info(br, p, &pinfo)) {
+ printf("Can't get info for %p",p);
+ return 1;
+ }
+
+ printf("%s (%d)\n", p, pinfo.port_no);
+ printf(" port id\t\t%.4x", pinfo.port_id);
+ printf("\t\t\tstate\t\t%15s\n", br_get_state_name(pinfo.state));
+ printf(" designated root\t");
+ br_dump_bridge_id((unsigned char *)&pinfo.designated_root);
+ printf("\tpath cost\t\t%4i\n", pinfo.path_cost);
+
+ printf(" designated bridge\t");
+ br_dump_bridge_id((unsigned char *)&pinfo.designated_bridge);
+ printf("\tmessage age timer\t");
+ br_show_timer(&pinfo.message_age_timer_value);
+ printf("\n designated port\t%.4x", pinfo.designated_port);
+ printf("\t\t\tforward delay timer\t");
+ br_show_timer(&pinfo.forward_delay_timer_value);
+ printf("\n designated cost\t%4i", pinfo.designated_cost);
+ printf("\t\t\thold timer\t\t");
+ br_show_timer(&pinfo.hold_timer_value);
+ printf("\n flags\t\t\t");
+ if (pinfo.config_pending)
+ printf("CONFIG_PENDING ");
+ if (pinfo.top_change_ack)
+ printf("TOPOLOGY_CHANGE_ACK ");
+ if (pinfo.hairpin_mode)
+ printf("\n hairpin mode\t\t\%4i", pinfo.hairpin_mode);
+ printf("\n");
+ printf("\n");
+ return 0;
+}
+
+void br_dump_info(const char *br, const struct bridge_info *bri)
+{
+ int err;
+
+ printf("%s\n", br);
+ printf(" bridge id\t\t");
+ br_dump_bridge_id((unsigned char *)&bri->bridge_id);
+ printf("\n designated root\t");
+ br_dump_bridge_id((unsigned char *)&bri->designated_root);
+ printf("\n root port\t\t%4i\t\t\t", bri->root_port);
+ printf("path cost\t\t%4i\n", bri->root_path_cost);
+ printf(" max age\t\t");
+ br_show_timer(&bri->max_age);
+ printf("\t\t\tbridge max age\t\t");
+ br_show_timer(&bri->bridge_max_age);
+ printf("\n hello time\t\t");
+ br_show_timer(&bri->hello_time);
+ printf("\t\t\tbridge hello time\t");
+ br_show_timer(&bri->bridge_hello_time);
+ printf("\n forward delay\t\t");
+ br_show_timer(&bri->forward_delay);
+ printf("\t\t\tbridge forward delay\t");
+ br_show_timer(&bri->bridge_forward_delay);
+ printf("\n ageing time\t\t");
+ br_show_timer(&bri->ageing_time);
+ printf("\n hello timer\t\t");
+ br_show_timer(&bri->hello_timer_value);
+ printf("\t\t\ttcn timer\t\t");
+ br_show_timer(&bri->tcn_timer_value);
+ printf("\n topology change timer\t");
+ br_show_timer(&bri->topology_change_timer_value);
+ printf("\t\t\tgc timer\t\t");
+ br_show_timer(&bri->gc_timer_value);
+ printf("\n flags\t\t\t");
+ if (bri->topology_change)
+ printf("TOPOLOGY_CHANGE ");
+ if (bri->topology_change_detected)
+ printf("TOPOLOGY_CHANGE_DETECTED ");
+ printf("\n");
+ printf("\n");
+ printf("\n");
+
+ err = br_foreach_port(br, dump_port_info, NULL);
+ if (err < 0)
+ printf("can't get ports: %s\n", strerror(-err));
+}
diff --git a/bridge-utils.spec.in b/bridge-utils.spec.in
new file mode 100644
index 0000000..468513b
--- /dev/null
+++ b/bridge-utils.spec.in
@@ -0,0 +1,76 @@
+Name: @PACKAGE@
+Version: @VERSION@
+Release: 1
+Copyright: GPL
+Group: System Environment/Base
+Url: git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git
+Summary: Utilities for configuring the linux ethernet bridge.
+Buildroot: %{_tmppath}/%{name}-%{version}
+Source: %{name}-%{version}.tar.gz
+
+%description
+This package contains utilities for configuring the linux ethernet
+bridge. The linux ethernet bridge can be used for connecting multiple
+ethernet devices together. The connecting is fully transparent: hosts
+connected to one ethernet device see hosts connected to the other
+ethernet devices directly.
+
+Install bridge-utils if you want to use the linux ethernet bridge.
+
+%package -n bridge-utils-devel
+Summary: Utilities for configuring the linux ethernet bridge.
+Group: Development/Libraries
+
+%description -n bridge-utils-devel
+The bridge-utils-devel package contains the header and object files
+necessary for developing programs which use 'libbridge.a', the
+interface to the linux kernel ethernet bridge. If you are developing
+programs which need to configure the linux ethernet bridge, your
+system needs to have these standard header and object files available
+in order to create the executables.
+
+Install bridge-utils-devel if you are going to develop programs which
+will use the linux ethernet bridge interface library.
+
+%prep
+%setup -q
+
+%build
+CFLAGS="${RPM_OPT_FLAGS}" ./configure --prefix=/usr --mandir=%{_mandir}
+make
+
+%install
+rm -rf %{buildroot}
+
+mkdir -p %{buildroot}%{_sbindir}
+mkdir -p %{buildroot}%{_includedir}
+mkdir -p %{buildroot}%{_libdir}
+mkdir -p %{buildroot}%{_mandir}/man8
+install -m755 brctl/brctl %{buildroot}%{_sbindir}
+gzip doc/brctl.8
+install -m 644 doc/brctl.8.gz %{buildroot}%{_mandir}/man8
+install -m 644 libbridge/libbridge.h %{buildroot}%{_includedir}
+install -m 644 libbridge/libbridge.a %{buildroot}%{_libdir}
+
+%clean
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr (-,root,root)
+%doc AUTHORS COPYING doc/FAQ doc/HOWTO doc/RPM-GPG-KEY
+%{_sbindir}/brctl
+%{_mandir}/man8/brctl.8.gz
+
+%files -n bridge-utils-devel
+%defattr (-,root,root)
+%{_includedir}/libbridge.h
+%{_libdir}/libbridge.a
+
+%changelog
+* Tue May 25 2004 Stephen Hemminger <shemminger@osdl.org>
+- cleanup to work for 1.0 code
+- add dependency on sysfs
+
+* Wed Nov 07 2001 Matthew Galgoci <mgalgoci@redhat.com>
+- initial cleanup of spec file from net release
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..5e3f89b
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,27 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(bridge-utils, 1.5)
+AC_CONFIG_HEADERS(libbridge/config.h)
+
+AC_ARG_WITH( linux-headers, [ --with-linux-headers Location of the linux headers to use],
+ KERNEL_HEADERS=$withval, KERNEL_HEADERS="/usr/src/linux/include")
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sys/ioctl.h sys/time.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(gethostname socket strdup uname)
+AC_CHECK_FUNCS(if_nametoindex if_indextoname)
+
+AC_SUBST(KERNEL_HEADERS)
+
+AC_OUTPUT(doc/Makefile libbridge/Makefile brctl/Makefile Makefile bridge-utils.spec)
diff --git a/doc/FAQ b/doc/FAQ
new file mode 100644
index 0000000..385c5a8
--- /dev/null
+++ b/doc/FAQ
@@ -0,0 +1,2 @@
+The FAQ is now located at
+ http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge
diff --git a/doc/FIREWALL b/doc/FIREWALL
new file mode 100644
index 0000000..7ffff86
--- /dev/null
+++ b/doc/FIREWALL
@@ -0,0 +1,38 @@
+Bridging and firewalling
+------------------------
+It is possible to use bridging in combination with firewalling. This is
+a blatant violation of the OSI model, but it's very useful, so we don't
+care.
+
+Assuming you are on a non-stone age kernel (less than 5 years old).
+You can use the regular iptables firewalling as if you were doing
+routing. So, rules for forwarding are added to the FORWARD chain,
+rules for input to the local machine are added to the INPUT chain,
+etc. Things will work like you expect them to.
+So a rule like
+
+ # iptables -A INPUT -i eth0 -j DROP
+
+will drop all traffic coming from 'eth0', even if the interface the packets
+are logically from is, say, 'br0'.
+
+
+
+Lennert Buytenhek, November 7th 2001
+<buytenh@gnu.org>
+
+
+
+--------------------------
+Bridge+firewalling with 2.2 kernels is also possible, but deprecated. I
+would severely recommend against using a 2.2 kernel and ipchains for bridge
+firewalling. But if there's really a need, it's still possible. Apply the
+extra firewalling patch available from the 'patches' section to your
+already-patched-with-the-vanilla-bridge-patch 2.2 kernel, and recompile. Now
+if you boot this kernel, the bridging code will check each to-be-forwarded
+packet against the ipchains chain which has the same name as the bridge. So..
+if a packet on eth0 is to be forwarded to eth1, and those interfaces are
+both part of the bridge group br0, the bridging code will check the packet
+against the chain called 'br0'. If the chain does not exist, the packet will
+be forwarded. So if you want to do firewalling, you'll have to create the
+chain yourself. This is important!
diff --git a/doc/HOWTO b/doc/HOWTO
new file mode 100644
index 0000000..3729618
--- /dev/null
+++ b/doc/HOWTO
@@ -0,0 +1,105 @@
+Hello everybody,
+
+Although there is a man page which documents most of the actual
+commands, there is still a 'gap' concerning what bridges are, and how
+to set them up. This document attempts to fill this gap.
+
+In fact, this document is a 15-min hack, so feel free to {complain
+about,improve on} it. Especially if this document (or the FAQ) does
+not tell you what you want to know; I would consider that to be a bug.
+
+
+Have fun!
+Lennert Buytenhek
+
+
+<================= CUT HERE AND DAMAGE YOUR SCREEN =================>
+
+
+
+1. The basics
+-------------
+
+What does a bridge actually do? In plain English, a bridge connects
+two or more different physical ethernets together to form one large
+(logical) ethernet. The physical ethernets being connected together
+correspond to network interfaces in your linux box. The bigger
+(logical) ethernet corresponds to a virtual network interface in linux
+(often called br0, br1, br2, etc.)
+
+Let's say we want to tie eth0 and eth1 together, turning those
+networks into one larger network. What do we do? Well, we need to
+create an instance of the bridge first.
+
+ # brctl addbr br0
+
+(You can check that this gives you a network interface called br0.)
+Now we want to enslave eth0 and eth1 to this bridge.
+
+ # brctl addif br0 eth0
+ # brctl addif br0 eth1
+
+And now... because we connected the two ethernets together, they now
+form one large subnet. We are actually only on only one subnet, namely
+br0. We can forget about the fact that br0 is actually eth[01] in
+disguise; we will only deal with br0 from now on. Because we are only
+on one subnet, we only need one IP address for the bridge. This
+address we assign to br0. eth0 and eth1 should not have IP addresses
+allocated to them.
+
+ # ifconfig eth0 0.0.0.0
+ # ifconfig eth1 0.0.0.0
+ # ifconfig br0 my.ip.address.here
+
+The last command also puts the interface br0 into the 'up' state. This
+will activate the forwarding of packets, which in plain English means
+that from that point on, eth0 and eth1 will be 'joined'
+together. Hosts on eth0 should 'see' hosts on eth1 and vice versa.
+
+The bridge will also (automatically) activate the Spanning Tree
+Protocol: this is a network protocol spoken by switches for (roughly
+speaking) calculating the shortest distances and eliminating loops in
+the topology of the network. You can disable the stp if you really
+want/need to; see brctl(8) for details.
+
+
+
+2. More complicated setups
+--------------------------
+
+We can create multiple bridge port groups and do filtering/NATting
+between them, just like we can do that with ordinary network
+interfaces.
+
+For example: on a quadport network card, dedicate two ports to a LAN
+on which we have IP 10.16.0.254, and the other two ports to a LAN on
+which we have IP 192.168.10.1 (this is an actual setup)
+
+ # brctl addbr br_10
+ # brctl addif br_10 eth0
+ # brctl addif br_10 eth1
+ # ifconfig br_10 10.16.0.254
+
+ # brctl addbr br_192
+ # brctl addif br_192 eth2
+ # brctl addif br_192 eth3
+ # ifconfig br_192 192.168.10.1
+
+You now have logical network interfaces br_10 and br_192, which will
+act just like ordinary interfaces. The only difference is that they
+each correspond to two physical network interfaces, but nobody cares
+about that.
+
+So.. for example, if 192.168.10.2 is the only host on the 192.*
+network that is allowed to access the 10.* network, we would do:
+
+ipchains -P forward REJECT
+ipchains -A forward -s 192.168.10.2/32 -d 10.0.0.0/8 -i br_10 -j ACCEPT
+
+(just like you were used to).
+
+
+
+
+
+Hope this helped. If not, send a cry for help to the mailing list.
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..23bfb06
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,21 @@
+
+DESTDIR=
+KERNEL_HEADERS=-I@KERNEL_HEADERS@
+
+INSTALL=@INSTALL@
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+mandir=@mandir@
+
+SUBDIRS=libbridge brctl
+
+all:
+
+clean:
+
+install:
+ mkdir -p $(DESTDIR)$(mandir)/man8
+ $(INSTALL) -m 644 brctl.8 $(DESTDIR)$(mandir)/man8
diff --git a/doc/PROJECTS b/doc/PROJECTS
new file mode 100644
index 0000000..de6dfb3
--- /dev/null
+++ b/doc/PROJECTS
@@ -0,0 +1,2 @@
+- Kristian Rietveld <kristian@planet.nl> is working on a GNOME
+ interface.
diff --git a/doc/RPM-GPG-KEY b/doc/RPM-GPG-KEY
new file mode 100644
index 0000000..83b1956
--- /dev/null
+++ b/doc/RPM-GPG-KEY
@@ -0,0 +1,30 @@
+Hi,
+
+This public key is the GPG public key I use to sign the bridge-utils
+and bridge-utils-devel RPM packages. You can use this key to verify
+the integrity of those packages.
+
+Lennert Buytenhek
+<buytenh@gnu.org>
+
+
+
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.1 (GNU/Linux)
+Comment: For info see http://www.gnupg.org
+
+mQGiBDiT6YIRBADbn6OduygntL0gYcBD3333gje45DSWl0PVghw9CtJQUZRZSBFp
+Z1CgkxI1F3kza4gJwIj/fgtuC8PWi1200rOwCLL8kLkFIH9Zy0VEuXskoXLeDU/f
+V14e+9GVtoVLQ5Bx2bTez3+2dEU7N0axKH5MJQsyWZx+U863unNk/qGO1wCgjYZ5
+zKhTuvWnR51tYjdwbfXyq0sD/iflTEUFkQ0MEQc/eJ+RU9kL55GyhT7f227CR6XZ
+/d2LCUkdaCdihAsJLXEL66gS7MOUd5I6dolPXG0vG0wQMBqt/jcKr2JRZsSf2Zjg
+IxTvlv+6h6LyaHBiq45yCAE1KC2ka2ebtdK0BubdRjKlxDMmGJMrMTeK6RsLbDej
+SEhqBACTtgUO9gOAFB53TAAjpftMW91mTOiokg1znKxqunbJ/4Ndo9Z9KI1m4wH8
+RsyGJBEkwlR5PNjnLZbE0ET2hk01RLFWX8yDXORXDx1bkcW/NJgMkyUua3A2QaTV
+D1SdIfnMLB2vg4FzjUdo9QXS+zNQ24jS7G6tDq8McvVM2DSwp7Q3TGVubmVydCBC
+dXl0ZW5oZWsgKFJQTSBzaWduYXR1cmUga2V5KSA8YnV5dGVuaEBnbnUub3JnPohW
+BBMRAgAWBQI4k+mCBAsKBAMDFQMCAxYCAQIXgAAKCRD/CxH2tC7NLt6pAKCGnrIT
+EfdFTc5S/Fz+LAYokMWKTwCfU7DQG4bkaOJTcv5fRUOD4UZ2MTk=
+=om8h
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/doc/SMPNOTES b/doc/SMPNOTES
new file mode 100644
index 0000000..ba54836
--- /dev/null
+++ b/doc/SMPNOTES
@@ -0,0 +1,21 @@
+Notes on the (20000210) SMP-ization of the bridging code:
+
+Each bridge has a hash table of MAC addresses. This table is protected
+by a rwlock hash_lock. The entries are refcounted; 'getting' an entry
+is done in the usual way: read_lock the table, find the entry,
+increment it's refcount and unlock the table. Bottom half context
+acquires this lock in read as well as write mode, therefore we always
+need to locally disable BHs when acquiring this lock.
+
+Each bridge also has an rwlock called lock. This slightly misnamed
+lock protects the bridge's port_list. All stp code acquires this lock
+in read mode, the only piece of code that acquires this lock in write
+mode is the ioctl code (br_ioctl.c). Bottom halves never acquire this
+lock in write mode, therefore we can use read_lock instead of
+read_lock_bh in all cases.
+
+All ioctls are globally serialized by the semaphore ioctl_mutex. All
+code which acquires the bridge lock in write mode also acquires
+ioctl_mutex. Therefore, if we have already grabbed ioctl_mutex we
+don't need to read_lock the bridge lock anymore; the ioctl_mutex will
+protect against concurrent writers.
diff --git a/doc/WISHLIST b/doc/WISHLIST
new file mode 100644
index 0000000..43ca124
--- /dev/null
+++ b/doc/WISHLIST
@@ -0,0 +1,25 @@
+Would be nice if:
+
+- Add address learning limiting (hard limit at a fixed # of
+ addresses? or maybe using rate markers?). There is a nasty DoS in
+ here.
+
+- Add fdb entry port # change limiting. For example: if one MAC
+ address switches port more than once in the same second, there is
+ something wrong (somebody trying to spoof?), so print a warning.
+
+- Faster port state cycling; currently it takes 30 seconds for ports
+ to cycle to the forwarding state.
+
+- Detect port speed and adjust path cost accordingly?
+
+- Use MII ioctls for detecting link beat lost quickly?
+
+- Keep the IEEE 802.1d-mandated statistics (counters, mostly).
+
+- Maybe integrate Kristian's GNOME frontend (see PROJECTS) once it
+ stabilises. It looks nice.
+
+- A cgi bridge configurer (a la Samba's SWAT, yummy....)
+
+
diff --git a/doc/brctl.8 b/doc/brctl.8
new file mode 100644
index 0000000..a708bc1
--- /dev/null
+++ b/doc/brctl.8
@@ -0,0 +1,172 @@
+.\"
+.\" 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.
+.\"
+.\"
+.TH BRCTL 8 "November 7, 2001" "" ""
+.SH NAME
+brctl \- ethernet bridge administration
+.SH SYNOPSIS
+.BR "brctl [command]"
+.SH DESCRIPTION
+.B brctl
+is used to set up, maintain, and inspect the ethernet bridge
+configuration in the Linux kernel.
+
+An ethernet bridge is a device commonly used to connect different
+networks of ethernets together, so that these ethernets will appear as
+one ethernet to the participants.
+
+Each of the ethernets being connected corresponds to one physical
+interface in the bridge. These individual ethernets are bundled into
+one bigger ('logical') ethernet, this bigger ethernet corresponds to
+the bridge network interface.
+
+
+.SH INSTANCES
+The command
+.B brctl addbr <name>
+creates a new instance of the ethernet bridge. The network interface
+corresponding to the bridge will be called <name>.
+
+The command
+.B brctl delbr <name>
+deletes the instance <name> of the ethernet bridge. The network
+interface corresponding to the bridge must be down before it can be
+deleted!
+
+The command
+.B brctl show
+shows all current instances of the ethernet bridge.
+
+
+.SH PORTS
+Each bridge has a number of ports attached to it. Network traffic
+coming in on any of these ports will be forwarded to the other ports
+transparently, so that the bridge is invisible to the rest of the
+network (i.e. it will not show up in
+.IR traceroute(8)
+).
+
+The command
+.B brctl addif <brname> <ifname>
+will make the interface <ifname> a port of the bridge <brname>. This
+means that all frames received on <ifname> will be processed as if
+destined for the bridge. Also, when sending frames on <brname>,
+<ifname> will be considered as a potential output interface.
+
+The command
+.B brctl delif <brname> <ifname>
+will detach the interface <ifname> from the bridge <brname>.
+
+The command
+.B brctl show <brname>
+will show some information on the bridge and its attached ports.
+
+
+.SH AGEING
+The bridge keeps track of ethernet addresses seen on each port. When
+it needs to forward a frame, and it happens to know on which port the
+destination ethernet address (specified in the frame) is located, it
+can 'cheat' by forwarding the frame to that port only, thus saving a
+lot of redundant copies and transmits.
+
+However, the ethernet address location data is not static
+data. Machines can move to other ports, network cards can be replaced
+(which changes the machine's ethernet address), etc.
+
+.B brctl showmacs <brname>
+shows a list of learned MAC addresses for this bridge.
+
+.B brctl setageing <brname> <time>
+sets the ethernet (MAC) address ageing time, in seconds. After <time>
+seconds of not having seen a frame coming from a certain address, the
+bridge will time out (delete) that address from the Forwarding
+DataBase (fdb).
+
+.B brctl setgcint <brname> <time>
+sets the garbage collection interval for the bridge <brname> to <time>
+seconds. This means that the bridge will check the forwarding database
+for timed out entries every <time> seconds.
+
+
+.SH SPANNING TREE PROTOCOL
+Multiple ethernet bridges can work together to create even larger
+networks of ethernets using the IEEE 802.1d spanning tree
+protocol. This protocol is used for finding the shortest path between
+two ethernets, and for eliminating loops from the topology. As this
+protocol is a standard, Linux bridges will interwork properly with
+other third party bridge products. Bridges communicate with each other
+by sending and receiving BPDUs (Bridge Protocol Data Units). These
+BPDUs can be recognised by an ethernet destination address of
+01:80:c2:00:00:00.
+
+The spanning tree protocol can also be turned off (for those
+situations where it just doesn't make sense, for example when this
+Linux box is the only bridge on the LAN, or when you know that there
+are no loops in the topology.)
+
+.IR brctl(8)
+can be used for configuring certain spanning tree protocol
+parameters. For an explanation of these parameters, see the IEEE
+802.1d specification (or send me an email). The default values should
+be just fine. If you don't know what these parameters mean, you
+probably won't feel the desire to tweak them.
+
+.B brctl stp <bridge> <state>
+controls this bridge instance's participation in the spanning tree
+protocol. If <state> is "on" or "yes" the STP will be turned on,
+otherwise it will be turned off. When turned off, the bridge will not
+send or receive BPDUs, and will thus not participate in the spanning
+tree protocol. If your bridge isn't the only bridge on the LAN, or if
+there are loops in the LAN's topology, DO NOT turn this option off. If
+you turn this option off, please know what you are doing.
+
+
+.B brctl setbridgeprio <bridge> <priority>
+sets the bridge's priority to <priority>. The priority value is an
+unsigned 16-bit quantity (a number between 0 and 65535), and has no
+dimension. Lower priority values are 'better'. The bridge with the
+lowest priority will be elected 'root bridge'.
+
+.B brctl setfd <bridge> <time>
+sets the bridge's 'bridge forward delay' to <time> seconds.
+
+.B brctl sethello <bridge> <time>
+sets the bridge's 'bridge hello time' to <time> seconds.
+
+.B brctl setmaxage <bridge> <time>
+sets the bridge's 'maximum message age' to <time> seconds.
+
+.B brctl setpathcost <bridge> <port> <cost>
+sets the port cost of the port <port> to <cost>. This is a
+dimensionless metric.
+
+.B brctl setportprio <bridge> <port> <priority>
+sets the port <port>'s priority to <priority>. The priority value is
+an unsigned 8-bit quantity (a number between 0 and 255), and has no
+dimension. This metric is used in the designated port and root port
+selection algorithms.
+
+
+.SH NOTES
+.BR brctl(8)
+replaces the older brcfg tool.
+
+.SH SEE ALSO
+.BR ipchains(8),
+.BR iptables(8)
+
+.SH AUTHOR
+Lennert Buytenhek <buytenh@gnu.org>
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, 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 M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/libbridge/.gitignore b/libbridge/.gitignore
new file mode 100644
index 0000000..f611548
--- /dev/null
+++ b/libbridge/.gitignore
@@ -0,0 +1,2 @@
+config.h
+stamp-h1
diff --git a/libbridge/Makefile.in b/libbridge/Makefile.in
new file mode 100644
index 0000000..20512c4
--- /dev/null
+++ b/libbridge/Makefile.in
@@ -0,0 +1,41 @@
+
+KERNEL_HEADERS=-I@KERNEL_HEADERS@
+
+AR=ar
+RANLIB=@RANLIB@
+
+CC=@CC@
+CFLAGS = -Wall -g $(KERNEL_HEADERS)
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+libbridge_SOURCES= \
+ libbridge_devif.c \
+ libbridge_if.c \
+ libbridge_init.c \
+ libbridge_misc.c
+
+libbridge_OBJECTS=$(libbridge_SOURCES:.c=.o)
+
+all: libbridge.a
+
+# At present there is no need for a bridge-utils-devel package
+install:
+
+
+clean:
+ rm -f *.o libbridge.a
+
+libbridge.a: $(libbridge_OBJECTS)
+ $(AR) rcs $@ $(libbridge_OBJECTS)
+ $(RANLIB) $@
+
+%.o: %.c libbridge.h libbridge_private.h
+ $(CC) $(CFLAGS) $(INCLUDE) -c $<
+
+libbridge_compat.o: libbridge_compat.c if_index.c
+ $(CC) $(CFLAGS) -c libbridge_compat.c
+
diff --git a/libbridge/config.h.in b/libbridge/config.h.in
new file mode 100644
index 0000000..22d1d7a
--- /dev/null
+++ b/libbridge/config.h.in
@@ -0,0 +1,79 @@
+/* libbridge/config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* 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 <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* 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 `strdup' function. */
+#undef HAVE_STRDUP
+
+/* 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 <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_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/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 `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* 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 home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
diff --git a/libbridge/libbridge.h b/libbridge/libbridge.h
new file mode 100644
index 0000000..39964f2
--- /dev/null
+++ b/libbridge/libbridge.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#ifndef _LIBBRIDGE_H
+#define _LIBBRIDGE_H
+
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_bridge.h>
+
+/* defined in net/if.h but that conflicts with linux/if.h... */
+extern unsigned int if_nametoindex (const char *__ifname);
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
+
+struct bridge_id
+{
+ unsigned char prio[2];
+ unsigned char addr[6];
+};
+
+struct bridge_info
+{
+ struct bridge_id designated_root;
+ struct bridge_id bridge_id;
+ unsigned root_path_cost;
+ struct timeval max_age;
+ struct timeval hello_time;
+ struct timeval forward_delay;
+ struct timeval bridge_max_age;
+ struct timeval bridge_hello_time;
+ struct timeval bridge_forward_delay;
+ u_int16_t root_port;
+ unsigned char stp_enabled;
+ unsigned char topology_change;
+ unsigned char topology_change_detected;
+ struct timeval ageing_time;
+ struct timeval hello_timer_value;
+ struct timeval tcn_timer_value;
+ struct timeval topology_change_timer_value;
+ struct timeval gc_timer_value;
+};
+
+struct fdb_entry
+{
+ u_int8_t mac_addr[6];
+ u_int16_t port_no;
+ unsigned char is_local;
+ struct timeval ageing_timer_value;
+};
+
+struct port_info
+{
+ unsigned port_no;
+ struct bridge_id designated_root;
+ struct bridge_id designated_bridge;
+ u_int16_t port_id;
+ u_int16_t designated_port;
+ u_int8_t priority;
+ unsigned char top_change_ack;
+ unsigned char config_pending;
+ unsigned char state;
+ unsigned path_cost;
+ unsigned designated_cost;
+ struct timeval message_age_timer_value;
+ struct timeval forward_delay_timer_value;
+ struct timeval hold_timer_value;
+ unsigned char hairpin_mode;
+};
+
+extern int br_init(void);
+extern int br_refresh(void);
+extern void br_shutdown(void);
+
+extern int br_foreach_bridge(int (*iterator)(const char *brname, void *),
+ void *arg);
+extern int br_foreach_port(const char *brname,
+ int (*iterator)(const char *brname, const char *port,
+ void *arg ),
+ void *arg);
+extern const char *br_get_state_name(int state);
+
+extern int br_get_bridge_info(const char *br, struct bridge_info *info);
+extern int br_get_port_info(const char *brname, const char *port,
+ struct port_info *info);
+extern int br_add_bridge(const char *brname);
+extern int br_del_bridge(const char *brname);
+extern int br_add_interface(const char *br, const char *dev);
+extern int br_del_interface(const char *br, const char *dev);
+extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv);
+extern int br_set_bridge_hello_time(const char *br, struct timeval *tv);
+extern int br_set_bridge_max_age(const char *br, struct timeval *tv);
+extern int br_set_ageing_time(const char *br, struct timeval *tv);
+extern int br_set_stp_state(const char *br, int stp_state);
+extern int br_set_bridge_priority(const char *br, int bridge_priority);
+extern int br_set_port_priority(const char *br, const char *p,
+ int port_priority);
+extern int br_set_path_cost(const char *br, const char *p,
+ int path_cost);
+extern int br_read_fdb(const char *br, struct fdb_entry *fdbs,
+ unsigned long skip, int num);
+extern int br_set_hairpin_mode(const char *bridge, const char *dev,
+ int hairpin_mode);
+#endif
diff --git a/libbridge/libbridge_devif.c b/libbridge/libbridge_devif.c
new file mode 100644
index 0000000..1e83925
--- /dev/null
+++ b/libbridge/libbridge_devif.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/fcntl.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+static FILE *fpopen(const char *dir, const char *name)
+{
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name);
+ return fopen(path, "r");
+}
+
+static void fetch_id(const char *dev, const char *name, struct bridge_id *id)
+{
+ FILE *f = fpopen(dev, name);
+
+ if (!f)
+ fprintf(stderr, "%s: %s\n", dev, strerror(errno));
+ else {
+ fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+ &id->prio[0], &id->prio[1],
+ &id->addr[0], &id->addr[1], &id->addr[2],
+ &id->addr[3], &id->addr[4], &id->addr[5]);
+ fclose(f);
+ }
+}
+
+/* Fetch an integer attribute out of sysfs. */
+static int fetch_int(const char *dev, const char *name)
+{
+ FILE *f = fpopen(dev, name);
+ int value = -1;
+
+ if (!f)
+ return 0;
+
+ fscanf(f, "%i", &value);
+ fclose(f);
+ return value;
+}
+
+/* Get a time value out of sysfs */
+static void fetch_tv(const char *dev, const char *name,
+ struct timeval *tv)
+{
+ __jiffies_to_tv(tv, fetch_int(dev, name));
+}
+
+/*
+ * Convert device name to an index in the list of ports in bridge.
+ *
+ * Old API does bridge operations as if ports were an array
+ * inside bridge structure.
+ */
+static int get_portno(const char *brname, const char *ifname)
+{
+ int i;
+ int ifindex = if_nametoindex(ifname);
+ int ifindices[MAX_PORTS];
+ unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+ (unsigned long)ifindices, MAX_PORTS, 0 };
+ struct ifreq ifr;
+
+ if (ifindex <= 0)
+ goto error;
+
+ memset(ifindices, 0, sizeof(ifindices));
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ dprintf("get_portno: get ports of %s failed: %s\n",
+ brname, strerror(errno));
+ goto error;
+ }
+
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (ifindices[i] == ifindex)
+ return i;
+ }
+
+ dprintf("%s is not a in bridge %s\n", ifname, brname);
+ error:
+ return -1;
+}
+
+/* get information via ioctl */
+static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
+{
+ struct ifreq ifr;
+ struct __bridge_info i;
+ unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
+ (unsigned long) &i, 0, 0 };
+
+ memset(info, 0, sizeof(*info));
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ dprintf("%s: can't get info %s\n",
+ bridge, strerror(errno));
+ return errno;
+ }
+
+ memcpy(&info->designated_root, &i.designated_root, 8);
+ memcpy(&info->bridge_id, &i.bridge_id, 8);
+ info->root_path_cost = i.root_path_cost;
+ info->root_port = i.root_port;
+ info->topology_change = i.topology_change;
+ info->topology_change_detected = i.topology_change_detected;
+ info->stp_enabled = i.stp_enabled;
+ __jiffies_to_tv(&info->max_age, i.max_age);
+ __jiffies_to_tv(&info->hello_time, i.hello_time);
+ __jiffies_to_tv(&info->forward_delay, i.forward_delay);
+ __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age);
+ __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time);
+ __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay);
+ __jiffies_to_tv(&info->ageing_time, i.ageing_time);
+ __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value);
+ __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value);
+ __jiffies_to_tv(&info->topology_change_timer_value,
+ i.topology_change_timer_value);
+ __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value);
+
+ return 0;
+}
+
+/*
+ * Get bridge parameters using either sysfs or old
+ * ioctl.
+ */
+int br_get_bridge_info(const char *bridge, struct bridge_info *info)
+{
+ DIR *dir;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge);
+ dir = opendir(path);
+ if (dir == NULL) {
+ dprintf("path '%s' is not a directory\n", path);
+ goto fallback;
+ }
+
+ memset(info, 0, sizeof(*info));
+ fetch_id(path, "root_id", &info->designated_root);
+ fetch_id(path, "bridge_id", &info->bridge_id);
+ info->root_path_cost = fetch_int(path, "root_path_cost");
+ fetch_tv(path, "max_age", &info->max_age);
+ fetch_tv(path, "hello_time", &info->hello_time);
+ fetch_tv(path, "forward_delay", &info->forward_delay);
+ fetch_tv(path, "max_age", &info->bridge_max_age);
+ fetch_tv(path, "hello_time", &info->bridge_hello_time);
+ fetch_tv(path, "forward_delay", &info->bridge_forward_delay);
+ fetch_tv(path, "ageing_time", &info->ageing_time);
+ fetch_tv(path, "hello_timer", &info->hello_timer_value);
+ fetch_tv(path, "tcn_timer", &info->tcn_timer_value);
+ fetch_tv(path, "topology_change_timer",
+ &info->topology_change_timer_value);;
+ fetch_tv(path, "gc_timer", &info->gc_timer_value);
+
+ info->root_port = fetch_int(path, "root_port");
+ info->stp_enabled = fetch_int(path, "stp_state");
+ info->topology_change = fetch_int(path, "topology_change");
+ info->topology_change_detected = fetch_int(path, "topology_change_detected");
+
+ closedir(dir);
+ return 0;
+
+fallback:
+ return old_get_bridge_info(bridge, info);
+}
+
+static int old_get_port_info(const char *brname, const char *port,
+ struct port_info *info)
+{
+ struct __port_info i;
+ int index;
+
+ memset(info, 0, sizeof(*info));
+
+ index = get_portno(brname, port);
+ if (index < 0)
+ return errno;
+
+ else {
+ struct ifreq ifr;
+ unsigned long args[4] = { BRCTL_GET_PORT_INFO,
+ (unsigned long) &i, index, 0 };
+
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ dprintf("old can't get port %s(%d) info %s\n",
+ brname, index, strerror(errno));
+ return errno;
+ }
+ }
+
+ info->port_no = index;
+ memcpy(&info->designated_root, &i.designated_root, 8);
+ memcpy(&info->designated_bridge, &i.designated_bridge, 8);
+ info->port_id = i.port_id;
+ info->designated_port = i.designated_port;
+ info->path_cost = i.path_cost;
+ info->designated_cost = i.designated_cost;
+ info->state = i.state;
+ info->top_change_ack = i.top_change_ack;
+ info->config_pending = i.config_pending;
+ __jiffies_to_tv(&info->message_age_timer_value,
+ i.message_age_timer_value);
+ __jiffies_to_tv(&info->forward_delay_timer_value,
+ i.forward_delay_timer_value);
+ __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value);
+ info->hairpin_mode = 0;
+ return 0;
+}
+
+/*
+ * Get information about port on bridge.
+ */
+int br_get_port_info(const char *brname, const char *port,
+ struct port_info *info)
+{
+ DIR *d;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port);
+ d = opendir(path);
+ if (!d)
+ goto fallback;
+
+ memset(info, 0, sizeof(*info));
+
+ fetch_id(path, "designated_root", &info->designated_root);
+ fetch_id(path, "designated_bridge", &info->designated_bridge);
+ info->port_no = fetch_int(path, "port_no");
+ info->port_id = fetch_int(path, "port_id");
+ info->designated_port = fetch_int(path, "designated_port");
+ info->path_cost = fetch_int(path, "path_cost");
+ info->designated_cost = fetch_int(path, "designated_cost");
+ info->state = fetch_int(path, "state");
+ info->top_change_ack = fetch_int(path, "change_ack");
+ info->config_pending = fetch_int(path, "config_pending");
+ fetch_tv(path, "message_age_timer", &info->message_age_timer_value);
+ fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value);
+ fetch_tv(path, "hold_timer", &info->hold_timer_value);
+ info->hairpin_mode = fetch_int(path, "hairpin_mode");
+
+ closedir(d);
+
+ return 0;
+fallback:
+ return old_get_port_info(brname, port, info);
+}
+
+static int set_sysfs(const char *path, unsigned long value)
+{
+ int fd, ret = 0, cc;
+ char buf[32];
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ cc = snprintf(buf, sizeof(buf), "%lu\n", value);
+ if (write(fd, buf, cc) < 0)
+ ret = -1;
+ close(fd);
+
+ return ret;
+}
+
+
+static int br_set(const char *bridge, const char *name,
+ unsigned long value, unsigned long oldcode)
+{
+ int ret;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge/%s",
+ bridge, name);
+
+ if ((ret = set_sysfs(path, value)) < 0) {
+ /* fallback to old ioctl */
+ struct ifreq ifr;
+ unsigned long args[4] = { oldcode, value, 0, 0 };
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+ ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+
+ return ret < 0 ? errno : 0;
+}
+
+int br_set_bridge_forward_delay(const char *br, struct timeval *tv)
+{
+ return br_set(br, "forward_delay", __tv_to_jiffies(tv),
+ BRCTL_SET_BRIDGE_FORWARD_DELAY);
+}
+
+int br_set_bridge_hello_time(const char *br, struct timeval *tv)
+{
+ return br_set(br, "hello_time", __tv_to_jiffies(tv),
+ BRCTL_SET_BRIDGE_HELLO_TIME);
+}
+
+int br_set_bridge_max_age(const char *br, struct timeval *tv)
+{
+ return br_set(br, "max_age", __tv_to_jiffies(tv),
+ BRCTL_SET_BRIDGE_MAX_AGE);
+}
+
+int br_set_ageing_time(const char *br, struct timeval *tv)
+{
+ return br_set(br, "ageing_time", __tv_to_jiffies(tv),
+ BRCTL_SET_AGEING_TIME);
+}
+
+int br_set_stp_state(const char *br, int stp_state)
+{
+ return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE);
+}
+
+int br_set_bridge_priority(const char *br, int bridge_priority)
+{
+ return br_set(br, "priority", bridge_priority,
+ BRCTL_SET_BRIDGE_PRIORITY);
+}
+
+static int port_set(const char *bridge, const char *ifname,
+ const char *name, unsigned long value,
+ unsigned long oldcode)
+{
+ int ret;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name);
+
+ if ((ret = set_sysfs(path, value)) < 0) {
+ int index = get_portno(bridge, ifname);
+
+ if (index < 0)
+ ret = index;
+ else {
+ struct ifreq ifr;
+ unsigned long args[4] = { oldcode, index, value, 0 };
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+ ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+ }
+
+ return ret < 0 ? errno : 0;
+}
+
+int br_set_port_priority(const char *bridge, const char *port, int priority)
+{
+ return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY);
+}
+
+int br_set_path_cost(const char *bridge, const char *port, int cost)
+{
+ return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST);
+}
+
+int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode)
+{
+ return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0);
+}
+
+static inline void __copy_fdb(struct fdb_entry *ent,
+ const struct __fdb_entry *f)
+{
+ memcpy(ent->mac_addr, f->mac_addr, 6);
+ ent->port_no = f->port_no;
+ ent->is_local = f->is_local;
+ __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value);
+}
+
+int br_read_fdb(const char *bridge, struct fdb_entry *fdbs,
+ unsigned long offset, int num)
+{
+ FILE *f;
+ int i, n;
+ struct __fdb_entry fe[num];
+ char path[SYSFS_PATH_MAX];
+
+ /* open /sys/class/net/brXXX/brforward */
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge);
+ f = fopen(path, "r");
+ if (f) {
+ fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
+ n = fread(fe, sizeof(struct __fdb_entry), num, f);
+ fclose(f);
+ } else {
+ /* old kernel, use ioctl */
+ unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES,
+ (unsigned long) fe,
+ num, offset };
+ struct ifreq ifr;
+ int retries = 0;
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+ ifr.ifr_data = (char *) args;
+
+ retry:
+ n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+
+ /* table can change during ioctl processing */
+ if (n < 0 && errno == EAGAIN && ++retries < 10) {
+ sleep(0);
+ goto retry;
+ }
+ }
+
+ for (i = 0; i < n; i++)
+ __copy_fdb(fdbs+i, fe+i);
+
+ return n;
+}
diff --git a/libbridge/libbridge_if.c b/libbridge/libbridge_if.c
new file mode 100644
index 0000000..77d3f8a
--- /dev/null
+++ b/libbridge/libbridge_if.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+
+int br_add_bridge(const char *brname)
+{
+ int ret;
+
+#ifdef SIOCBRADDBR
+ ret = ioctl(br_socket_fd, SIOCBRADDBR, brname);
+ if (ret < 0)
+#endif
+ {
+ char _br[IFNAMSIZ];
+ unsigned long arg[3]
+ = { BRCTL_ADD_BRIDGE, (unsigned long) _br };
+
+ strncpy(_br, brname, IFNAMSIZ);
+ ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
+ }
+
+ return ret < 0 ? errno : 0;
+}
+
+int br_del_bridge(const char *brname)
+{
+ int ret;
+
+#ifdef SIOCBRDELBR
+ ret = ioctl(br_socket_fd, SIOCBRDELBR, brname);
+ if (ret < 0)
+#endif
+ {
+ char _br[IFNAMSIZ];
+ unsigned long arg[3]
+ = { BRCTL_DEL_BRIDGE, (unsigned long) _br };
+
+ strncpy(_br, brname, IFNAMSIZ);
+ ret = ioctl(br_socket_fd, SIOCSIFBR, arg);
+ }
+ return ret < 0 ? errno : 0;
+}
+
+int br_add_interface(const char *bridge, const char *dev)
+{
+ struct ifreq ifr;
+ int err;
+ int ifindex = if_nametoindex(dev);
+
+ if (ifindex == 0)
+ return ENODEV;
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+#ifdef SIOCBRADDIF
+ ifr.ifr_ifindex = ifindex;
+ err = ioctl(br_socket_fd, SIOCBRADDIF, &ifr);
+ if (err < 0)
+#endif
+ {
+ unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
+
+ ifr.ifr_data = (char *) args;
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+
+ return err < 0 ? errno : 0;
+}
+
+int br_del_interface(const char *bridge, const char *dev)
+{
+ struct ifreq ifr;
+ int err;
+ int ifindex = if_nametoindex(dev);
+
+ if (ifindex == 0)
+ return ENODEV;
+
+ strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+#ifdef SIOCBRDELIF
+ ifr.ifr_ifindex = ifindex;
+ err = ioctl(br_socket_fd, SIOCBRDELIF, &ifr);
+ if (err < 0)
+#endif
+ {
+ unsigned long args[4] = { BRCTL_DEL_IF, ifindex, 0, 0 };
+
+ ifr.ifr_data = (char *) args;
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ }
+
+ return err < 0 ? errno : 0;
+}
diff --git a/libbridge/libbridge_init.c b/libbridge/libbridge_init.c
new file mode 100644
index 0000000..f3a551e
--- /dev/null
+++ b/libbridge/libbridge_init.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+int br_socket_fd = -1;
+
+int br_init(void)
+{
+ if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+ return errno;
+ return 0;
+}
+
+void br_shutdown(void)
+{
+ close(br_socket_fd);
+ br_socket_fd = -1;
+}
+
+/* If /sys/class/net/XXX/bridge exists then it must be a bridge */
+static int isbridge(const struct dirent *entry)
+{
+ char path[SYSFS_PATH_MAX];
+ struct stat st;
+ int ret, saved_errno;
+
+ if (entry->d_name[0] == '.'
+ && (entry->d_name[1] == '\0'
+ || (entry->d_name[1] == '.'
+ && entry->d_name[2] == '\0')))
+ return 0;
+
+ snprintf(path, SYSFS_PATH_MAX,
+ SYSFS_CLASS_NET "%s/bridge", entry->d_name);
+
+ /* Workaround old glibc breakage.
+ If errno is set, then it fails scandir! */
+ saved_errno = errno;
+ ret = (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
+ errno = saved_errno;
+
+ return ret;
+}
+
+/*
+ * New interface uses sysfs to find bridges
+ */
+static int new_foreach_bridge(int (*iterator)(const char *name, void *),
+ void *arg)
+{
+ struct dirent **namelist;
+ int i, count = 0;
+
+ count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
+ if (count < 0)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ if (iterator(namelist[i]->d_name, arg))
+ break;
+ }
+
+ for (i = 0; i < count; i++)
+ free(namelist[i]);
+ free(namelist);
+
+ return count;
+}
+
+/*
+ * Old interface uses ioctl
+ */
+static int old_foreach_bridge(int (*iterator)(const char *, void *),
+ void *iarg)
+{
+ int i, ret=0, num;
+ char ifname[IFNAMSIZ];
+ int ifindices[MAX_BRIDGES];
+ unsigned long args[3] = { BRCTL_GET_BRIDGES,
+ (unsigned long)ifindices, MAX_BRIDGES };
+
+ num = ioctl(br_socket_fd, SIOCGIFBR, args);
+ if (num < 0) {
+ dprintf("Get bridge indices failed: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (!if_indextoname(ifindices[i], ifname)) {
+ dprintf("get find name for ifindex %d\n",
+ ifindices[i]);
+ return -errno;
+ }
+
+ ++ret;
+ if(iterator(ifname, iarg))
+ break;
+
+ }
+
+ return ret;
+
+}
+
+/*
+ * Go over all bridges and call iterator function.
+ * if iterator returns non-zero then stop.
+ */
+int br_foreach_bridge(int (*iterator)(const char *, void *),
+ void *arg)
+{
+ int ret;
+
+ ret = new_foreach_bridge(iterator, arg);
+ if (ret <= 0)
+ ret = old_foreach_bridge(iterator, arg);
+
+ return ret;
+}
+
+/*
+ * Only used if sysfs is not available.
+ */
+static int old_foreach_port(const char *brname,
+ int (*iterator)(const char *br, const char *port,
+ void *arg),
+ void *arg)
+{
+ int i, err, count;
+ struct ifreq ifr;
+ char ifname[IFNAMSIZ];
+ int ifindices[MAX_PORTS];
+ unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+ (unsigned long)ifindices, MAX_PORTS, 0 };
+
+ memset(ifindices, 0, sizeof(ifindices));
+ strncpy(ifr.ifr_name, brname, IFNAMSIZ);
+ ifr.ifr_data = (char *) &args;
+
+ err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
+ if (err < 0) {
+ dprintf("list ports for bridge:'%s' failed: %s\n",
+ brname, strerror(errno));
+ return -errno;
+ }
+
+ count = 0;
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (!ifindices[i])
+ continue;
+
+ if (!if_indextoname(ifindices[i], ifname)) {
+ dprintf("can't find name for ifindex:%d\n",
+ ifindices[i]);
+ continue;
+ }
+
+ ++count;
+ if (iterator(brname, ifname, arg))
+ break;
+ }
+
+ return count;
+}
+
+/*
+ * Iterate over all ports in bridge (using sysfs).
+ */
+int br_foreach_port(const char *brname,
+ int (*iterator)(const char *br, const char *port, void *arg),
+ void *arg)
+{
+ int i, count;
+ struct dirent **namelist;
+ char path[SYSFS_PATH_MAX];
+
+ snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
+ count = scandir(path, &namelist, 0, alphasort);
+ if (count < 0)
+ return old_foreach_port(brname, iterator, arg);
+
+ for (i = 0; i < count; i++) {
+ if (namelist[i]->d_name[0] == '.'
+ && (namelist[i]->d_name[1] == '\0'
+ || (namelist[i]->d_name[1] == '.'
+ && namelist[i]->d_name[2] == '\0')))
+ continue;
+
+ if (iterator(brname, namelist[i]->d_name, arg))
+ break;
+ }
+ for (i = 0; i < count; i++)
+ free(namelist[i]);
+ free(namelist);
+
+ return count;
+}
diff --git a/libbridge/libbridge_misc.c b/libbridge/libbridge_misc.c
new file mode 100644
index 0000000..5791638
--- /dev/null
+++ b/libbridge/libbridge_misc.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <asm/param.h>
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+
+static const char *state_names[5] = {
+ [BR_STATE_DISABLED] = "disabled",
+ [BR_STATE_LISTENING] = "listening",
+ [BR_STATE_LEARNING] = "learning",
+ [BR_STATE_FORWARDING] = "forwarding",
+ [BR_STATE_BLOCKING] = "blocking",
+};
+
+const char *br_get_state_name(int state)
+{
+ if (state >= 0 && state <= 4)
+ return state_names[state];
+
+ return "<INVALID STATE>";
+}
+
+int __br_hz_internal;
+
+int __get_hz(void)
+{
+ const char * s = getenv("HZ");
+ return s ? atoi(s) : HZ;
+}
diff --git a/libbridge/libbridge_private.h b/libbridge/libbridge_private.h
new file mode 100644
index 0000000..99a511d
--- /dev/null
+++ b/libbridge/libbridge_private.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * 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.
+ */
+
+#ifndef _LIBBRIDGE_PRIVATE_H
+#define _LIBBRIDGE_PRIVATE_H
+
+#include "config.h"
+
+#include <linux/sockios.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/if_bridge.h>
+
+#define MAX_BRIDGES 1024
+#define MAX_PORTS 1024
+
+#define SYSFS_CLASS_NET "/sys/class/net/"
+#define SYSFS_PATH_MAX 256
+
+#define dprintf(fmt,arg...)
+
+extern int br_socket_fd;
+
+static inline unsigned long __tv_to_jiffies(const struct timeval *tv)
+{
+ unsigned long long jif;
+
+ jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
+
+ return jif/10000;
+}
+
+static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
+{
+ unsigned long long tvusec;
+
+ tvusec = 10000ULL*jiffies;
+ tv->tv_sec = tvusec/1000000;
+ tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
+}
+#endif
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..81a40bc
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,14 @@
+This is a set of shell scripts for testing Ethernet bridging.
+
+mkbr makes a simple bridge and clones the ip address.
+rmbr removes bridge
+
+The functional test needs two ethernets (eth0, eth1,
+and the dummy network device. It may screw up your route
+table. Also, it leaves eth0 in an bad state if test fails.
+
+The stresstest needs two ethernets (eth0 and eth1).
+For highest stress, traffic should be sent over the bridge
+while the test is ongoing. The goal is to exercise, races
+that occur when traffic is flowing while management operations occur.
+
diff --git a/tests/busybr b/tests/busybr
new file mode 100755
index 0000000..bdaed46
--- /dev/null
+++ b/tests/busybr
@@ -0,0 +1,23 @@
+#! /bin/sh
+BR=${1:-"br549"}
+ETH0=${1:-"eth0"}
+ETH1=${1:-"eth1"}
+
+# fetch ip of working br0
+IP=`/sbin/ifconfig $BR | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'`
+echo "Using IP address $IP"
+
+while true;
+do
+ ifconfig $BR down
+ brctl delbr $BR
+ ifconfig $ETH0 $IP
+
+ ifconfig $ETH0 0.0.0.0
+ brctl addbr $BR
+ brctl addif $BR $ETH0
+ brctl addif $BR $ETH1
+ ifconfig $BR $IP
+
+ sleep 10
+done
diff --git a/tests/functest b/tests/functest
new file mode 100755
index 0000000..a321c59
--- /dev/null
+++ b/tests/functest
@@ -0,0 +1,171 @@
+#! /bin/bash
+BR=${1:-"br549"}
+ETH=${2:-"eth0"}
+maxports=${3:-1000}
+
+echo "Ethernet Bridge functional test"
+
+echo -n "Testing kernel: " ; uname -a
+echo -n "Utilities: " ; brctl -V
+
+# fetch ip of working $ETH
+IP=`/sbin/ifconfig $ETH | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'`
+echo "Using IP address $IP"
+
+# All commands in this part must succeed
+set -e
+
+echo "0. Creating $maxports dummy devices"
+modprobe dummy numdummies=$maxports
+
+echo "1. Creating bridge $BR"
+brctl addbr $BR
+brctl stp $BR on
+
+echo "2. Add $ETH"
+ifconfig $ETH 0.0.0.0
+brctl addif $BR $ETH
+
+echo "3. Bring up bridge"
+ifconfig $BR $IP
+
+echo "4 Bring up another bridge"
+brctl addbr "brx%d"
+ifconfig brx0 1.1.1.1
+
+echo "5 Bring down bridge"
+ifconfig brx0 down
+brctl delbr brx0
+
+echo -n "6. Add " $maxports " ports:"
+for (( i=1; i < $maxports; i++))
+do
+ brctl addif $BR dummy$i
+ if [[ $(( $i % 10 )) -eq 10 ]]
+ then echo -n '.'
+ fi
+done
+echo
+
+echo -n "7. Delete those ports:"
+for (( i=1; i < $maxports; i++))
+do
+ brctl delif $BR dummy$i
+ if [[ $(( $i % 10 )) -eq 10 ]]
+ then echo -n '.'
+ fi
+done
+echo
+
+echo "8. Notififer cases"
+brctl addif $BR dummy0
+
+echo "8a Device down"
+ifconfig dummy0 down
+
+echo "8b Change device address"
+ifconfig dummy0 hw ether 00:0d:02:03:04:05
+
+echo "8c. Device up"
+ifconfig dummy0 up
+
+echo "8d Unregister device (slow)"
+rmmod dummy
+echo "** Done"
+
+modprobe dummy numdummies=2
+
+set +e
+
+echo "10 Error cases"
+echo -n " duplicate bridge - "
+brctl addbr $BR
+
+echo -n " bridge to bridge - "
+brctl addbr brTmp
+brctl addif $BR brTmp
+
+echo -n " already in other bridge - "
+brctl addif brTmp $ETH
+
+echo -n " already in this bridge - "
+brctl addif $BR $ETH
+
+echo -n " remove from wrong bridge - "
+brctl delif brTmp $ETH
+brctl delbr brTmp
+
+echo -n " remove bridge $ETH - "
+brctl delbr $ETH
+
+echo -n " remove bridge bogus - "
+brctl delbr bogus
+
+echo -n " remove still active bridge - "
+brctl delbr $BR
+
+echo -n " zero hw address - "
+ifconfig dummy0 hw ether 00:00:00:00:00:00
+brctl addif $BR dummy0
+
+echo -n " duplicate hw address - "
+ifconfig dummy0 hw ether 00:0d:01:00:00:00
+ifconfig dummy1 hw ether 00:0d:01:00:00:00
+brctl addif $BR dummy0
+brctl addif $BR dummy1
+# leave dummy0 for next test.
+
+echo "10 Tuning"
+set -e
+brctl stp $BR off
+brctl stp $BR on
+brctl setageing $BR 4000
+brctl setbridgeprio $BR 1
+brctl setfd $BR 120
+brctl sethello $BR 20
+brctl setmaxage $BR 1000
+brctl setpathcost $BR dummy0 50
+brctl setportprio $BR dummy0 2
+
+echo "Status check"
+brctl show
+read -p "Ok?"
+brctl showstp $BR
+read -p "Ok?"
+brctl showmacs $BR
+read -p "Ok?"
+
+
+echo "30 Shutdown"
+ifconfig $BR down
+brctl delbr $BR
+ifconfig $ETH $IP
+
+echo "31 Remove bridge module"
+rmmod bridge
+rmmod dummy
+rmmod bridge
+
+echo "32 Check for dead bridge cleanup"
+brctl addbr $BR
+rmmod bridge
+modprobe bridge
+sleep 1
+
+echo "33 Remove module with race"
+brctl addbr $BR
+ifconfig $BR 9.9.9.9
+
+rmmod --wait bridge &
+sleep 2
+brctl addbr brXX
+if ifconfig brXX 1.1.1.1 ; then
+ echo "?? ifconfig succeeded"
+ ifconfig brXX down
+fi
+
+ifconfig $BR down
+wait
+
+echo "*** Done ***"
+
diff --git a/tests/mkbr b/tests/mkbr
new file mode 100755
index 0000000..1d64e82
--- /dev/null
+++ b/tests/mkbr
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+BR=${1:-"br549"}
+ETH=${2:-"eth0"}
+
+# fetch ip of working eth0
+IP=`/sbin/ifconfig $ETH | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'`
+echo "Using IP address $IP"
+
+ifconfig $ETH 0.0.0.0
+brctl addbr $BR
+brctl addif $BR $ETH
+ifconfig $BR $IP
diff --git a/tests/rmbr b/tests/rmbr
new file mode 100755
index 0000000..8d1dc30
--- /dev/null
+++ b/tests/rmbr
@@ -0,0 +1,11 @@
+#! /bin/sh
+BR=${1:-"br549"}
+
+# fetch ip of working br0
+IP=`/sbin/ifconfig $BR | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'`
+echo "Using IP address $IP"
+
+ifconfig $BR down
+brctl delbr $BR
+ifconfig eth0 172.20.5.22
+rmmod bridge
diff --git a/tests/showme b/tests/showme
new file mode 100755
index 0000000..7bc869e
--- /dev/null
+++ b/tests/showme
@@ -0,0 +1,10 @@
+#!/bin/bash
+BR=${1:-"br549"}
+
+while true;
+do
+ brctl show
+ brctl showstp $BR
+ brctl showmacs $BR
+ sleep 5
+done
diff --git a/tests/stresstest b/tests/stresstest
new file mode 100755
index 0000000..5d529d8
--- /dev/null
+++ b/tests/stresstest
@@ -0,0 +1,66 @@
+#! /bin/bash
+
+BR=${1:-"br549"}
+ETH0=${2:-"eth0"}
+ETH1=${3:-"eth1"}
+ETH2=${4:-"eth1"}
+
+echo "Ethernet Bridge stress test"
+
+IP=`/sbin/ifconfig $ETH0 | sed -n -e 's/^.*inet addr:\([0-9][0-9\.]*\).*$/\1/p'`
+echo $IP
+
+inout() {
+ while true;
+ do
+ brctl addif $1 $2
+ sleep $(($RANDOM % 10))
+ brctl delif $1 $2
+ done
+}
+
+newdel() {
+ while true;
+ do
+ brctl addbr $1
+ brctl delbr $1
+ done
+}
+
+updown() {
+ while true;
+ do
+ ifconfig $1 down
+ ifconfig $1 up
+ sleep 11
+ done
+}
+
+echo "1. Creating bridge $BR"
+brctl addbr $BR
+
+echo -n "2. Add ethernets"
+ifconfig $ETH0 0.0.0.0
+brctl addif $BR $ETH0
+echo -n $ETH0
+ifconfig $ETH2 0.0.0.0
+brctl addif $BR $ETH2
+echo $ETH2
+
+echo "4. Starting add/del interface" $ETH1
+ifconfig $ETH1 0.0.0.0
+inout $BR $ETH1 &
+ipid=$!
+
+echo "5. Starting add/remove bridge"
+newdel brtmp1 &
+npid=$!
+
+echo "6. Starting up/down" $ETH1
+updown $BR $ETH1 &
+upid=$!
+
+trap "kill $ipid $npid $upid" 1 2 3 15
+
+echo " Waiting"
+wait