From 83f7687a91638a399621f7fbb5b832d84d53c57f Mon Sep 17 00:00:00 2001
From: p4u
Date: Thu, 4 Apr 2013 13:56:25 +0200
Subject: [PATCH 1/1] First commit with the existing packages
---
packages/bmx6-luci/COPYING | 339 ++
packages/bmx6-luci/Makefile | 62 +
packages/bmx6-luci/files/etc/config/luci-bmx6 | 7 +
.../usr/lib/lua/luci/controller/bmx6.lua | 329 ++
.../files/usr/lib/lua/luci/model/bmx6json.lua | 219 ++
.../lib/lua/luci/model/cbi/bmx6/advanced.lua | 74 +
.../usr/lib/lua/luci/model/cbi/bmx6/hna.lua | 47 +
.../lua/luci/model/cbi/bmx6/interfaces.lua | 77 +
.../usr/lib/lua/luci/model/cbi/bmx6/main.lua | 108 +
.../lib/lua/luci/model/cbi/bmx6/plugins.lua | 50 +
.../lib/lua/luci/model/cbi/bmx6/tunnels.lua | 75 +
.../admin_status/index/neighbours_simple.htm | 108 +
.../files/usr/lib/lua/luci/view/bmx6/chat.htm | 35 +
.../usr/lib/lua/luci/view/bmx6/error.htm | 10 +
.../usr/lib/lua/luci/view/bmx6/gateways_j.htm | 120 +
.../usr/lib/lua/luci/view/bmx6/graph.htm | 110 +
.../usr/lib/lua/luci/view/bmx6/interfaces.htm | 59 +
.../usr/lib/lua/luci/view/bmx6/links.htm | 55 +
.../usr/lib/lua/luci/view/bmx6/neighbours.htm | 89 +
.../lib/lua/luci/view/bmx6/neighbours_j.htm | 188 +
.../usr/lib/lua/luci/view/bmx6/nodes.htm | 87 +
.../usr/lib/lua/luci/view/bmx6/nodes_j.htm | 193 +
.../usr/lib/lua/luci/view/bmx6/status.htm | 69 +
.../usr/lib/lua/luci/view/bmx6/status_j.htm | 114 +
.../usr/lib/lua/luci/view/bmx6/tunnels_j.htm | 107 +
.../usr/lib/lua/luci/view/bmx6/wireless.htm | 7 +
.../bmx6-luci/files/www/cgi-bin/bmx6-info | 112 +
.../luci-static/resources/bmx6/bmx6logo.png | Bin 0 -> 4986 bytes
.../resources/bmx6/js/Curry-1.0.1.js | 29 +
.../resources/bmx6/js/dracula_algorithms.js | 599 ++++
.../resources/bmx6/js/dracula_graffle.js | 106 +
.../resources/bmx6/js/dracula_graph.js | 527 +++
.../resources/bmx6/js/jquery-1.4.2.min.js | 154 +
.../luci-static/resources/bmx6/js/polling.js | 81 +
.../resources/bmx6/js/raphael-min.js | 7 +
.../resources/bmx6/js/seedrandom.js | 266 ++
.../www/luci-static/resources/bmx6/link.png | Bin 0 -> 2910 bytes
.../www/luci-static/resources/bmx6/style.css | 22 +
.../www/luci-static/resources/bmx6/wifi.png | Bin 0 -> 3551 bytes
.../www/luci-static/resources/bmx6/world.png | Bin 0 -> 1885 bytes
.../resources/bmx6/world_small.png | Bin 0 -> 923 bytes
packages/bmx6-qmp/Makefile | 157 +
packages/bmx6-qmp/files/etc/config/bmx6 | 82 +
packages/bmx6-qmp/files/etc/init.d/bmx6 | 41 +
packages/qmp-quagga/Makefile | 312 ++
packages/qmp-quagga/files/quagga | 335 ++
packages/qmp-quagga/files/quagga.conf | 7 +
packages/qmp-quagga/files/quagga.init | 11 +
.../patches/110-fix_ipctl_forwarding.patch | 25 +
.../qmp-quagga/patches/120-quagga_manet.patch | 243 ++
.../qmp-quagga/patches/121-quagga-bmx6.patch | 127 +
packages/qmp-quagga/patches/130-fix_cpp.patch | 11 +
.../patches/140-holdtimer-set.patch | 22 +
.../patches/150-no-cross-fs-link.patch | 40 +
packages/qmp-quagga/patches/160-pgbgp.patch | 3104 +++++++++++++++++
.../qmp-quagga/patches/161-pgbgp-addon.patch | 318 ++
.../patches/170-use-supported-pagers.patch | 29 +
57 files changed, 9505 insertions(+)
create mode 100644 packages/bmx6-luci/COPYING
create mode 100644 packages/bmx6-luci/Makefile
create mode 100644 packages/bmx6-luci/files/etc/config/luci-bmx6
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/controller/bmx6.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/bmx6json.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/advanced.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/hna.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/interfaces.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/main.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/plugins.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/tunnels.lua
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/admin_status/index/neighbours_simple.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/chat.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/error.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/gateways_j.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/graph.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/interfaces.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/links.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/neighbours.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/neighbours_j.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/nodes.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/nodes_j.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/status.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/status_j.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/tunnels_j.htm
create mode 100644 packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/wireless.htm
create mode 100644 packages/bmx6-luci/files/www/cgi-bin/bmx6-info
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/bmx6logo.png
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/Curry-1.0.1.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/dracula_algorithms.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/dracula_graffle.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/dracula_graph.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/jquery-1.4.2.min.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/polling.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/raphael-min.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/js/seedrandom.js
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/link.png
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/style.css
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/wifi.png
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/world.png
create mode 100644 packages/bmx6-luci/files/www/luci-static/resources/bmx6/world_small.png
create mode 100644 packages/bmx6-qmp/Makefile
create mode 100644 packages/bmx6-qmp/files/etc/config/bmx6
create mode 100755 packages/bmx6-qmp/files/etc/init.d/bmx6
create mode 100644 packages/qmp-quagga/Makefile
create mode 100644 packages/qmp-quagga/files/quagga
create mode 100644 packages/qmp-quagga/files/quagga.conf
create mode 100644 packages/qmp-quagga/files/quagga.init
create mode 100644 packages/qmp-quagga/patches/110-fix_ipctl_forwarding.patch
create mode 100644 packages/qmp-quagga/patches/120-quagga_manet.patch
create mode 100644 packages/qmp-quagga/patches/121-quagga-bmx6.patch
create mode 100644 packages/qmp-quagga/patches/130-fix_cpp.patch
create mode 100644 packages/qmp-quagga/patches/140-holdtimer-set.patch
create mode 100644 packages/qmp-quagga/patches/150-no-cross-fs-link.patch
create mode 100644 packages/qmp-quagga/patches/160-pgbgp.patch
create mode 100644 packages/qmp-quagga/patches/161-pgbgp-addon.patch
create mode 100644 packages/qmp-quagga/patches/170-use-supported-pagers.patch
diff --git a/packages/bmx6-luci/COPYING b/packages/bmx6-luci/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/packages/bmx6-luci/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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.
+
+
+ Copyright (C)
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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.
+
+ , 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 Lesser General
+Public License instead of this License.
diff --git a/packages/bmx6-luci/Makefile b/packages/bmx6-luci/Makefile
new file mode 100644
index 0000000..4fd86b8
--- /dev/null
+++ b/packages/bmx6-luci/Makefile
@@ -0,0 +1,62 @@
+# Copyright (C) 2011 Pau Escrich
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bmx6-luci
+PKG_RELEASE:=2
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/bmx6-luci
+ SECTION:=luci
+ CATEGORY:=LuCI
+ SUBMENU:=3. Applications
+ TITLE:= Bmx6 configuration, status and visualization module
+# DEPENDS:=+bmx6 +bmx6-uci-config
+ DEPENDS:=+luci-lib-json +luci-mod-admin-core +luci-lib-httpclient
+endef
+
+define Package/bmx6-luci/description
+ bmx6 web module for LuCi web interface
+endef
+
+define Package/bmx6-luci/conffiles
+ /etc/config/luci-bmx6
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/bmx6-luci/install
+ $(CP) ./files/* $(1)/
+ chmod 755 $(1)/www/cgi-bin/bmx6-info
+endef
+
+$(eval $(call BuildPackage,bmx6-luci))
+
diff --git a/packages/bmx6-luci/files/etc/config/luci-bmx6 b/packages/bmx6-luci/files/etc/config/luci-bmx6
new file mode 100644
index 0000000..f70205b
--- /dev/null
+++ b/packages/bmx6-luci/files/etc/config/luci-bmx6
@@ -0,0 +1,7 @@
+config 'bmx6' 'luci'
+ option ignore '0'
+ #option place 'admin status Bmx6'
+ option place 'qmp Mesh'
+ option position '3'
+ #option json 'http://127.0.0.1/cgi-bin/bmx6-info?'
+ option json 'exec:/www/cgi-bin/bmx6-info -s'
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/controller/bmx6.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/controller/bmx6.lua
new file mode 100644
index 0000000..cb5642e
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/controller/bmx6.lua
@@ -0,0 +1,329 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+ Contributors Jo-Philipp Wich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+local bmx6json = require("luci.model.bmx6json")
+
+module("luci.controller.bmx6", package.seeall)
+
+function index()
+ local place = {}
+ local ucim = require "luci.model.uci"
+ local uci = ucim.cursor()
+
+ -- checking if ignore is on
+ if uci:get("luci-bmx6","luci","ignore") == "1" then
+ return nil
+ end
+
+ -- getting value from uci database
+ local uci_place = uci:get("luci-bmx6","luci","place")
+
+ -- default values
+ if uci_place == nil then
+ place = {"bmx6"}
+ else
+ local util = require "luci.util"
+ place = util.split(uci_place," ")
+ end
+
+ -- getting position of menu
+ local uci_position = uci:get("luci-bmx6","luci","position")
+
+ ---------------------------
+ -- Starting with the pages
+ ---------------------------
+
+ --- status (default)
+ entry(place,call("action_nodes_j"),place[#place],tonumber(uci_position))
+
+ table.insert(place,"Status")
+ entry(place,call("action_status_j"),"Status",0)
+ table.remove(place)
+
+ -- not visible
+ table.insert(place,"nodes_nojs")
+ entry(place, call("action_nodes"), nil)
+ table.remove(place)
+
+ --- nodes
+ table.insert(place,"Nodes")
+ entry(place,call("action_nodes_j"),"Nodes",1)
+ table.remove(place)
+
+ --- links
+ table.insert(place,"Links")
+ entry(place,call("action_links"),"Links",2).leaf = true
+ table.remove(place)
+
+ -- Tunnels
+ table.insert(place,"Tunnels")
+ entry(place,call("action_tunnels_j"), "Tunnels", 3).leaf = true
+ table.remove(place)
+
+ -- Gateways (deprecated)
+ --table.insert(place,"Gateways")
+ --entry(place,call("action_gateways_j"),"Gateways").leaf = true
+ --table.remove(place)
+
+ --- Chat
+ table.insert(place,"Chat")
+ entry(place,call("action_chat"),"Chat",5)
+ table.remove(place)
+
+ --- Graph
+ table.insert(place,"Graph")
+ entry(place, template("bmx6/graph"), "Graph",4)
+ table.remove(place)
+
+ --- Topology (hidden)
+ table.insert(place,"topology")
+ entry(place, call("action_topology"), nil)
+ table.remove(place)
+
+ --- configuration (CBI)
+ table.insert(place,"Configuration")
+ entry(place, cbi("bmx6/main"), "Configuration",6).dependent=false
+
+ table.insert(place,"General")
+ entry(place, cbi("bmx6/main"), "General",1)
+ table.remove(place)
+
+ table.insert(place,"Advanced")
+ entry(place, cbi("bmx6/advanced"), "Advanced",5)
+ table.remove(place)
+
+ table.insert(place,"Interfaces")
+ entry(place, cbi("bmx6/interfaces"), "Interfaces",2)
+ table.remove(place)
+
+ table.insert(place,"Tunnels")
+ entry(place, cbi("bmx6/tunnels"), "Tunnels",3)
+ table.remove(place)
+
+ table.insert(place,"Plugins")
+ entry(place, cbi("bmx6/plugins"), "Plugins",6)
+ table.remove(place)
+
+ table.insert(place,"HNAv6")
+ entry(place, cbi("bmx6/hna"), "HNAv6",4)
+ table.remove(place)
+
+ table.remove(place)
+
+end
+
+function action_status()
+ local status = bmx6json.get("status").status or nil
+ local interfaces = bmx6json.get("interfaces").interfaces or nil
+
+ if status == nil or interfaces == nil then
+ luci.template.render("bmx6/error", {txt="Cannot fetch data from bmx6 json"})
+ else
+ luci.template.render("bmx6/status", {status=status,interfaces=interfaces})
+ end
+end
+
+function action_status_j()
+ luci.template.render("bmx6/status_j", {})
+end
+
+
+function action_nodes()
+ local orig_list = bmx6json.get("originators").originators or nil
+
+ if orig_list == nil then
+ luci.template.render("bmx6/error", {txt="Cannot fetch data from bmx6 json"})
+ return nil
+ end
+
+ local originators = {}
+ local desc = nil
+ local orig = nil
+ local name = ""
+ local ipv4 = ""
+
+ for _,o in ipairs(orig_list) do
+ orig = bmx6json.get("originators/"..o.name) or {}
+ desc = bmx6json.get("descriptions/"..o.name) or {}
+
+ if string.find(o.name,'.') then
+ name = luci.util.split(o.name,'.')[1]
+ else
+ name = o.name
+ end
+
+ table.insert(originators,{name=name,orig=orig,desc=desc})
+ end
+
+ luci.template.render("bmx6/nodes", {originators=originators})
+end
+
+function action_nodes_j()
+ local http = require "luci.http"
+ local link_non_js = "/cgi-bin/luci" .. http.getenv("PATH_INFO") .. '/nodes_nojs'
+
+ luci.template.render("bmx6/nodes_j", {link_non_js=link_non_js})
+end
+
+function action_gateways_j()
+ luci.template.render("bmx6/gateways_j", {})
+end
+
+function action_tunnels_j()
+ luci.template.render("bmx6/tunnels_j", {})
+end
+
+
+function action_links(host)
+ local links = bmx6json.get("links", host)
+ local devlinks = {}
+ local _,l
+
+ if links ~= nil then
+ links = links.links
+ for _,l in ipairs(links) do
+ devlinks[l.viaDev] = {}
+ end
+ for _,l in ipairs(links) do
+ l.globalId = luci.util.split(l.globalId,'.')[1]
+ table.insert(devlinks[l.viaDev],l)
+ end
+ end
+
+ luci.template.render("bmx6/links", {links=devlinks})
+end
+
+function action_topology()
+ local originators = bmx6json.get("originators/all")
+ local o,i,l,i2
+ local first = true
+ local topology = '[ '
+ local cache = '/tmp/bmx6-topology.json'
+ local offset = 60
+
+ local cachefd = io.open(cache,r)
+ local update = false
+
+ if cachefd ~= nil then
+ local lastupdate = tonumber(cachefd:read("*line")) or 0
+ if os.time() >= lastupdate + offset then
+ update = true
+ else
+ topology = cachefd:read("*all")
+ end
+ cachefd:close()
+ end
+
+ if cachefd == nil or update then
+ for i,o in ipairs(originators) do
+ local links = bmx6json.get("links",o.primaryIp)
+ if links then
+ if first then
+ first = false
+ else
+ topology = topology .. ', '
+ end
+
+ topology = topology .. '{ "globalId": "%s", "links": [' %o.globalId:match("^[^%.]+")
+
+ local first2 = true
+
+ for i2,l in ipairs(links.links) do
+ if first2 then
+ first2 = false
+ else
+ topology = topology .. ', '
+ end
+
+ topology = topology .. '{ "globalId": "%s", "rxRate": %s, "txRate": %s }'
+ %{ l.globalId:match("^[^%.]+"), l.rxRate, l.txRate }
+
+ end
+
+ topology = topology .. ']}'
+ end
+
+ end
+
+ topology = topology .. ' ]'
+
+ -- Upgrading the content of the cache file
+ cachefd = io.open(cache,'w+')
+ cachefd:write(os.time()..'\n')
+ cachefd:write(topology)
+ cachefd:close()
+ end
+
+ luci.http.prepare_content("application/json")
+ luci.http.write(topology)
+end
+
+
+function action_chat()
+ local sms_dir = "/var/run/bmx6/sms"
+ local rcvd_dir = sms_dir .. "/rcvdSms"
+ local send_file = sms_dir .. "/sendSms/chat"
+ local sms_list = bmx6json.get("rcvdSms")
+ local sender = ""
+ local sms_file = ""
+ local chat = {}
+ local to_send = nil
+ local sent = ""
+ local fd = nil
+
+ if luci.sys.call("test -d " .. sms_dir) ~= 0 then
+ luci.template.render("bmx6/error", {txt="sms plugin disabled or some problem with directory " .. sms_dir})
+ return nil
+ end
+
+ sms_list = luci.util.split(luci.util.exec("ls "..rcvd_dir.."/*:chat"))
+
+ for _,sms_path in ipairs(sms_list) do
+ if #sms_path > #rcvd_dir then
+ sms_file = luci.util.split(sms_path,'/')
+ sms_file = sms_file[#sms_file]
+ sender = luci.util.split(sms_file,':')[1]
+
+ -- Trying to clean the name
+ if string.find(sender,".") ~= nil then
+ sender = luci.util.split(sender,".")[1]
+ end
+
+ fd = io.open(sms_path,"r")
+ chat[sender] = fd:read()
+ fd:close()
+ end
+ end
+
+ to_send = luci.http.formvalue("toSend")
+ if to_send ~= nil and #to_send > 1 then
+ fd = io.open(send_file,"w")
+ fd:write(to_send)
+ fd:close()
+ sent = to_send
+ else
+ sent = luci.util.exec("cat "..send_file)
+ end
+
+ luci.template.render("bmx6/chat", {chat=chat,sent=sent})
+end
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/bmx6json.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/bmx6json.lua
new file mode 100644
index 0000000..dfe9ab1
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/bmx6json.lua
@@ -0,0 +1,219 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+ Contributors Jo-Philipp Wich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+local ltn12 = require("luci.ltn12")
+local json = require("luci.json")
+local util = require("luci.util")
+local uci = require("luci.model.uci")
+local sys = require("luci.sys")
+local template = require("luci.template")
+local http = require("luci.http")
+local string = require("string")
+local table = require("table")
+local nixio = require("nixio")
+local nixiofs = require("nixio.fs")
+local ipairs = ipairs
+
+module "luci.model.bmx6json"
+
+-- Returns a LUA object from bmx6 JSON daemon
+
+function get(field, host)
+ local url
+ if host ~= nil then
+ if host:match(":") then
+ url = 'http://[%s]/cgi-bin/bmx6-info?' % host
+ else
+ url = 'http://%s/cgi-bin/bmx6-info?' % host
+ end
+ else
+ url = uci.cursor():get("luci-bmx6","luci","json")
+ end
+
+ if url == nil then
+ print_error("bmx6 json url not configured, cannot fetch bmx6 daemon data",true)
+ return nil
+ end
+
+ local json_url = util.split(url,":")
+ local raw = ""
+
+ if json_url[1] == "http" then
+ raw,err = wget(url..field,1000)
+ else
+
+ if json_url[1] == "exec" then
+ raw = sys.exec(json_url[2]..' '..field)
+ else
+ print_error("bmx6 json url not recognized, cannot fetch bmx6 daemon data. Use http: or exec:",true)
+ return nil
+ end
+
+ end
+
+ local data = nil
+
+ if raw and raw:len() > 10 then
+ local decoder = json.Decoder()
+ ltn12.pump.all(ltn12.source.string(raw), decoder:sink())
+ data = decoder:get()
+-- else
+-- print_error("Cannot get data from bmx6 daemon",true)
+-- return nil
+ end
+
+ return data
+end
+
+function print_error(txt,popup)
+ util.perror(txt)
+ sys.call("logger -t bmx6json " .. txt)
+
+ if popup then
+ http.write('')
+ else
+ http.write("
')
+ end
+
+end
+
+function text2html(txt)
+ txt = string.gsub(txt,"<","{")
+ txt = string.gsub(txt,">","}")
+ txt = util.striptags(txt)
+ return txt
+end
+
+
+function wget(url, timeout)
+ local rfd, wfd = nixio.pipe()
+ local pid = nixio.fork()
+ if pid == 0 then
+ rfd:close()
+ nixio.dup(wfd, nixio.stdout)
+
+ local candidates = { "/usr/bin/wget", "/bin/wget" }
+ local _, bin
+ for _, bin in ipairs(candidates) do
+ if nixiofs.access(bin, "x") then
+ nixio.exec(bin, "-q", "-O", "-", url)
+ end
+ end
+ return
+ else
+ wfd:close()
+ rfd:setblocking(false)
+
+ local buffer = { }
+ local err1, err2
+
+ while true do
+ local ready = nixio.poll({{ fd = rfd, events = nixio.poll_flags("in") }}, timeout)
+ if not ready then
+ nixio.kill(pid, nixio.const.SIGKILL)
+ err1 = "timeout"
+ break
+ end
+
+ local rv = rfd:read(4096)
+ if rv then
+ -- eof
+ if #rv == 0 then
+ break
+ end
+
+ buffer[#buffer+1] = rv
+ else
+ -- error
+ if nixio.errno() ~= nixio.const.EAGAIN and
+ nixio.errno() ~= nixio.const.EWOULDBLOCK then
+ err1 = "error"
+ err2 = nixio.errno()
+ end
+ end
+ end
+
+ nixio.waitpid(pid, "nohang")
+ if not err1 then
+ return table.concat(buffer)
+ else
+ return nil, err1, err2
+ end
+ end
+end
+
+function getOptions(name)
+ -- Getting json and Checking if bmx6-json is avaiable
+ local options = get("options")
+ if options == nil or options.OPTIONS == nil then
+ m.message = "bmx6-json plugin is not running or some mistake in luci-bmx6 configuration, check /etc/config/luci-bmx6"
+ return nil
+ else
+ options = options.OPTIONS
+ end
+
+ -- Filtering by the option name
+ local i,_
+ local namedopt = nil
+ if name ~= nil then
+ for _,i in ipairs(options) do
+ if i.name == name and i.CHILD_OPTIONS ~= nil then
+ namedopt = i.CHILD_OPTIONS
+ break
+ end
+ end
+ end
+
+ return namedopt
+end
+
+-- Rturns a help string formated to be used in HTML scope
+function getHtmlHelp(opt)
+ if opt == nil then return nil end
+
+ local help = ""
+ if opt.help ~= nil then
+ help = text2html(opt.help)
+ end
+ if opt.syntax ~= nil then
+ help = help .. " Syntax: " .. text2html(opt.syntax)
+ end
+
+ return help
+end
+
+function testandreload()
+ local test = sys.call('bmx6 -c --test > /tmp/bmx6-luci.err.tmp')
+ if test ~= 0 then
+ return sys.exec("cat /tmp/bmx6-luci.err.tmp")
+ end
+
+ local err = sys.call('bmx6 -c --configReload > /tmp/bmx6-luci.err.tmp')
+ if err ~= 0 then
+ return sys.exec("cat /tmp/bmx6-luci.err.tmp")
+ end
+
+ return nil
+end
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/advanced.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/advanced.lua
new file mode 100644
index 0000000..9510214
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/advanced.lua
@@ -0,0 +1,74 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+m = Map("bmx6", "bmx6")
+
+local bmx6json = require("luci.model.bmx6json")
+local util = require("luci.util")
+local http = require("luci.http")
+local sys = require("luci.sys")
+
+local options = bmx6json.get("options")
+if options == nil or options.OPTIONS == nil then
+ m.message = "bmx6-json plugin is not running or some mistake in luci-bmx6 configuration, check /etc/config/luci-bmx6"
+ options = {}
+else
+ options = options.OPTIONS
+end
+
+local general = m:section(NamedSection,"general","general","General Options")
+
+local name = ""
+local help = ""
+local value = nil
+local _,o
+
+for _,o in ipairs(options) do
+ if o.name ~= nil and o.CHILD_OPTIONS == nil and o.configurable == 1 then
+ help = ""
+ name = o.name
+
+ if o.help ~= nil then
+ help = bmx6json.text2html(o.help)
+ end
+
+ if o.syntax ~= nil then
+ help = help .. " Syntax: " .. bmx6json.text2html(o.syntax)
+ end
+
+ if o.def ~= nil then
+ help = help .. " Default: " .. o.def
+ end
+
+ value = general:option(Value,name,name,help)
+
+ end
+end
+
+function m.on_commit(self,map)
+ local err = sys.call('bmx6 -c --configReload > /tmp/bmx6-luci.err.tmp')
+ if err ~= 0 then
+ m.message = sys.exec("cat /tmp/bmx6-luci.err.tmp")
+ end
+end
+
+return m
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/hna.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/hna.lua
new file mode 100644
index 0000000..db98ae6
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/hna.lua
@@ -0,0 +1,47 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+local sys = require("luci.sys")
+
+m = Map("bmx6", "bmx6")
+
+local hna = m:section(TypedSection,"unicastHna","IPv6 HNA")
+hna.addremove = true
+hna.anonymous = true
+local hna_option = hna:option(Value,"unicastHna", "IPv6 Host Network Announcement. Syntax /")
+
+--function hna_option:validate(value)
+-- local err = sys.call('bmx6 -c --test -a ' .. value)
+-- if err ~= 0 then
+-- return nil
+-- end
+-- return value
+--end
+
+function m.on_commit(self,map)
+ local err = sys.call('bmx6 -c --configReload > /tmp/bmx6-luci.err.tmp')
+ if err ~= 0 then
+ m.message = sys.exec("cat /tmp/bmx6-luci.err.tmp")
+ end
+end
+
+return m
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/interfaces.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/interfaces.lua
new file mode 100644
index 0000000..fb1261b
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/interfaces.lua
@@ -0,0 +1,77 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+local sys = require("luci.sys")
+local bmx6json = require("luci.model.bmx6json")
+local m = Map("bmx6", "bmx6")
+
+local eth_int = sys.net.devices()
+local interfaces = m:section(TypedSection,"dev","Devices","")
+interfaces.addremove = true
+interfaces.anonymous = true
+
+local intlv = interfaces:option(ListValue,"dev","Device")
+
+for _,i in ipairs(eth_int) do
+ intlv:value(i,i)
+end
+
+-- Getting json and looking for device section
+local json = bmx6json.get("options")
+
+if json == nil or json.OPTIONS == nil then
+ m.message = "bmx6-json plugin is not running or some mistake in luci-bmx6 configuration, check /etc/config/luci-bmx6"
+ json = {}
+else
+ json = json.OPTIONS
+end
+
+local dev = {}
+for _,j in ipairs(json) do
+ if j.name == "dev" and j.CHILD_OPTIONS ~= nil then
+ dev = j.CHILD_OPTIONS
+ break
+ end
+end
+
+local help = ""
+local name = ""
+
+for _,o in ipairs(dev) do
+ if o.name ~= nil then
+ help = ""
+ name = o.name
+ if o.help ~= nil then
+ help = bmx6json.text2html(o.help)
+ end
+
+ if o.syntax ~= nil then
+ help = help .. " Syntax: " .. bmx6json.text2html(o.syntax)
+ end
+
+ value = interfaces:option(Value,name,name,help)
+ value.optional = true
+ end
+end
+
+
+return m
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/main.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/main.lua
new file mode 100644
index 0000000..8c114bf
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/main.lua
@@ -0,0 +1,108 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+local sys = require("luci.sys")
+local bmx6json = require("luci.model.bmx6json")
+
+m = Map("bmx6", "bmx6")
+
+-- Getting json and Checking if bmx6-json is avaiable
+local options = bmx6json.get("options")
+if options == nil or options.OPTIONS == nil then
+ m.message = "bmx6-json plugin is not running or some mistake in luci-bmx6 configuration, check /etc/config/luci-bmx6"
+else
+ options = options.OPTIONS
+end
+
+-- Getting a list of interfaces
+local eth_int = luci.sys.net.devices()
+
+-- Getting the most important options from general
+local general = m:section(NamedSection,"general","general","General")
+general.addremove = false
+general:option(Value,"globalPrefix","Global ip prefix","Specify global prefix for interfaces: NETADDR/LENGTH. If you are using IPv6 leave blank to let bmx6 autoassign an ULA IPv6 address.")
+
+if m:get("ipVersion","ipVersion") == "6" then
+ general:option(Value,"tun4Address","IPv4 address or range","specify default IPv4 tunnel address and announced range")
+end
+
+-- IP section
+-- ipVersion section is important, we are allways showing it
+local ipV = m:section(NamedSection,"ipVersion","ipVersion","IP options")
+ipV.addremove = false
+local lipv = ipV:option(ListValue,"ipVersion","IP version")
+lipv:value("4","4")
+lipv:value("6","6")
+lipv.default = "6"
+
+-- rest of ip options are optional, getting them from json
+local ipoptions = {}
+for _,o in ipairs(options) do
+ if o.name == "ipVersion" and o.CHILD_OPTIONS ~= nil then
+ ipoptions = o.CHILD_OPTIONS
+ break
+ end
+end
+
+local help = ""
+local name = ""
+local value = nil
+
+for _,o in ipairs(ipoptions) do
+ if o.name ~= nil then
+ help = ""
+ name = o.name
+ if o.help ~= nil then
+ help = bmx6json.text2html(o.help)
+ end
+
+ if o.syntax ~= nil then
+ help = help .. " Syntax: " .. bmx6json.text2html(o.syntax)
+ end
+
+ if o.def ~= nil then
+ help = help .. " Default: " .. bmx6json.text2html(o.def)
+ end
+
+ value = ipV:option(Value,name,name,help)
+ value.optional = true
+ end
+end
+
+-- Interfaces section
+local interfaces = m:section(TypedSection,"dev","Devices","")
+interfaces.addremove = true
+interfaces.anonymous = true
+local intlv = interfaces:option(ListValue,"dev","Device")
+
+for _,i in ipairs(eth_int) do
+ intlv:value(i,i)
+end
+
+function m.on_commit(self,map)
+ local err = sys.call('bmx6 -c --configReload > /tmp/bmx6-luci.err.tmp')
+ if err ~= 0 then
+ m.message = sys.exec("cat /tmp/bmx6-luci.err.tmp")
+ end
+end
+
+return m
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/plugins.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/plugins.lua
new file mode 100644
index 0000000..518864e
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/plugins.lua
@@ -0,0 +1,50 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+local sys = require("luci.sys")
+
+m = Map("bmx6", "bmx6")
+plugins_dir = {"/usr/lib/","/var/lib","/lib"}
+
+plugin = m:section(TypedSection,"plugin","Plugin")
+plugin.addremove = true
+plugin.anonymous = true
+plv = plugin:option(ListValue,"plugin", "Plugin")
+
+for _,d in ipairs(plugins_dir) do
+ pl = luci.sys.exec("cd "..d..";ls bmx6_*")
+ if #pl > 6 then
+ for _,v in ipairs(luci.util.split(pl,"\n")) do
+ plv:value(v,v)
+ end
+ end
+end
+
+
+function m.on_commit(self,map)
+ local err = sys.call('/etc/init.d/bmx6 restart')
+ if err ~= 0 then
+ m.message = sys.exec("Cannot restart bmx6")
+ end
+end
+
+
+return m
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/tunnels.lua b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/tunnels.lua
new file mode 100644
index 0000000..7a6bfd3
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/model/cbi/bmx6/tunnels.lua
@@ -0,0 +1,75 @@
+--[[
+ Copyright (C) 2011 Pau Escrich
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+--]]
+
+local sys = require("luci.sys")
+local bmx6json = require("luci.model.bmx6json")
+
+m = Map("bmx6", "bmx6")
+
+-- tunOut
+local tunnelsOut = m:section(TypedSection,"tunOut",translate("Networks to fetch"),translate("Tunnel announcements to fetch if possible"))
+tunnelsOut.addremove = true
+tunnelsOut.anonymous = true
+tunnelsOut:option(Value,"tunOut","Name")
+tunnelsOut:option(Value,"network", translate("Network to fetch"))
+
+local tunoptions = bmx6json.getOptions("tunOut")
+local _,o
+for _,o in ipairs(tunoptions) do
+ if o.name ~= nil and o.name ~= "network" then
+ help = bmx6json.getHtmlHelp(o)
+ value = tunnelsOut:option(Value,o.name,o.name,help)
+ value.optional = true
+ end
+end
+
+
+--tunIn
+local tunnelsIn = m:section(TypedSection,"tunInNet",translate("Networks to offer"),translate("Tunnels to announce in the network"))
+tunnelsIn.addremove = true
+tunnelsIn.anonymous = true
+
+local net = tunnelsIn:option(Value,"tunInNet", translate("Network to offer"))
+net.default = "10.0.0.0/8"
+
+local bwd = tunnelsIn:option(Value,"bandwidth",translate("Bandwidth (Bytes)"))
+bwd.default = "1000000"
+
+local tuninoptions = bmx6json.getOptions("tunInNet")
+local _,o
+for _,o in ipairs(tuninoptions) do
+ if o.name ~= nil and o.name ~= "tunInNet" and o.name ~= "bandwidth" then
+ help = bmx6json.getHtmlHelp(o)
+ value = tunnelsIn:option(Value,o.name,o.name,help)
+ value.optional = true
+ end
+end
+
+function m.on_commit(self,map)
+ --Not working. If test returns error the changes are still commited
+ local msg = bmx6json.testandreload()
+ if msg ~= nil then
+ m.message = msg
+ end
+end
+
+return m
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/view/admin_status/index/neighbours_simple.htm b/packages/bmx6-luci/files/usr/lib/lua/luci/view/admin_status/index/neighbours_simple.htm
new file mode 100644
index 0000000..97d6e0e
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/view/admin_status/index/neighbours_simple.htm
@@ -0,0 +1,108 @@
+
+
+
This is sms a chat where all bmx6 nodes can participate. The data is replayed using routing packets, so there is a limit of 2040 bytes. Use it only to send short messages.
+
Each participant can only send one sms at same time.
+
+
+Received SMS
+
+
+<% for orig,sms in pairs(chat) do %>
+ <%=orig%>:<%=sms%>
+<% end %>
+
+
+<%+footer%>
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/graph.htm b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/graph.htm
new file mode 100644
index 0000000..a4dabb7
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/graph.htm
@@ -0,0 +1,110 @@
+<%#
+Copyright (C) 2011 Pau Escrich
+Contributors Jo-Philip
+
+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.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+The full GNU General Public License is included in this distribution in
+the file called "COPYING".
+-%>
+
+<%
+ luci.http.prepare_content("text/html")
+
+ local location = { unpack(luci.dispatcher.context.path) }
+ location[#location] = "topology"
+%>
+
+<%+header%>
+
+
+
+
+
+
+
+
+
+ <% if o.desc.DESC_ADV ~= nil then %>
+ <% for j,h in ipairs(o.desc.DESC_ADV.extensions[2].HNA6_EXTENSION) do %>
+ <%=h.address%>
+ <% end %>
+ <% end %>
+
+ <% if o.desc.DESC_ADV ~= nil then %>
+ <% for j,h in ipairs(o.desc.DESC_ADV.extensions[2].HNA6_EXTENSION) do %>
+ <%=h.address%>
+ <% end %>
+ <% end %>
+
+
+<% end %>
+
+
+
+<%+footer%>
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/nodes_j.htm b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/nodes_j.htm
new file mode 100644
index 0000000..0435655
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/nodes_j.htm
@@ -0,0 +1,193 @@
+<%#
+ Copyright (C) 2011 Pau Escrich
+ Contributors Lluis Esquerda
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+-%>
+
+<%+header%>
+
+
+
+
+
+
+
+
Node originators
+
+
+
+
+ Click icon to see individual node information
+
+
+
+
+
+
+Go to non JavaScript view
+
+
+
+<%+footer%>
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/status.htm b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/status.htm
new file mode 100644
index 0000000..11e9682
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/status.htm
@@ -0,0 +1,69 @@
+<%+header%>
+
+
+
+
+Bmx6 is a routing protocol for Linux based operating systems. Visit bmx6.net for more info.
+
+
+
+
+
+
+
+
+a mesh routing protocol for Linux devices.
+Visit bmx6.net for more info.
+
+
+
+
+
status
+
+
+
+
+
+
+
+
+
+
+<%+footer%>
+
diff --git a/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/tunnels_j.htm b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/tunnels_j.htm
new file mode 100644
index 0000000..1b7ce42
--- /dev/null
+++ b/packages/bmx6-luci/files/usr/lib/lua/luci/view/bmx6/tunnels_j.htm
@@ -0,0 +1,107 @@
+<%#
+ Copyright (C) 2011 Pau Escrich
+ Contributors Lluis Esquerda
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+-%>
+
+
+<%+header%>
+
+
+
+
+
+
"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/
+//
+// Math.seedrandom('yipee'); Sets Math.random to a function that is
+// initialized using the given explicit seed.
+//
+// Math.seedrandom(); Sets Math.random to a function that is
+// seeded using the current time, dom state,
+// and other accumulated local entropy.
+// The generated seed string is returned.
+//
+// Math.seedrandom('yowza', true);
+// Seeds using the given explicit seed mixed
+// together with accumulated entropy.
+//
+//
+// Seeds using physical random bits downloaded
+// from random.org.
+//
+// Examples:
+//
+// Math.seedrandom("hello"); // Use "hello" as the seed.
+// document.write(Math.random()); // Always 0.5463663768140734
+// document.write(Math.random()); // Always 0.43973793770592234
+// var rng1 = Math.random; // Remember the current prng.
+//
+// var autoseed = Math.seedrandom(); // New prng with an automatic seed.
+// document.write(Math.random()); // Pretty much unpredictable.
+//
+// Math.random = rng1; // Continue "hello" prng sequence.
+// document.write(Math.random()); // Always 0.554769432473455
+//
+// Math.seedrandom(autoseed); // Restart at the previous seed.
+// document.write(Math.random()); // Repeat the 'unpredictable' value.
+//
+// Notes:
+//
+// Each time seedrandom('arg') is called, entropy from the passed seed
+// is accumulated in a pool to help generate future seeds for the
+// zero-argument form of Math.seedrandom, so entropy can be injected over
+// time by calling seedrandom with explicit data repeatedly.
+//
+// On speed - This javascript implementation of Math.random() is about
+// 3-10x slower than the built-in Math.random() because it is not native
+// code, but this is typically fast enough anyway. Seeding is more expensive,
+// especially if you use auto-seeding. Some details (timings on Chrome 4):
+//
+// Our Math.random() - avg less than 0.002 milliseconds per call
+// seedrandom('explicit') - avg less than 0.5 milliseconds per call
+// seedrandom('explicit', true) - avg less than 2 milliseconds per call
+// seedrandom() - avg about 38 milliseconds per call
+//
+// LICENSE (BSD):
+//
+// Copyright 2010 David Bau, all rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of this module nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+/**
+ * All code is in an anonymous closure to keep the global namespace clean.
+ *
+ * @param {number=} overflow
+ * @param {number=} startdenom
+ */
+(function (pool, math, width, chunks, significance, overflow, startdenom) {
+
+
+//
+// seedrandom()
+// This is the seedrandom function described above.
+//
+math['seedrandom'] = function seedrandom(seed, use_entropy) {
+ var key = [];
+ var arc4;
+
+ // Flatten the seed string or build one from local entropy if needed.
+ seed = mixkey(flatten(
+ use_entropy ? [seed, pool] :
+ arguments.length ? seed :
+ [new Date().getTime(), pool, window], 3), key);
+
+ // Use the seed to initialize an ARC4 generator.
+ arc4 = new ARC4(key);
+
+ // Mix the randomness into accumulated entropy.
+ mixkey(arc4.S, pool);
+
+ // Override Math.random
+
+ // This function returns a random double in [0, 1) that contains
+ // randomness in every bit of the mantissa of the IEEE 754 value.
+
+ math['random'] = function random() { // Closure to return a random double:
+ var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48
+ var d = startdenom; // and denominator d = 2 ^ 48.
+ var x = 0; // and no 'extra last byte'.
+ while (n < significance) { // Fill up all significant digits by
+ n = (n + x) * width; // shifting numerator and
+ d *= width; // denominator and generating a
+ x = arc4.g(1); // new least-significant-byte.
+ }
+ while (n >= overflow) { // To avoid rounding up, before adding
+ n /= 2; // last byte, shift everything
+ d /= 2; // right using integer math until
+ x >>>= 1; // we have exactly the desired bits.
+ }
+ return (n + x) / d; // Form the number within [0, 1).
+ };
+
+ // Return the seed that was used
+ return seed;
+};
+
+//
+// ARC4
+//
+// An ARC4 implementation. The constructor takes a key in the form of
+// an array of at most (width) integers that should be 0 <= x < (width).
+//
+// The g(count) method returns a pseudorandom integer that concatenates
+// the next (count) outputs from ARC4. Its return value is a number x
+// that is in the range 0 <= x < (width ^ count).
+//
+/** @constructor */
+function ARC4(key) {
+ var t, u, me = this, keylen = key.length;
+ var i = 0, j = me.i = me.j = me.m = 0;
+ me.S = [];
+ me.c = [];
+
+ // The empty key [] is treated as [0].
+ if (!keylen) { key = [keylen++]; }
+
+ // Set up S using the standard key scheduling algorithm.
+ while (i < width) { me.S[i] = i++; }
+ for (i = 0; i < width; i++) {
+ t = me.S[i];
+ j = lowbits(j + t + key[i % keylen]);
+ u = me.S[j];
+ me.S[i] = u;
+ me.S[j] = t;
+ }
+
+ // The "g" method returns the next (count) outputs as one number.
+ me.g = function getnext(count) {
+ var s = me.S;
+ var i = lowbits(me.i + 1); var t = s[i];
+ var j = lowbits(me.j + t); var u = s[j];
+ s[i] = u;
+ s[j] = t;
+ var r = s[lowbits(t + u)];
+ while (--count) {
+ i = lowbits(i + 1); t = s[i];
+ j = lowbits(j + t); u = s[j];
+ s[i] = u;
+ s[j] = t;
+ r = r * width + s[lowbits(t + u)];
+ }
+ me.i = i;
+ me.j = j;
+ return r;
+ };
+ // For robust unpredictability discard an initial batch of values.
+ // See http://www.rsa.com/rsalabs/node.asp?id=2009
+ me.g(width);
+}
+
+//
+// flatten()
+// Converts an object tree to nested arrays of strings.
+//
+/** @param {Object=} result
+ * @param {string=} prop */
+function flatten(obj, depth, result, prop) {
+ result = [];
+ if (depth && typeof(obj) == 'object') {
+ for (prop in obj) {
+ if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage)
+ try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
+ }
+ }
+ }
+ return result.length ? result : '' + obj;
+}
+
+//
+// mixkey()
+// Mixes a string seed into a key that is an array of integers, and
+// returns a shortened string seed that is equivalent to the result key.
+//
+/** @param {number=} smear
+ * @param {number=} j */
+function mixkey(seed, key, smear, j) {
+ seed += ''; // Ensure the seed is a string
+ smear = 0;
+ for (j = 0; j < seed.length; j++) {
+ key[lowbits(j)] =
+ lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j));
+ }
+ seed = '';
+ for (j in key) { seed += String.fromCharCode(key[j]); }
+ return seed;
+}
+
+//
+// lowbits()
+// A quick "n mod width" for width a power of 2.
+//
+function lowbits(n) { return n & (width - 1); }
+
+//
+// The following constants are related to IEEE 754 limits.
+//
+startdenom = math.pow(width, chunks);
+significance = math.pow(2, significance);
+overflow = significance * 2;
+
+//
+// When seedrandom.js is loaded, we immediately mix a few bits
+// from the built-in RNG into the entropy pool. Because we do
+// not want to intefere with determinstic PRNG state later,
+// seedrandom will not call math.random on its own again after
+// initialization.
+//
+mixkey(math.random(), pool);
+
+// End anonymous scope, and pass initial values.
+})(
+ [], // pool: entropy pool starts empty
+ Math, // math: package containing random, pow, and seedrandom
+ 256, // width: each RC4 output is 0 <= x < 256
+ 6, // chunks: at least six RC4 outputs for each double
+ 52 // significance: there are 52 significant digits in a double
+);
diff --git a/packages/bmx6-luci/files/www/luci-static/resources/bmx6/link.png b/packages/bmx6-luci/files/www/luci-static/resources/bmx6/link.png
new file mode 100644
index 0000000000000000000000000000000000000000..58977ffbb2f76f4fa7eab89c4d833c024c4a9da3
GIT binary patch
literal 2910
zcmV-k3!(IhP)}27>jaztz!)zUr~`NcrXw@&WPTbhNQ*@#2T$7tf^AY5V&3bXsT_
zK(vDCKt!KoSLf|Ou+CVZjY$At&3b-4=y^R!&8jp~UIbkhCQweN$xVBtwf`(GUa6nH
zc=6b=bosUb8~<|O=7w)hoZR!}!gccDzd3eqBHC2jTB5aJJP>e+suRyvh~HFQMkxTu
z9_K<*n}TVMESima(XwV2%AtH&Z65pA;S<-LT(fI;t1cM>KmW$({`(IA*6iB7RPke-
zzuNn$pZ(rx!5;eRPacg$sMH=eX1NGOR4VIEKtzRQ#)Yf|72(MM;1K2#*Qt|$QB*8a
zZgRIlNv$$dG}}rQ?jQMwEpL!(sagN$`$rt9ls&oU%NGEEUI$=2xL)m^ICb6fEzcc&
zSP|~Bu5i$V9OzVJEb?HjV@`Fw@Z`0c@7yDNbx`=~pyoUG2v1(ioa%ZH);dMTBFKTx
zu5i#)gu86Zb4MRer-cRpYWKt`#)Ipx>q-Ey;_>}$y2@9+^Dj^TBArfax%N;`ai;vG
zuCC;1B_1;1iGItfueKWAJ&dxrq)IVCr8u}31^ft?SeQsKd`Gm@>dsw0cfw4TDGa?S
zQ@OM-U;Vh;XP*7U+K&3S(rL4I^dUqxPpuw9{l4h?100sb>rmXZyY;4!~cx&;ObIF<@_Xmw|-VCnAH7np6%pATfsmidCo#vS=Ja2n38swbrcO
zU#!jjYS;LS|js93zZEC99MHDYtsW(%G
zp@IPcLJ&019WkDN_HXg(E3aYqzwO3~#qBW99We+&kO2Y1P*JHjQ$+ESn(B7N!fKN@
z8vQ&HiH0ZSWT?ZK_k`VZqX?;Bk;Fh!lQcIJ;I$~{axB!M7@m+4l24+p=c%fyC>&hn
z+*PgoC8Uxm001QvkM7tGD}M=`yDA4)RaH@3&r>CzL_HxTLM@8Hxf~1dT2#{9P+}md
zQNbcNQXnKh5GysprWOnZJtycAp?e+@vd}}IPSE9o`a;NzQdw|8g%Btd=b}CTE
zs}3OqASfl2${y!%xuAmZpz!pNN1TL9gibs)Xf~8k%&vzoOMc*g9Uu~OtXiv19Nl3&
zz!Zu2j!1xbK>?yrN{C~7G9{o?A_%sxz{}s3m?UDjTySaDFpK*B3Ej)PKBT;
z6JK|UuiJHJ85PvL0pJk({bI3pZ%=#g+cs^;s-{gZRLp@?Yp5W=XetqPCN5<4XvClf
zY8dSAK_IdgUZfuYaNkG!VO8caekl(VA-YhmlYyn3j(|id_oRi2*{W*VL{mtz=IBzf
zn7P*>_WL(dpqR>`s^zT$FDuL?bjjUqCvDT#?53{~0>We_+S?-h!sQtvo0qV0-5}1N
zJ`S$Nz||Pe{pJKVuKfsD?IJE*o+0gR5zb^L2m!I1zGj=Yw&d=%lguR)ysT6$ZUIDCJnn~$U@nu%C49jJAdpPN{N6ZlW}yYI9X^H3WDZT&hb>f0
z7aMr>@OwC0ila9UBoi?o5by;TnM^JbHi9{L+y{W!s@oxiuN~j_`SB0j1)k4e&t$UO
zC0THv3%~EK#PLRx<4R^OOhGw^FIKnA*AuvyraQK3P@++CSaHGl5cUR)L&xJ3^f@d<>?VitH|G-@U05hi!o@iUW{jUk3ZZN3V
zC5fo9XsC2Gn_pD7EY`smq-~p5k$@`Wx5s~s9>c`iMLIStRj|5ShR%yvIj|h9Em54m
zkRj)$>#SV0=)kh>w-uR|d>{4fOtG(6s`ZV({AW7>@DDfuz;j&b`N`?R1C@F$?1MIS
zjg|VBcAv0p7adBGu2{YTKR$W{R?8ZZZ+(zY@lH(U3YeRp!~GjJLZTEa23De7DN@UJ
z(Z96&gs!oY58ABMYvIZ1!UK*gJrBV90|x+L_SD#!&U+qRQmQnzr6R$M#AGOn%$KN>
zo!dt4Q#kkW^W*PfqS}t2J4bu80!Huu7`AQQ21$}|@cVC|tFsdwZ7G&9tSR04_m+L{jUTnIdHkW7`SMUOAQcRmxr_9f!3Rc0F?R5K
zD4HGy;wE`y^D1n8@Im<8!`K^Rc>CQmDA|%I&Sl8x$SAIyKcy7C#6+P|3H)gm>`do-cgqb~@6X0A@}eJk-D86V6CK
z-8!^+2<37a!$YGm%_H!_r*Nv$&~`De&@)c1qNyh>NjAQ62+NI%Fw1^WHV>k
z`FZixUw&if-`z=v;X~q2dU9VG+59OKiv`r{b-cWHH)^#i7Mu_-lc-sjSkvM2VaIV5
z&-Ue7y`ejr!G@x8JAP!t7*5kf~t2ilS;#9HF$>+OZAYS48Zw%s75
zQYn}((cBaV2vZLz{>3-PiZM3!vxb_WMwPC!c(BS$A)5dor2Ae|+cLD3>eM
zGZPcTQwEdqBq|@n@fQT!qil2-fLAhM2
zXS3OFUOPGi*B%{!ZkncY`0$al0F-N|ssunuBocuQn>ReL`XhrMf9tI`$&T%hL6%wk
zg%@5}`OGuV{Q5%y0s;Apj_W$R_k7(G0+_s#-3nm#+T6-Dk=r?U-C94N&o>W^9oiiW
z#Re8HmHzA7`(6b=n8Mg!0QjpvstZ1(ZP^{*y_?=1{=dZk0CEu>=Ej2Zb^rhX07*qo
IM6N<$g2srGw*UYD
literal 0
HcmV?d00001
diff --git a/packages/bmx6-luci/files/www/luci-static/resources/bmx6/style.css b/packages/bmx6-luci/files/www/luci-static/resources/bmx6/style.css
new file mode 100644
index 0000000..d8191a7
--- /dev/null
+++ b/packages/bmx6-luci/files/www/luci-static/resources/bmx6/style.css
@@ -0,0 +1,22 @@
+ table {
+ width:90%;
+ border-top:1px solid #e5eaf8;
+ border-right:1px solid #e5eaf8;
+ margin:1em auto;
+ border-collapse:collapse;
+ }
+
+ td {
+ color:#678197;
+ border-bottom:1px solid #e6eff8;
+ border-left:1px solid #e6eff8;
+ padding:.3em 1em;
+ text-align:center;
+ }
+ th {
+ background:#f4f9fe;
+ text-align:center;
+ font:bold 1.2em/2em Century Gothic,Trebuchet MS,Arial,Helvetica,sans-serif;
+ color:#66a3d3;
+ }
+
diff --git a/packages/bmx6-luci/files/www/luci-static/resources/bmx6/wifi.png b/packages/bmx6-luci/files/www/luci-static/resources/bmx6/wifi.png
new file mode 100644
index 0000000000000000000000000000000000000000..4195b0872f4813e5bf5911b3b8179d29b823c76a
GIT binary patch
literal 3551
zcmZ{mc{tSF-^Yhcmh2?i-C44Xv1A+BiIJg@m_lO~#$YBhNY=7cG9!tStVT*RaJS}Dc0##Q5Fx+rdSTfD`e-K|5CRq!Vyz|1m6%BFOxQC
zT>6$d8ZuhXIRE=zu$xei7!qjU5Sg1)O6oV<2%p>UOC$Eh0zG$s&A`IL!x?4QYF8-}
z6Nr12>LaoKB3!W|Rba=!k_MfgQKUl-2CxykY2e1~%VOh#*0GxEtXSiC>Fz3uX9Ah>E&wUJV`(XEIGD
z&F&sz=foK2+SVtm3-^kv#qUgej06s)VfF~DYLBu1mG^Q$EHAJ}lsM`IZkXS%3_1+~^RvB+s^0d9(tYA^K`C}X
z%&+H?mlZAFN%I@)v&zBt>NkU;8?T@IVkuss!^`M4^>EzyMw7i)r7QcbgSiWYp@o#2
z$qzcFbVqOF*4vWpjXrajtHjp9u;F+omecwRx{wJpZBk+z0*UP-k|mBWWBI^kR(8$D|*fA-*`p!G2jvDLg)pE%C);^Zx{
zuRU%OhcDdqjt4G*YJW7S6*?*BR<~%0JREf|ac=gi@kjR#SA*T^BMz=!$t~YV{qAot
zn3~DQ-UW~}k$%JKqR-yK=6&pOQ}CS-ww>@FmrXKX9U=<^`OfdF1KtKrk!MyZ6cBxQ
zYxtQx90!$8F3M4Fg2VUvjE(mRgeg#M1~(iqcKt*!>xZZ-t%|dyjZqkxz{y#Z5f&Z=
zYgM=UybukXMXoFk3P0?Wq)hpKf`cpR`7imgMO$R+-CPoG+p;AvM-kd*8rW;vSI{o=
z@s50Ss}KhwQYR0{afa}ugU>KVAm%6kiZ_Do)UhF!ahA4ZuKiWrx82hIV-op~yVp)p
zX}T^h_>xZ1$^n7N{DACpce6FwM|d~;OiNi)j~x(8vREYS>rf-yD-kNqKm8>p*3A~s
zHa@dwP3AvdfB&ddu1mL~s!+j4;YV-h-r1S=qC@#nV3z)Pp0LDnLbfVGD
z4+C)X??og+G~zuxU6;CZ;XSU#`QG?Rqv5uCV(Y`X2FRJ%M_KD#de~v4pXviJ#;{f5-nu@x-@DotSdDMUCS@!O3Nqd0!vdbZbqWYbc+vRG*5tB(XF4w6>?k
zI*oOi%8^7tmMC~hek4Tm7rew>x{^Lytx-qcrdsZ=7WY83e01VWr2ekGcwkiOyLZwV
zb$sDID5tykF=0}#=WiQ$gRSV^YQCUqI8A0dhA-3
zHT%J*lc5Sl6XnCHpW5?laIPsHPZ1is#*%XP4!7_$Y?Y7KLp%2kO#&d~F|RK_}SN
zDhHK^MLpXT<5i~rdiot+hJpF0*Xl}W0U2Gy;sR=<uJkH06F4dS5-sE&E4PNs8@Y6v8nJn2XFYj#g7q0MvK%s@uRmQ&ZL7|bD
znO1rRBJ6UKYne?+{X5^tO!K06+n_#mwAZboa_Os((warC^G39r8-sTh`xZzI_PFrT
zj~^d-`}t?_ELJ-~a=qiVKWAPoh7Z_gKb}b`kM_oKSXgTpSM+Q;=&75QpM%xp0hjbd
zW$zaQm7sEtB;8<*YoPMx^Je5IxWbDs?lYql4c;2zXSOheZ?w~C3@!gw-!kSYM0QfD=cceGx2;Y&
zO4+|FUEO$q{i*q2)QI5YMiHjcnf
zZC-6@eqo|2BEEGV|KZCQCq|ZGXue9yuk3!0?am_JAL@O(+T=Gz4b~&nhF?y@jRqEnvO4_Q@
zv@c)pCmFM*j-MA}9y`ul8OwQ@csQk_533uHANUk1LZiggo!GUo@am69os*1v4vdCj
ze^;paL80_h1Iat|`0zH!3iW;6WxGh>`nUBjOv+u(nccU6WGbZC{G_Lcx-ioEjh6UB
zZMe2(GPoqZ%})<3=Pkcl^R$8e@c@72Kx?59T!R!4DrJn+sTZ9H)r)NU0jIE$=sYeG9YEH#NK2GBr1%ZdTlI_V_{SpzrlRrTx9mA!*@+7dJ
z^B*i5f-+6pcMWhEV6l~)lxrL*Bk}RI^DMDWPgJ
z+!2Y(22Wo-m-mt5xXXqs3t1Qapu_;Q_U!}-?ie83LT#^Uy&~Inj)*>;QIl0e8Xu0?
zOZ_$)rSS|(Jh{@$Pal@5AXjOVQI})OB~9D^+;peBuenHdTz)3bOP)6+n*uLvm5~F^+@sIoY2|oGEj)R-vAlH#Z0sW+K&&5JoZNkCQ
zka(n^2nFn+DzDTOg6MH9Y$~n#vTYa~xZBq2p>1_R?T(Cj?qlTSs4N}dGWA5y4wrlA
z#fbc{5M=O{`S%&8?EQ3JfNq4%be8Z*Mr_i%jg?#QCwBV8Psxb8+CGwfjpleC;=Wse
zU$2%{{oTbatrRUa|+4ab2$UhqJb^d7Wv
zjOkHjMVP@0jhqDKSc*B
zDl=d7yd+B(l4&5x8y^4&Mqtstp4c)bQ4Js91@^@v(f&j<5$qWPA|k+A
zYU*J3Xm}H|yZlji6oQ0?{KKIEn(7+rAazZUrk0b24n#`_ahY
zVnY6Zpx9aG1{2UcI>Gke0D%8yMEk1+V{upl8ihst6YyvUz7*)m4C;Zx`ysIY#s`c2
zO#1W@?TE*af|>UO1P2GJVf}GLB!YlG;?h^oi!n_S|C#~=kZ6EC0qrki?u#YJmYFXn%V48)F%uZO6FY{O|1}j5A
ZVr7ts0F-WxFpc3m7qncN-I?rX?NYW
zDvNH4+EsT|yXXpagStQs5)>5#X#gQoNE`>SlQ_msY>z#@&&@Oc{r|eD5|AKS_Uw*6
z>3#I-J9^I%?osPX<*rwo(xu#TA)CFgwH<`68=)Cu*!k3S9Qcw+W~#evY1~c6___zB
zlr;_A)uuP)`cXdAMUT;O4UIUZh~tPLhIY##>*-q`%(s3#wmUOZ5V`eLdh&Ik_vhB1
zcM|CrYFq8mQg4QooxtftO2-hT6dFnyS|oZxV`$$@p^k
z>czS0Q@I_M-Pc`InS?Hlx(fn28cKmCKpc?FBn63WNCHpcxq{~io-1@bh2w$mns|Z6++2-9
z(v`?3
z9Y6>pg<%-@mZDI|lExz$CDht>Ud9)jef@>>-;`3{7m@h3qkn(8`kR^?@5~pI(rB*{
zh$izZEmX>&?szm@m!{KZqqas6wHX;MGPJv!(#|e)JA-TKBr+K!^d+4#m66M{SPPOs
z?zW>)shxj%m`x2aFZbu
zpUzP1%@Ndm_Us;Dp|Zw>i;ExzNh61*KsP)1orp{itk*hpS`H=}l}*LuTqL(0U7DDX
zrS%$~W)WH%*KchzK0eN|BL~v?SRV47KWK(ZKF;q)x&{9hp9KVxOKBa
zyWK+9H8ipC0uRUYDeNq>RokZB?x2Z*9(d>-?+z$ZAuH7tj6|N12M#bfyUfV`1BeQE
z_x;OcQYjwzMv{rkSIFhkJaqgJ!^3$lUaT@XInC!ctLSD-v0A0E-3DLB_anl%30mt8
zsFcrQ8}lqy7Re@4n6VK0F;kP*Fg2l7-)3)Povy6K^o>QXd~%H_5(Wnc**|uGu|vnH
zH7XQ)Q_L^daGVf#+rzXvlm=3FK)*Qij5;^|2`jNrJ{i*A-OZ&7K
z*I(kZ$t83ngRW^*Dx1vRe1{;6C=cW~b@~J;D?@Kz21}G0-l62gSW)}?Z~q6n-$p-m
zY|M`QDvx|~A20p&k4RUZP(Z`P#pC?>YmD9>GtgINYH9}Cwu$i306UeWuRO%`^<^$!
zo&sl^tf?e@bhy&<@ZOuZBS=J+zkB-eKO7wDX}t3C+qB!;1VKO;`uLuUia^9*V&XG0
zxh@_&`XCz{Yec?_3Vk+LD`f063%4prU+)ry5r@YP5;Q~V8+D#|>@hx{zDiHdR#_uvS3aqR
zdo1
z9qiq^3qOt+=q*yt8q!``Re3!5=?}mC_Q`{#GhdnB<+QwZ=0_)f_2>ipRJge$VSSUJ
zwMpn~q1-yktE0Rcde~y(<8$oY)y=ctdl+wRiGm?~^v0X2q;Jc~BO@>_6Z7kjS(#>@=EbU>XKiGJy!}8yck0-OcRGbq*gKC7ZO+y(TA*j;;Uf
z=_5Ptc{5y?+0-0A_+`HD8Ft>cpEqB9i+Zg=+RR{T5VTv|KRQZpA;*;~moQ9&LRXfx
z^(DS_{4hqbt9Wj5!8?6$cjB&&KD;{Dv(f0R&s3Wx9qMJ5i$H
z2KZrwp_^p8vQ(F=AcAR`7^Xqwx>&l2W(XNOK}mS`%Zsuz3
z@JPcA3+*8AT;H?8AjWZhbOg;Z34;I?$7Jm!QRtED%9u&RjN>?*DCSe%(LFuO{6Ffy
XJC$YshjJ?x00000NkvXXu0mjf;7FEt
literal 0
HcmV?d00001
diff --git a/packages/bmx6-luci/files/www/luci-static/resources/bmx6/world_small.png b/packages/bmx6-luci/files/www/luci-static/resources/bmx6/world_small.png
new file mode 100644
index 0000000000000000000000000000000000000000..f5f31056c65084460d38d309afba7a848d37caf0
GIT binary patch
literal 923
zcmV;M17!S(P)SkJX=+>gNTc|mwMr`$#Fi=*>c*`IiVOb*
z7cL4eT!~w8rzqHf+NeZmlaQ%NNSfwh(>x}LnVCDU`UVWzP`IXKfdiobEy>7swr0+Fu!7XW$9o-h=Y{
zJAQD|a7vMx6+;>UY&Shh)he#nBApQsPYA7BM^8Xg%TU~MZvjLBexBa=aDKPWwRd0T
z!OXe{qYAqXlR`dApt?-XZW6RZqH8fs8E0{ROUlFQwb`v&CJHb
zsRB+IVQivET-5;;K>$_+m#Apkbsla;z3+dk$OwSl`_czb<)7(auR0{-8j}-C=v_H#
zb(7P>$M8bI#Qga=6{Ql<@
z`Ft;@hh9KLTkMqU*i|WYO^Vls2ZSP}6xT1FNMCw!kh!tHFpUTyYd3g#6;88*i`AF5tEr(sNDPjwyW~79Xx~X6P(V
zt%WK&H0w1fU6T_z!Oe@uZwn#X3V
4@>|swPtrUJxA8-
xrf_W!O;2Jqnq)Hxvgwr4*PStYvJrpJ{~uzmj|OZihQ9y+002ovPDHLkV1ltKp)CLa
literal 0
HcmV?d00001
diff --git a/packages/bmx6-qmp/Makefile b/packages/bmx6-qmp/Makefile
new file mode 100644
index 0000000..e92483e
--- /dev/null
+++ b/packages/bmx6-qmp/Makefile
@@ -0,0 +1,157 @@
+# Copyright (C) 2011 Fundacio Privada per a la Xarxa Oberta, Lliure i Neutral guifi.net
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contibutors:
+# Axel Neumann, Simó Albert i Beltran, Pau Escrich
+#
+
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bmx6-qmp
+
+PKG_SOURCE_PROTO:=git
+
+Public Sources:
+#PKG_SOURCE_URL:=git://git.bmx6.net/bmx6.git
+PKG_SOURCE_URL:=git://github.com/axn/bmx6.git
+
+PKG_REV:=7219010098ea67f8ea08a06a68e7a765b114ca16
+
+Private Sources:
+#PKG_SOURCE_URL:=file:///usr/src/bmx6/bmx6-private.git
+
+PKG_VERSION:=r2013022001
+
+PKG_RELEASE:=4
+#PKG_INSTALL:=1 # this tries to install straight to /usr/sbin/bmx6
+
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
+
+include $(INCLUDE_DIR)/package.mk
+
+
+TARGET_CFLAGS += $(FPIC)
+
+#-DNO_TRAFFIC_DUMP -DNO_DYN_PLUGIN -DNO_DEBUG_DUMP -DNO_DEBUG_ALL -DNO_DEBUG_TRACK -DNO_DEBUG_SYS
+
+MAKE_ARGS += \
+ EXTRA_CFLAGS="$(TARGET_CFLAGS) -I. -I$(STAGING_DIR)/usr/include -DNO_DEBUG_ALL -DNO_DEBUG_DUMP" \
+ EXTRA_LDFLAGS="-L$(STAGING_DIR)/usr/lib " \
+ REVISION_VERSION="$(PKG_REV)" \
+ CC="$(TARGET_CC)" \
+ INSTALL_DIR="$(PKG_INSTALL_DIR)" \
+ STRIP="/bin/false" \
+ build_all
+
+
+define Package/bmx6-qmp/Default
+ SECTION:=net
+ CATEGORY:=qMp
+ TITLE:=BMX6 layer 3 routing daemon (QMP version)
+ URL:=http://bmx6.net/
+ MAINTAINER:=Axel Neumann
+endef
+
+define Package/bmx6-qmp/description
+BMX6 layer 3 routing daemon (QMP version) supporting IPv4, IPv6, and IPv4 over IPv6 - http://www.bmx6.net
+endef
+
+define Package/bmx6-qmp
+ $(call Package/bmx6-qmp/Default)
+ MENU:=1
+endef
+
+define Package/bmx6-qmp-uci-config
+ $(call Package/bmx6-qmp/Default)
+ DEPENDS:=bmx6-qmp +libuci
+ TITLE:=configuration plugin based on uci (recommended!)
+endef
+
+
+define Package/bmx6-qmp-json
+ $(call Package/bmx6-qmp/Default)
+ DEPENDS:=bmx6-qmp +libjson
+ TITLE:=josn plugin based on jsonc
+endef
+
+define Package/bmx6-qmp-sms
+ $(call Package/bmx6-qmp/Default)
+ DEPENDS:=bmx6-qmp
+ TITLE:=sms plugin
+endef
+
+define Package/bmx6-qmp-quagga
+ $(call Package/bmx6-qmp/Default)
+ DEPENDS:=bmx6-qmp +qmp-quagga
+ TITLE:=bmx6 quagga plugin to redistribute/export routes (needs manet/bmx6 patched quagga 0.99.21)
+endef
+
+define Build/Configure
+ mkdir -p $(PKG_INSTALL_DIR)
+endef
+
+define Build/Compile
+ $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_ARGS)
+endef
+
+
+define Package/bmx6-qmp/install
+ $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/bmx6 $(1)/usr/sbin/bmx6
+endef
+
+
+define Package/bmx6-qmp-uci-config/conffiles
+/etc/config/bmx6
+endef
+
+
+define Package/bmx6-qmp-uci-config/install
+ $(INSTALL_DIR) $(1)/usr/lib $(1)/etc/config $(1)/etc/init.d
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/bmx6_uci_config/bmx6_config.so $(1)/usr/lib/bmx6_config.so
+ $(INSTALL_BIN) ./files/etc/init.d/bmx6 $(1)/etc/init.d/bmx6
+ $(INSTALL_DATA) ./files/etc/config/bmx6 $(1)/etc/config/bmx6
+endef
+
+define Package/bmx6-qmp-json/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/bmx6_json/bmx6_json.so $(1)/usr/lib/bmx6_json.so
+endef
+
+define Package/bmx6-qmp-sms/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/bmx6_sms/bmx6_sms.so $(1)/usr/lib/bmx6_sms.so
+endef
+
+define Package/bmx6-qmp-quagga/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/bmx6_quagga/bmx6_quagga.so $(1)/usr/lib/bmx6_quagga.so
+endef
+
+$(eval $(call BuildPackage,bmx6-qmp))
+$(eval $(call BuildPackage,bmx6-qmp-uci-config))
+$(eval $(call BuildPackage,bmx6-qmp-json))
+$(eval $(call BuildPackage,bmx6-qmp-sms))
+$(eval $(call BuildPackage,bmx6-qmp-quagga))
+
+
diff --git a/packages/bmx6-qmp/files/etc/config/bmx6 b/packages/bmx6-qmp/files/etc/config/bmx6
new file mode 100644
index 0000000..884fd12
--- /dev/null
+++ b/packages/bmx6-qmp/files/etc/config/bmx6
@@ -0,0 +1,82 @@
+
+# for more information:
+# http://bmx6.net/projects/bmx6/wiki
+# options execute: bmx6 --help
+
+config 'bmx6' 'general'
+# option 'runtimeDir' '/var/run/bmx6'
+# option 'tun4Address' '10.202.0.116/32'
+# option 'tun4Address' '10.254.10.0/32'
+# option 'tun6Address' '2012:0:0:1000::1/64'
+
+#config 'ipVersion' 'ipVersion'
+# option 'ipVersion' '6' # default is 4
+# option 'throwRules' '0'
+
+
+#config 'plugin'
+# option 'plugin' 'bmx6_config.so'
+
+
+
+#config 'plugin'
+# option 'plugin' 'bmx6_json.so'
+
+
+
+#config 'plugin'
+# option 'plugin' 'bmx6_sms.so'
+
+
+config 'dev' 'mesh_1'
+ option 'dev' 'eth0.12'
+
+config 'dev' 'mesh_2'
+ option 'dev' 'ath0.12'
+
+
+
+#config 'hna' 'my_global_prefix'
+# option 'hna' '2012:0:0:74:0:0:0:0/64'
+
+
+#config 'tunOut'
+# option 'tunOut' 'ip6'
+# option 'network' '2012::/16'
+# option 'exportDistance' '0'
+
+#config 'tunOut'
+# option 'tunOut' 'ip4'
+# option 'network' '10.254.0.0/16'
+# option 'exportDistance' '0' # requires quagga plugin !
+# option 'minPrefixLen' '27'
+
+
+
+#config 'plugin'
+# option 'plugin' 'bmx6_quagga.so'
+
+
+
+#config 'redistribute'
+# option 'redistribute' 'ospf6'
+# option 'network' '10.0.0.0/8'
+# option 'minPrefixLen' '10'
+# option 'bandwidth' '10000000'
+# option 'ospf6' '1'
+# option 'aggregatePrefixLen' '16'
+
+#config 'redistribute'
+# option 'redistribute' 'bgp'
+# option 'network' '0.0.0.0/0'
+# option 'minPrefixLen' '0'
+# option 'maxPrefixLen' '24'
+# option 'bandwidth' '10000000'
+# option 'bgp' '1'
+# option 'aggregatePrefixLen' '8'
+
+
+
+
+
+
diff --git a/packages/bmx6-qmp/files/etc/init.d/bmx6 b/packages/bmx6-qmp/files/etc/init.d/bmx6
new file mode 100755
index 0000000..2b54386
--- /dev/null
+++ b/packages/bmx6-qmp/files/etc/init.d/bmx6
@@ -0,0 +1,41 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2011 Fundacio Privada per a la Xarxa Oberta, Lliure i Neutral guifi.net
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+
+START=91
+
+BIN=/usr/sbin/bmx6
+CONF=/etc/config/bmx6
+PID=/var/run/bmx6/pid
+
+
+start() {
+ cd /root/
+ ulimit -c 20000
+ $BIN -f $CONF -d0 > /dev/null &
+# start-stop-daemon -b -x $BIN -S -- -f $CONF
+}
+
+stop() {
+ start-stop-daemon -p $PID -K
+}
+
+restart() {
+ stop; sleep 3; start
+}
diff --git a/packages/qmp-quagga/Makefile b/packages/qmp-quagga/Makefile
new file mode 100644
index 0000000..2401827
--- /dev/null
+++ b/packages/qmp-quagga/Makefile
@@ -0,0 +1,312 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# Contributors:
+# Simó Albert i Beltran
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=qmp-quagga
+PKG_VERSION:=0.99.21
+PKG_RELEASE:=2
+PKG_MD5SUM:=99840adbe57047c90dfba6b6ed9aec7f
+
+PKG_SOURCE:=quagga-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.quagga.net/download/ \
+ http://www.de.quagga.net/download/ \
+ http://www.uk.quagga.net/download/
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/quagga-$(PKG_VERSION)
+
+PKG_CONFIG_DEPENDS:= \
+ CONFIG_IPV6 \
+ CONFIG_PACKAGE_qmp-quagga-watchquagga \
+ CONFIG_PACKAGE_qmp-quagga-zebra \
+ CONFIG_PACKAGE_qmp-quagga-libzebra \
+ CONFIG_PACKAGE_qmp-quagga-libospf \
+ CONFIG_PACKAGE_qmp-quagga-bgpd \
+ CONFIG_PACKAGE_qmp-quagga-isisd \
+ CONFIG_PACKAGE_qmp-quagga-ospf6d \
+ CONFIG_PACKAGE_qmp-quagga-ripd \
+ CONFIG_PACKAGE_qmp-quagga-ripngd \
+ CONFIG_PACKAGE_qmp-quagga-babeld \
+ CONFIG_PACKAGE_qmp-quagga-vtysh
+PKG_BUILD_PARALLEL:=1
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/qmp-quagga/Default
+ SECTION:=qMp
+ CATEGORY:=qMp
+ SUBMENU:=Routing and Redirection
+ DEPENDS:=qmp-quagga
+ TITLE:=The Quagga Software Routing Suite
+ URL:=http://www.quagga.net
+ MAINTAINER:=Vasilis Tsiligiannis
+endef
+
+define Package/qmp-quagga
+ $(call Package/qmp-quagga/Default)
+ DEPENDS:=+qmp-quagga-vtysh +qmp-quagga-bgpd
+ MENU:=1
+endef
+
+define Package/qmp-quagga/description
+ A routing software package that provides TCP/IP based routing services
+ with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2,
+ OSPFv3, BGP-4, and BGP-4+
+endef
+
+define Package/qmp-quagga-watchquagga
+ $(call Package/qmp-quagga/Default)
+ TITLE:=Quagga watchdog
+ DEPENDS+=+qmp-quagga-libzebra
+ DEFAULT:=y if PACKAGE_qmp-quagga
+endef
+
+define Package/qmp-quagga-zebra
+ $(call Package/qmp-quagga/Default)
+ TITLE:=Zebra daemon
+ DEPENDS+=+qmp-quagga-libzebra
+ DEFAULT:=y if PACKAGE_qmp-quagga
+endef
+
+define Package/qmp-quagga-libzebra
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+librt
+ TITLE:=zebra library
+endef
+
+define Package/qmp-quagga-libospf
+ $(call Package/qmp-quagga/Default)
+ TITLE:=OSPF library
+endef
+
+define Package/qmp-quagga-bgpd
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libzebra
+ TITLE:=BGPv4, BGPv4+, BGPv4- routing engine
+endef
+
+define Package/qmp-quagga-isisd
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libzebra
+ TITLE:=IS-IS routing engine
+endef
+
+define Package/qmp-quagga-ospfd
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libospf +qmp-quagga-libzebra
+ TITLE:=OSPFv2 routing engine
+endef
+
+define Package/qmp-quagga-ospf6d
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libospf +qmp-quagga-libzebra @IPV6
+ TITLE:=OSPFv3 routing engine
+endef
+
+define Package/qmp-quagga-ripd
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libzebra
+ TITLE:=RIP routing engine
+endef
+
+define Package/qmp-quagga-ripngd
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libzebra @IPV6
+ TITLE:=RIPNG routing engine
+endef
+
+define Package/qmp-quagga-babeld
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libzebra
+ TITLE:=Babel routing engine
+endef
+
+define Package/qmp-quagga-vtysh
+ $(call Package/qmp-quagga/Default)
+ DEPENDS+=+qmp-quagga-libzebra +libreadline +libncurses
+ TITLE:=integrated shell for Quagga routing software
+endef
+
+define Package/qmp-quagga-zebra/conffiles
+/etc/quagga/zebra.conf
+endef
+
+define Package/qmp-quagga-bgpd/conffiles
+/etc/quagga/bgpd.conf
+endef
+
+define Package/qmp-quagga-isisd/conffiles
+/etc/quagga/isisd.conf
+endef
+
+define Package/qmp-quagga-ospfd/conffiles
+/etc/quagga/ospfd.conf
+endef
+
+define Package/qmp-quagga-ospf6d/conffiles
+/etc/quagga/ospf6d.conf
+endef
+
+define Package/qmp-quagga-ripd/conffiles
+/etc/quagga/ripd.conf
+endef
+
+define Package/qmp-quagga-ripngd/conffiles
+/etc/quagga/ripngd.conf
+endef
+
+define Package/qmp-quagga-babeld/conffiles
+/etc/quagga/babeld.conf
+endef
+
+ifneq ($(SDK),)
+CONFIG_PACKAGE_qmp-quagga-libzebra:=m
+CONFIG_PACKAGE_qmp-quagga-libospf:=m
+CONFIG_PACKAGE_qmp-quagga-watchquagga:=m
+CONFIG_PACKAGE_qmp-quagga-zebra:=m
+CONFIG_PACKAGE_qmp-quagga-bgpd:=m
+CONFIG_PACKAGE_qmp-quagga-isisd:=m
+CONFIG_PACKAGE_qmp-quagga-ospf6d:=m
+CONFIG_PACKAGE_qmp-quagga-ripd:=m
+CONFIG_PACKAGE_qmp-quagga-ripngd:=m
+CONFIG_PACKAGE_qmp-quagga-babeld:=m
+CONFIG_PACKAGE_qmp-quagga-vtysh:=m
+endif
+
+CONFIGURE_ARGS+= \
+ --localstatedir=/var/run/quagga \
+ --sysconfdir=/etc/quagga/ \
+ --enable-shared \
+ --disable-static \
+ --enable-user=network \
+ --enable-group=network \
+ --enable-pie=no \
+ --enable-multipath=8 \
+ --disable-ospfclient \
+ --disable-capabilities \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-libzebra,zebra) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-libospf,ospfd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-bgpd,bgpd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-isisd,isisd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-ospf6d,ospf6d) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-ripd,ripd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-ripngd,ripngd) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-babeld,babeld) \
+ $(call autoconf_bool,CONFIG_PACKAGE_qmp-quagga-vtysh,vtysh) \
+
+MAKE_FLAGS += \
+ CFLAGS="$(TARGET_CFLAGS) -std=gnu99"
+
+define Package/qmp-quagga/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) ./files/quagga $(1)/usr/sbin/quagga.init
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/quagga.init $(1)/etc/init.d/quagga
+endef
+
+define Package/qmp-quagga-watchquagga/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/watchquagga $(1)/usr/sbin/
+endef
+
+define Package/qmp-quagga-zebra/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/zebra $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/zebra.conf
+endef
+
+define Package/qmp-quagga-bgpd/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/bgpd $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/bgpd.conf
+endef
+
+define Package/qmp-quagga-isisd/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/isisd $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/isisd.conf
+endef
+
+define Package/qmp-quagga-ospfd/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ospfd $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ospfd.conf
+endef
+
+define Package/qmp-quagga-ospf6d/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ospf6d $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ospf6d.conf
+endef
+
+define Package/qmp-quagga-ripd/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ripd $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ripd.conf
+endef
+
+define Package/qmp-quagga-ripngd/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ripngd $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/ripngd.conf
+endef
+
+define Package/qmp-quagga-babeld/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/babeld $(1)/usr/sbin/
+ $(INSTALL_DIR) $(1)/etc/quagga
+ chmod 0750 $(1)/etc/quagga
+ $(INSTALL_CONF) ./files/quagga.conf $(1)/etc/quagga/babeld.conf
+endef
+
+define Package/qmp-quagga-vtysh/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vtysh $(1)/usr/bin/
+endef
+
+define Package/qmp-quagga-libospf/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libospf.so.* $(1)/usr/lib/
+endef
+
+define Package/qmp-quagga-libzebra/install
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libzebra.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,qmp-quagga))
+$(eval $(call BuildPackage,qmp-quagga-libzebra))
+$(eval $(call BuildPackage,qmp-quagga-libospf))
+$(eval $(call BuildPackage,qmp-quagga-watchquagga))
+$(eval $(call BuildPackage,qmp-quagga-zebra))
+$(eval $(call BuildPackage,qmp-quagga-bgpd))
+$(eval $(call BuildPackage,qmp-quagga-isisd))
+$(eval $(call BuildPackage,qmp-quagga-ospfd))
+$(eval $(call BuildPackage,qmp-quagga-ospf6d))
+$(eval $(call BuildPackage,qmp-quagga-ripd))
+$(eval $(call BuildPackage,qmp-quagga-ripngd))
+$(eval $(call BuildPackage,qmp-quagga-babeld))
+$(eval $(call BuildPackage,qmp-quagga-vtysh))
diff --git a/packages/qmp-quagga/files/quagga b/packages/qmp-quagga/files/quagga
new file mode 100644
index 0000000..0ccfb1c
--- /dev/null
+++ b/packages/qmp-quagga/files/quagga
@@ -0,0 +1,335 @@
+#!/bin/sh
+#
+# quagga Starts/stops quagga daemons and watchquagga.
+# Create a daemon.conf file to have that routing daemon
+# started/stopped automagically when using this script
+# without any daemon names as args.
+# If watchquagga is available, it will also be
+# started/stopped if the script is called without
+# any daemon names.
+#
+
+ME=$(basename $0)
+
+usage() {
+ echo "Usage: ${ME} {start|stop|restart} [daemon ...]"
+ exit 2
+}
+
+if [ -z "$1" ]
+then
+ usage
+else
+ COMMAND=$1
+fi
+shift
+ARG_DAEMONS=$*
+BINDIR=/usr/sbin
+CONFDIR=/etc/quagga
+STATEDIR=/var/run/quagga
+RUNUSER=network
+RUNGROUP=$RUNUSER
+DAEMONS="zebra ripd ripngd ospfd ospf6d bgpd"
+DAEMON_FLAGS=-d
+WATCHQUAGGA_FLAGS="-d -z -T 60 -R"
+WATCHQUAGGA_CMD="$0 watchrestart"
+if [ ${COMMAND} != "watchrestart" ]
+then
+ DAEMONS="${DAEMONS} watchquagga"
+fi
+DAEMONS_STARTSEQ=${DAEMONS}
+
+reverse()
+{
+ local revlist r
+ revlist=
+ for r
+ do
+ revlist="$r $revlist"
+ done
+ echo $revlist
+}
+
+DAEMONS_STOPSEQ=$(reverse ${DAEMONS_STARTSEQ})
+
+#pidof() {
+# ps ax | awk 'match($5, "(^|/)'"$1"'$") > 0 { printf " %s", $1 }'
+#}
+
+quit() {
+ echo "${ME}: $1"
+ exit 0
+}
+
+die() {
+ echo "${ME}: $1"
+ exit 1
+}
+
+is_in() {
+ local i
+ for i in $2
+ do
+ [ "$1" = "$i" ] && return 0
+ done
+ return 1
+}
+
+select_subset() {
+ local unknown i j
+ unknown=
+ RESULT=
+ for i in $1
+ do
+ is_in $i "$2" || unknown="$unknown $i"
+ done
+ if [ -n "$unknown" ]
+ then
+ RESULT=$unknown
+ return 1
+ else
+ for j in $2
+ do
+ is_in $j "$1" && RESULT="$RESULT $j"
+ done
+ return 0
+ fi
+}
+
+# check command
+
+case ${COMMAND}
+in
+ start|stop|restart)
+ ;;
+ watchrestart)
+ if [ -n "$ARG_DAEMONS" ]
+ then
+ echo "${ME}: watchrestart mode is only for use by watchquagga"
+ exit 2
+ fi
+ ;;
+ *)
+ usage
+ ;;
+esac
+
+# select daemons to start
+
+case ${COMMAND}
+in
+ start|restart|watchrestart)
+ START_DAEMONS=
+ for d in ${DAEMONS_STARTSEQ}
+ do
+ [ -x "${BINDIR}/${d}" -a -f "${CONFDIR}/${d}.conf" ] \
+ && START_DAEMONS="${START_DAEMONS}${d} "
+ done
+ WATCHQUAGGA_DAEMONS=${START_DAEMONS}
+ if is_in watchquagga "${DAEMONS_STARTSEQ}"
+ then
+ START_DAEMONS="${START_DAEMONS} watchquagga"
+ fi
+ if [ -n "${ARG_DAEMONS}" ]
+ then
+ if select_subset "${ARG_DAEMONS}" "${DAEMONS}"
+ then
+ if select_subset "${ARG_DAEMONS}" "${START_DAEMONS}"
+ then
+ START_DAEMONS=${RESULT}
+ else
+ die "these daemons are not startable:${RESULT}."
+ fi
+ else
+ die "unknown daemons:${RESULT}; choose from: ${DAEMONS}."
+ fi
+ fi
+ ;;
+esac
+
+# select daemons to stop
+
+case ${COMMAND}
+in
+ stop|restart|watchrestart)
+ STOP_DAEMONS=${DAEMONS_STOPSEQ}
+ if [ -n "${ARG_DAEMONS}" ]
+ then
+ if select_subset "${ARG_DAEMONS}" "${STOP_DAEMONS}"
+ then
+ STOP_DAEMONS=${RESULT}
+ else
+ die "unknown daemons:${RESULT}; choose from: ${DAEMONS}."
+ fi
+ fi
+ stop_daemons=
+ for d in ${STOP_DAEMONS}
+ do
+ pidfile=${STATEDIR}/${d}.pid
+ if [ -f "${pidfile}" -o -n "$(pidof ${d})" ]
+ then
+ stop_daemons="${stop_daemons}${d} "
+ elif [ -n "${ARG_DAEMONS}" ]
+ then
+ echo "${ME}: found no ${d} process running."
+ fi
+ done
+ STOP_DAEMONS=${stop_daemons}
+ ;;
+esac
+
+# stop daemons
+
+for d in $STOP_DAEMONS
+do
+ echo -n "${ME}: Stopping ${d} ... "
+ pidfile=${STATEDIR}/${d}.pid
+ if [ -f "${pidfile}" ]
+ then
+ file_pid=$(cat ${pidfile})
+ if [ -z "${file_pid}" ]
+ then
+ echo -n "no pid file entry found ... "
+ fi
+ else
+ file_pid=
+ echo -n "no pid file found ... "
+ fi
+ proc_pid=$(pidof ${d})
+ if [ -z "${proc_pid}" ]
+ then
+ echo -n "found no ${d} process running ... "
+ else
+ count=0
+ notinpidfile=
+ for p in ${proc_pid}
+ do
+ count=$((${count}+1))
+ if kill ${p}
+ then
+ echo -n "killed ${p} ... "
+ else
+ echo -n "failed to kill ${p} ... "
+ fi
+ [ "${p}" = "${file_pid}" ] \
+ || notinpidfile="${notinpidfile} ${p}"
+ done
+ [ ${count} -le 1 ] \
+ || echo -n "WARNING: ${count} ${d} processes were found running ... "
+ for n in ${notinpidfile}
+ do
+ echo -n "WARNING: process ${n} was not in pid file ... "
+ done
+ fi
+ count=0
+ survivors=$(pidof ${d})
+ while [ -n "${survivors}" ]
+ do
+ sleep 1
+ count=$((${count}+1))
+ survivors=$(pidof ${d})
+ [ -z "${survivors}" -o ${count} -gt 5 ] && break
+ for p in ${survivors}
+ do
+ sleep 1
+ echo -n "${p} "
+ kill ${p}
+ done
+ done
+ survivors=$(pidof ${d})
+ [ -n "${survivors}" ] && \
+ if kill -KILL ${survivors}
+ then
+ echo -n "KILLed ${survivors} ... "
+ else
+ echo -n "failed to KILL ${survivors} ... "
+ fi
+ sleep 1
+ survivors=$(pidof ${d})
+ if [ -z "${survivors}" ]
+ then
+ echo -n "done."
+ if [ -f "${pidfile}" ]
+ then
+ rm -f ${pidfile} \
+ || echo -n " Failed to remove pidfile."
+ fi
+ else
+ echo -n "failed to stop ${survivors} - giving up."
+ if [ "${survivors}" != "${file_pid}" ]
+ then
+ if echo "${survivors}" > ${pidfile}
+ then
+ chown ${RUNUSER}:${RUNGROUP} ${pidfile}
+ echo -n " Wrote ${survivors} to pidfile."
+ else
+ echo -n " Failed to write ${survivors} to pidfile."
+ fi
+ fi
+ fi
+ echo
+done
+
+# start daemons
+
+if [ -n "$START_DAEMONS" ]
+then
+ [ -d ${CONFDIR} ] \
+ || quit "${ME}: no config directory ${CONFDIR} - exiting."
+ chown -R ${RUNUSER}:${RUNGROUP} ${CONFDIR}
+ [ -d ${STATEDIR} ] || mkdir -p ${STATEDIR} \
+ || die "${ME}: could not create state directory ${STATEDIR} - exiting."
+ chown -R ${RUNUSER}:${RUNGROUP} ${STATEDIR}
+
+ for d in $START_DAEMONS
+ do
+ echo -n "${ME}: Starting ${d} ... "
+ proc_pid=$(pidof ${d})
+ pidfile=${STATEDIR}/${d}.pid
+ file_pid=
+ if [ -f "${pidfile}" ]
+ then
+ file_pid=$(cat ${pidfile})
+ if [ -n "${file_pid}" ]
+ then
+ echo -n "found old pid file entry ${file_pid} ... "
+ fi
+ fi
+ if [ -n "${proc_pid}" ]
+ then
+ echo -n "found ${d} running (${proc_pid}) - skipping ${d}."
+ if [ "${proc_pid}" != "${file_pid}" ]
+ then
+ if echo "${proc_pid}" > ${pidfile}
+ then
+ chown ${RUNUSER}:${RUNGROUP} ${pidfile}
+ echo -n " Wrote ${proc_pid} to pidfile."
+ else
+ echo -n " Failed to write ${proc_pid} to pidfile."
+ fi
+ fi
+ elif rm -f "${pidfile}"
+ then
+ if [ "${d}" = "watchquagga" ]
+ then
+ "${BINDIR}/${d}" \
+ ${WATCHQUAGGA_FLAGS} \
+ "${WATCHQUAGGA_CMD}" \
+ ${WATCHQUAGGA_DAEMONS}
+ status=$?
+ else
+ "${BINDIR}/${d}" ${DAEMON_FLAGS}
+ status=$?
+ fi
+ if [ $status -eq 0 ]
+ then
+ echo -n "done."
+ else
+ echo -n "failed."
+ fi
+ else
+ echo -n " failed to remove pidfile."
+ fi
+ echo
+ done
+fi
diff --git a/packages/qmp-quagga/files/quagga.conf b/packages/qmp-quagga/files/quagga.conf
new file mode 100644
index 0000000..fb7a54e
--- /dev/null
+++ b/packages/qmp-quagga/files/quagga.conf
@@ -0,0 +1,7 @@
+password zebra
+!
+access-list vty permit 127.0.0.0/8
+access-list vty deny any
+!
+line vty
+ access-class vty
diff --git a/packages/qmp-quagga/files/quagga.init b/packages/qmp-quagga/files/quagga.init
new file mode 100644
index 0000000..21fbf2c
--- /dev/null
+++ b/packages/qmp-quagga/files/quagga.init
@@ -0,0 +1,11 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+START=60
+start() {
+ /usr/sbin/quagga.init start
+}
+
+stop() {
+ /usr/sbin/quagga.init stop
+}
diff --git a/packages/qmp-quagga/patches/110-fix_ipctl_forwarding.patch b/packages/qmp-quagga/patches/110-fix_ipctl_forwarding.patch
new file mode 100644
index 0000000..d757312
--- /dev/null
+++ b/packages/qmp-quagga/patches/110-fix_ipctl_forwarding.patch
@@ -0,0 +1,25 @@
+Add definitions for IPCTL_FORWARDING and IP6CTL_FORWARDING.
+
+Inspired from
+http://svn.gnumonks.org/trunk/grouter/build/src/quagga/quagga/quagga-0.99.1-forward_sysctl-2.6.14.patch
+
+Signed-off-by: Thomas Petazzoni
+
+--- a/zebra/ipforward_sysctl.c
++++ b/zebra/ipforward_sysctl.c
+@@ -31,6 +31,15 @@
+
+ #define MIB_SIZ 4
+
++/* Fix for recent (2.6.14) kernel headers */
++#ifndef IPCTL_FORWARDING
++#define IPCTL_FORWARDING NET_IPV4_FORWARD
++#endif
++
++#ifndef IP6CTL_FORWARDING
++#define IP6CTL_FORWARDING NET_IPV6_FORWARDING
++#endif
++
+ extern struct zebra_privs_t zserv_privs;
+
+ /* IPv4 forwarding control MIB. */
diff --git a/packages/qmp-quagga/patches/120-quagga_manet.patch b/packages/qmp-quagga/patches/120-quagga_manet.patch
new file mode 100644
index 0000000..bf6d056
--- /dev/null
+++ b/packages/qmp-quagga/patches/120-quagga_manet.patch
@@ -0,0 +1,243 @@
+--- a/lib/log.c
++++ b/lib/log.c
+@@ -929,13 +929,19 @@ proto_redistnum(int afi, const char *s)
+ return ZEBRA_ROUTE_STATIC;
+ else if (strncmp (s, "r", 1) == 0)
+ return ZEBRA_ROUTE_RIP;
+- else if (strncmp (s, "o", 1) == 0)
++ else if (strncmp (s, "os", 2) == 0)
+ return ZEBRA_ROUTE_OSPF;
+ else if (strncmp (s, "i", 1) == 0)
+ return ZEBRA_ROUTE_ISIS;
+ else if (strncmp (s, "bg", 2) == 0)
+ return ZEBRA_ROUTE_BGP;
+- else if (strncmp (s, "ba", 2) == 0)
++ else if (strncmp (s, "h", 1) == 0)
++ return ZEBRA_ROUTE_HSLS;
++ else if (strncmp (s, "ol", 2) == 0)
++ return ZEBRA_ROUTE_OLSR;
++ else if (strncmp (s, "bat", 3) == 0)
++ return ZEBRA_ROUTE_BATMAN;
++ else if (strncmp (s, "bab", 3) == 0)
+ return ZEBRA_ROUTE_BABEL;
+ }
+ if (afi == AFI_IP6)
+@@ -948,13 +954,19 @@ proto_redistnum(int afi, const char *s)
+ return ZEBRA_ROUTE_STATIC;
+ else if (strncmp (s, "r", 1) == 0)
+ return ZEBRA_ROUTE_RIPNG;
+- else if (strncmp (s, "o", 1) == 0)
++ else if (strncmp (s, "os", 2) == 0)
+ return ZEBRA_ROUTE_OSPF6;
+ else if (strncmp (s, "i", 1) == 0)
+ return ZEBRA_ROUTE_ISIS;
+ else if (strncmp (s, "bg", 2) == 0)
+ return ZEBRA_ROUTE_BGP;
+- else if (strncmp (s, "ba", 2) == 0)
++ else if (strncmp (s, "h", 1) == 0)
++ return ZEBRA_ROUTE_HSLS;
++ else if (strncmp (s, "ol", 2) == 0)
++ return ZEBRA_ROUTE_OLSR;
++ else if (strncmp (s, "bat", 3) == 0)
++ return ZEBRA_ROUTE_BATMAN;
++ else if (strncmp (s, "bab", 3) == 0)
+ return ZEBRA_ROUTE_BABEL;
+ }
+ return -1;
+--- a/lib/route_types.txt
++++ b/lib/route_types.txt
+@@ -51,13 +51,9 @@ ZEBRA_ROUTE_OSPF, ospf, ospfd
+ ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv6"
+ ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS"
+ ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
+-# HSLS and OLSR both are AFI independent (so: 1, 1), however
+-# we want to disable for them for general Quagga distribution.
+-# This at least makes it trivial for users of these protocols
+-# to 'switch on' redist support (direct numeric entry remaining
+-# possible).
+-ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
+-ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
++ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 1, 1, "HSLS"
++ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 1, 1, "OLSR"
++ZEBRA_ROUTE_BATMAN, batman, batmand,'b', 1, 1, "BATMAN"
+ ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
+
+ ## help strings
+@@ -72,5 +68,6 @@ ZEBRA_ROUTE_OSPF6, "Open Shortest Path
+ ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)"
+ ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)"
+ ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
+-ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
++ZEBRA_ROUTE_OLSR, "Optimized Link State Routing (OLSR)"
++ZEBRA_ROUTE_BATMAN, "Better Approach to Mobile Ad-Hoc Networking (BATMAN)"
+ ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
+--- a/ripd/rip_zebra.c
++++ b/ripd/rip_zebra.c
+@@ -206,9 +206,12 @@ static struct {
+ {ZEBRA_ROUTE_KERNEL, 1, "kernel"},
+ {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+ {ZEBRA_ROUTE_STATIC, 1, "static"},
+- {ZEBRA_ROUTE_OSPF, 1, "ospf"},
++ {ZEBRA_ROUTE_OSPF, 2, "ospf"},
+ {ZEBRA_ROUTE_BGP, 2, "bgp"},
+- {ZEBRA_ROUTE_BABEL, 2, "babel"},
++ {ZEBRA_ROUTE_HSLS, 1, "hsls"},
++ {ZEBRA_ROUTE_OLSR, 2, "olsr"},
++ {ZEBRA_ROUTE_BATMAN, 3, "batman"},
++ {ZEBRA_ROUTE_BABEL, 3, "babel"},
+ {0, 0, NULL}
+ };
+
+--- a/ripngd/ripng_zebra.c
++++ b/ripngd/ripng_zebra.c
+@@ -216,9 +216,12 @@ static struct {
+ {ZEBRA_ROUTE_KERNEL, 1, "kernel"},
+ {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+ {ZEBRA_ROUTE_STATIC, 1, "static"},
+- {ZEBRA_ROUTE_OSPF6, 1, "ospf6"},
++ {ZEBRA_ROUTE_OSPF6, 2, "ospf6"},
+ {ZEBRA_ROUTE_BGP, 2, "bgp"},
+- {ZEBRA_ROUTE_BABEL, 2, "babel"},
++ {ZEBRA_ROUTE_HSLS, 1, "hsls"},
++ {ZEBRA_ROUTE_OLSR, 2, "olsr"},
++ {ZEBRA_ROUTE_BATMAN, 3, "batman"},
++ {ZEBRA_ROUTE_BABEL, 3, "babel"},
+ {0, 0, NULL}
+ };
+
+--- a/zebra/rt_netlink.c
++++ b/zebra/rt_netlink.c
+@@ -1623,6 +1623,9 @@ netlink_route_multipath (int cmd, struct
+ addattr_l (&req.n, sizeof req, RTA_PREFSRC,
+ &nexthop->src.ipv4, bytelen);
+
++ if (rib->type == ZEBRA_ROUTE_OLSR)
++ req.r.rtm_scope = RT_SCOPE_LINK;
++
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("netlink_route_multipath() (single hop): "
+ "nexthop via if %u", nexthop->ifindex);
+--- a/zebra/zebra_rib.c
++++ b/zebra/zebra_rib.c
+@@ -67,6 +67,9 @@ static const struct
+ [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110},
+ [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115},
+ [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */},
++ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 0},
++ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 0},
++ [ZEBRA_ROUTE_BATMAN] = {ZEBRA_ROUTE_BATMAN, 0},
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95},
+ /* no entry/default: 150 */
+ };
+@@ -403,6 +406,18 @@ nexthop_active_ipv4 (struct rib *rib, st
+ }
+ return 0;
+ }
++ else if (match->type == ZEBRA_ROUTE_OLSR)
++ {
++ for (newhop = match->nexthop; newhop; newhop = newhop->next)
++ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
++ && newhop->type == NEXTHOP_TYPE_IFINDEX)
++ {
++ if (nexthop->type == NEXTHOP_TYPE_IPV4)
++ nexthop->ifindex = newhop->ifindex;
++ return 1;
++ }
++ return 0;
++ }
+ else
+ {
+ return 0;
+@@ -507,6 +522,18 @@ nexthop_active_ipv6 (struct rib *rib, st
+ }
+ return 0;
+ }
++ else if (match->type == ZEBRA_ROUTE_OLSR)
++ {
++ for (newhop = match->nexthop; newhop; newhop = newhop->next)
++ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
++ && newhop->type == NEXTHOP_TYPE_IFINDEX)
++ {
++ if (nexthop->type == NEXTHOP_TYPE_IPV6)
++ nexthop->ifindex = newhop->ifindex;
++ return 1;
++ }
++ return 0;
++ }
+ else
+ {
+ return 0;
+@@ -1236,6 +1263,8 @@ static const u_char meta_queue_map[ZEBRA
+ [ZEBRA_ROUTE_ISIS] = 2,
+ [ZEBRA_ROUTE_BGP] = 3,
+ [ZEBRA_ROUTE_HSLS] = 4,
++ [ZEBRA_ROUTE_OLSR] = 4,
++ [ZEBRA_ROUTE_BATMAN] = 4,
+ [ZEBRA_ROUTE_BABEL] = 2,
+ };
+
+--- a/zebra/zebra_snmp.c
++++ b/zebra/zebra_snmp.c
+@@ -251,6 +251,12 @@ proto_trans(int type)
+ return 1; /* shouldn't happen */
+ case ZEBRA_ROUTE_BGP:
+ return 14; /* bgp */
++ case ZEBRA_ROUTE_HSLS:
++ return 1; /* other */
++ case ZEBRA_ROUTE_OLSR:
++ return 1; /* other */
++ case ZEBRA_ROUTE_BATMAN:
++ return 1; /* other */
+ default:
+ return 1; /* other */
+ }
+--- a/zebra/zebra_vty.c
++++ b/zebra/zebra_vty.c
+@@ -558,7 +558,10 @@ vty_show_ip_route_detail (struct vty *vt
+ || rib->type == ZEBRA_ROUTE_OSPF
+ || rib->type == ZEBRA_ROUTE_BABEL
+ || rib->type == ZEBRA_ROUTE_ISIS
+- || rib->type == ZEBRA_ROUTE_BGP)
++ || rib->type == ZEBRA_ROUTE_BGP
++ || rib->type == ZEBRA_ROUTE_HSLS
++ || rib->type == ZEBRA_ROUTE_OLSR
++ || rib->type == ZEBRA_ROUTE_BATMAN)
+ {
+ time_t uptime;
+ struct tm *tm;
+@@ -777,7 +780,10 @@ vty_show_ip_route (struct vty *vty, stru
+ || rib->type == ZEBRA_ROUTE_OSPF
+ || rib->type == ZEBRA_ROUTE_BABEL
+ || rib->type == ZEBRA_ROUTE_ISIS
+- || rib->type == ZEBRA_ROUTE_BGP)
++ || rib->type == ZEBRA_ROUTE_BGP
++ || rib->type == ZEBRA_ROUTE_HSLS
++ || rib->type == ZEBRA_ROUTE_OLSR
++ || rib->type == ZEBRA_ROUTE_BATMAN)
+ {
+ time_t uptime;
+ struct tm *tm;
+@@ -1536,7 +1542,10 @@ vty_show_ipv6_route_detail (struct vty *
+ || rib->type == ZEBRA_ROUTE_OSPF6
+ || rib->type == ZEBRA_ROUTE_BABEL
+ || rib->type == ZEBRA_ROUTE_ISIS
+- || rib->type == ZEBRA_ROUTE_BGP)
++ || rib->type == ZEBRA_ROUTE_BGP
++ || rib->type == ZEBRA_ROUTE_HSLS
++ || rib->type == ZEBRA_ROUTE_OLSR
++ || rib->type == ZEBRA_ROUTE_BATMAN)
+ {
+ time_t uptime;
+ struct tm *tm;
+@@ -1716,7 +1725,10 @@ vty_show_ipv6_route (struct vty *vty, st
+ || rib->type == ZEBRA_ROUTE_OSPF6
+ || rib->type == ZEBRA_ROUTE_BABEL
+ || rib->type == ZEBRA_ROUTE_ISIS
+- || rib->type == ZEBRA_ROUTE_BGP)
++ || rib->type == ZEBRA_ROUTE_BGP
++ || rib->type == ZEBRA_ROUTE_HSLS
++ || rib->type == ZEBRA_ROUTE_OLSR
++ || rib->type == ZEBRA_ROUTE_BATMAN)
+ {
+ time_t uptime;
+ struct tm *tm;
diff --git a/packages/qmp-quagga/patches/121-quagga-bmx6.patch b/packages/qmp-quagga/patches/121-quagga-bmx6.patch
new file mode 100644
index 0000000..ec81afb
--- /dev/null
+++ b/packages/qmp-quagga/patches/121-quagga-bmx6.patch
@@ -0,0 +1,127 @@
+--- a/lib/log.c
++++ b/lib/log.c
+@@ -941,6 +941,8 @@ proto_redistnum(int afi, const char *s)
+ return ZEBRA_ROUTE_OLSR;
+ else if (strncmp (s, "bat", 3) == 0)
+ return ZEBRA_ROUTE_BATMAN;
++ else if (strncmp (s, "bmx", 3) == 0)
++ return ZEBRA_ROUTE_BMX6;
+ else if (strncmp (s, "bab", 3) == 0)
+ return ZEBRA_ROUTE_BABEL;
+ }
+@@ -966,6 +968,8 @@ proto_redistnum(int afi, const char *s)
+ return ZEBRA_ROUTE_OLSR;
+ else if (strncmp (s, "bat", 3) == 0)
+ return ZEBRA_ROUTE_BATMAN;
++ else if (strncmp (s, "bmx", 3) == 0)
++ return ZEBRA_ROUTE_BMX6;
+ else if (strncmp (s, "bab", 3) == 0)
+ return ZEBRA_ROUTE_BABEL;
+ }
+--- a/lib/route_types.txt
++++ b/lib/route_types.txt
+@@ -54,6 +54,7 @@ ZEBRA_ROUTE_BGP, bgp, bgpd,
+ ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 1, 1, "HSLS"
+ ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 1, 1, "OLSR"
+ ZEBRA_ROUTE_BATMAN, batman, batmand,'b', 1, 1, "BATMAN"
++ZEBRA_ROUTE_BMX6, bmx6, bmx6, 'x', 1, 1, "BMX6"
+ ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
+
+ ## help strings
+@@ -70,4 +71,5 @@ ZEBRA_ROUTE_BGP, "Border Gateway Prot
+ ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
+ ZEBRA_ROUTE_OLSR, "Optimized Link State Routing (OLSR)"
+ ZEBRA_ROUTE_BATMAN, "Better Approach to Mobile Ad-Hoc Networking (BATMAN)"
++ZEBRA_ROUTE_BMX6, "BMX6 networking protocol"
+ ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
+--- a/ripd/rip_zebra.c
++++ b/ripd/rip_zebra.c
+@@ -211,6 +211,7 @@ static struct {
+ {ZEBRA_ROUTE_HSLS, 1, "hsls"},
+ {ZEBRA_ROUTE_OLSR, 2, "olsr"},
+ {ZEBRA_ROUTE_BATMAN, 3, "batman"},
++ {ZEBRA_ROUTE_BMX6, 3, "bmx6"},
+ {ZEBRA_ROUTE_BABEL, 3, "babel"},
+ {0, 0, NULL}
+ };
+--- a/ripngd/ripng_zebra.c
++++ b/ripngd/ripng_zebra.c
+@@ -221,6 +221,7 @@ static struct {
+ {ZEBRA_ROUTE_HSLS, 1, "hsls"},
+ {ZEBRA_ROUTE_OLSR, 2, "olsr"},
+ {ZEBRA_ROUTE_BATMAN, 3, "batman"},
++ {ZEBRA_ROUTE_BMX6, 3, "bmx6"},
+ {ZEBRA_ROUTE_BABEL, 3, "babel"},
+ {0, 0, NULL}
+ };
+--- a/zebra/zebra_rib.c
++++ b/zebra/zebra_rib.c
+@@ -70,6 +70,7 @@ static const struct
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 0},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 0},
+ [ZEBRA_ROUTE_BATMAN] = {ZEBRA_ROUTE_BATMAN, 0},
++ [ZEBRA_ROUTE_BMX6] = {ZEBRA_ROUTE_BMX6, 0},
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95},
+ /* no entry/default: 150 */
+ };
+@@ -1265,6 +1266,7 @@ static const u_char meta_queue_map[ZEBRA
+ [ZEBRA_ROUTE_HSLS] = 4,
+ [ZEBRA_ROUTE_OLSR] = 4,
+ [ZEBRA_ROUTE_BATMAN] = 4,
++ [ZEBRA_ROUTE_BMX6] = 4,
+ [ZEBRA_ROUTE_BABEL] = 2,
+ };
+
+--- a/zebra/zebra_snmp.c
++++ b/zebra/zebra_snmp.c
+@@ -257,6 +257,8 @@ proto_trans(int type)
+ return 1; /* other */
+ case ZEBRA_ROUTE_BATMAN:
+ return 1; /* other */
++ case ZEBRA_ROUTE_BMX6:
++ return 1; /* other */
+ default:
+ return 1; /* other */
+ }
+--- a/zebra/zebra_vty.c
++++ b/zebra/zebra_vty.c
+@@ -561,7 +561,8 @@ vty_show_ip_route_detail (struct vty *vt
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+- || rib->type == ZEBRA_ROUTE_BATMAN)
++ || rib->type == ZEBRA_ROUTE_BATMAN
++ || rib->type == ZEBRA_ROUTE_BMX6)
+ {
+ time_t uptime;
+ struct tm *tm;
+@@ -783,7 +784,8 @@ vty_show_ip_route (struct vty *vty, stru
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+- || rib->type == ZEBRA_ROUTE_BATMAN)
++ || rib->type == ZEBRA_ROUTE_BATMAN
++ || rib->type == ZEBRA_ROUTE_BMX6)
+ {
+ time_t uptime;
+ struct tm *tm;
+@@ -1545,7 +1547,8 @@ vty_show_ipv6_route_detail (struct vty *
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+- || rib->type == ZEBRA_ROUTE_BATMAN)
++ || rib->type == ZEBRA_ROUTE_BATMAN
++ || rib->type == ZEBRA_ROUTE_BMX6)
+ {
+ time_t uptime;
+ struct tm *tm;
+@@ -1728,7 +1731,8 @@ vty_show_ipv6_route (struct vty *vty, st
+ || rib->type == ZEBRA_ROUTE_BGP
+ || rib->type == ZEBRA_ROUTE_HSLS
+ || rib->type == ZEBRA_ROUTE_OLSR
+- || rib->type == ZEBRA_ROUTE_BATMAN)
++ || rib->type == ZEBRA_ROUTE_BATMAN
++ || rib->type == ZEBRA_ROUTE_BMX6)
+ {
+ time_t uptime;
+ struct tm *tm;
diff --git a/packages/qmp-quagga/patches/130-fix_cpp.patch b/packages/qmp-quagga/patches/130-fix_cpp.patch
new file mode 100644
index 0000000..23991c3
--- /dev/null
+++ b/packages/qmp-quagga/patches/130-fix_cpp.patch
@@ -0,0 +1,11 @@
+--- a/vtysh/extract.pl.in
++++ b/vtysh/extract.pl.in
+@@ -63,7 +63,7 @@ $ignore{'"show history"'} = "ignore";
+ foreach (@ARGV) {
+ $file = $_;
+
+- open (FH, "cpp -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |");
++ open (FH, "@CPP@ -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -DHAVE_IPV6 -I@top_builddir@ -I@srcdir@/ -I@srcdir@/.. -I@top_srcdir@/lib -I@top_srcdir@/isisd/topology @SNMP_INCLUDES@ @CPPFLAGS@ $file |");
+ local $/; undef $/;
+ $line = ;
+ close (FH);
diff --git a/packages/qmp-quagga/patches/140-holdtimer-set.patch b/packages/qmp-quagga/patches/140-holdtimer-set.patch
new file mode 100644
index 0000000..6f0d79a
--- /dev/null
+++ b/packages/qmp-quagga/patches/140-holdtimer-set.patch
@@ -0,0 +1,22 @@
+--- a/bgpd/bgp_network.c
++++ b/bgpd/bgp_network.c
+@@ -193,8 +193,7 @@ bgp_accept (struct thread *thread)
+ peer->fd = bgp_sock;
+ peer->status = Active;
+ peer->local_id = peer1->local_id;
+- peer->v_holdtime = peer1->v_holdtime;
+- peer->v_keepalive = peer1->v_keepalive;
++ peer->v_holdtime = BGP_LARGE_HOLDTIME;
+
+ /* Make peer's address string. */
+ sockunion2str (&su, buf, SU_ADDRSTRLEN);
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -718,6 +718,7 @@ struct bgp_nlri
+ /* BGP timers default value. */
+ #define BGP_INIT_START_TIMER 5
+ #define BGP_ERROR_START_TIMER 30
++#define BGP_LARGE_HOLDTIME 240
+ #define BGP_DEFAULT_HOLDTIME 180
+ #define BGP_DEFAULT_KEEPALIVE 60
+ #define BGP_DEFAULT_ASORIGINATE 15
diff --git a/packages/qmp-quagga/patches/150-no-cross-fs-link.patch b/packages/qmp-quagga/patches/150-no-cross-fs-link.patch
new file mode 100644
index 0000000..c3f29c3
--- /dev/null
+++ b/packages/qmp-quagga/patches/150-no-cross-fs-link.patch
@@ -0,0 +1,40 @@
+--- a/lib/command.c
++++ b/lib/command.c
+@@ -2601,6 +2601,13 @@ DEFUN (config_write_file,
+ VTY_NEWLINE);
+ goto finished;
+ }
++
++#if 0
++ /* This code fails on UNION MOUNTs and similar filesystems if the
++ * config file is still on the RO layer. Hardlinks across layers
++ * will not work and cause quagga to fail saving the configuration...
++ * should use rename() to move files around...
++ */
+ if (link (config_file, config_file_sav) != 0)
+ {
+ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+@@ -2614,7 +2621,23 @@ DEFUN (config_write_file,
+ VTY_NEWLINE);
+ goto finished;
+ }
++#else
++ /* And this is the code that hopefully does work */
++ if (rename (config_file, config_file_sav) != 0)
++ {
++ vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
++ VTY_NEWLINE);
++ goto finished;
++ }
++ sync ();
++#endif
++
++#if 0
++ /* same here. Please no cross-filesystem hardlinks... */
+ if (link (config_file_tmp, config_file) != 0)
++#else
++ if (rename (config_file_tmp, config_file) != 0)
++#endif
+ {
+ vty_out (vty, "Can't save configuration file %s.%s", config_file,
+ VTY_NEWLINE);
diff --git a/packages/qmp-quagga/patches/160-pgbgp.patch b/packages/qmp-quagga/patches/160-pgbgp.patch
new file mode 100644
index 0000000..fb01ee1
--- /dev/null
+++ b/packages/qmp-quagga/patches/160-pgbgp.patch
@@ -0,0 +1,3104 @@
+From: Josh Karlin
+Date: Mon, 18 Aug 2008 13:17:21 +0000 (+0100)
+Subject: [bgp] Add support for Pretty-Good BGP
+X-Git-Url: http://git.ozo.com/?p=quagga-pgbg.git;a=commitdiff_plain;h=c2ee55705cad607f4b86ff143f7af92d538dc946
+
+[bgp] Add support for Pretty-Good BGP
+
+2008-7-7 Josh Karlin
+
+ * bgpd/bgp_pgbgp.c: Added file
+ * bgpd/bgp_pgbgp.h: Added file
+ * bgpd/Makefile.am: Added bgp_pgbgp.h and bgp_pgbgp.c
+ * bgpd/bgp_aspath.h: Externed the hash of as paths (ashash)
+ * bgpd/bgp_route.c: . Added PGBGP depref check to decision process.
+ . Informs PGBGP of new updates and selected routes
+ . Added anomaly status for show ip bgp
+ . Added PGBGP commands
+ * bgpd/bgp_route.h: Added suspicious route flags
+ * bgpd/bgp_table.h: Added PGBGP history pointer to struct bgp_node
+ * bgpd/bgpd.h: Defined BGP_CONFIG_PGBGP
+ * lib/hash.c: Added "hash_iterate_until" to be able to break out
+ * lib/hash.h: Definition for "hash_iterate_until"
+ * lib/memtypes.c: Added PGBGP memory types
+---
+
+--- a/bgpd/Makefile.am
++++ b/bgpd/Makefile.am
+@@ -15,14 +15,14 @@ libbgp_a_SOURCES = \
+ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
+ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
+ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
+- bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c
++ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c bgp_pgbgp.c
+
+ noinst_HEADERS = \
+ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
+ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
+ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
+ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
+- bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h
++ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_pgbgp.h
+
+ bgpd_SOURCES = bgp_main.c
+ bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
+--- /dev/null
++++ b/bgpd/bgp_pgbgp.c
+@@ -0,0 +1,2401 @@
++/*
++ BGP Pretty Good BGP
++ Copyright (C) 2008 University of New Mexico (Josh Karlin)
++
++This file is part of GNU Zebra.
++
++GNU Zebra is free software; you can redistribute it and/or modify it
++under the terms of the GNU General Public License as published by the
++Free Software Foundation; either version 2, or (at your option) any
++later version.
++
++GNU Zebra is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with GNU Zebra; see the file COPYING. If not, write to the Free
++Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++02111-1307, USA.
++*/
++
++/*
++ Quagga based Pretty Good BGP:
++
++ Summary
++ -------
++ Pretty Good BGP (PGBGP) is a soft security enhancement to BGP.
++ It uses independently collected (therefore completely distributed)
++ historical routing information to determine network topology and
++ prefix ownership. Abberations to the historical database are considered
++ anomalous and avoided when possible.
++
++ What PGBGP can protect against: prefix hijacks, sub-prefix hijacks, and
++ spoofed edges.
++
++ Further reading is available at http://cs.unm.edu/~karlinjf/pgbgp/
++
++ Route updates are forwarded to PGBGP, which determines if the route
++ is anomalous. Anomalous routes are flagged as suspicious and
++ avoided where feasible for 24 hours. If the anomalous
++ characteristic is still in the RIB after 24 hours, consider it valid
++ and enter it into the normal database.
++
++ Cases for anomalous routes
++ --------------------------
++ case 1) New origin AS - prefix pair (one not recently seen in the RIB):
++ response) label the route with BGP_INFO_SUSPICIOUS_O and avoid for 24 hours if possible
++
++ case 2) New edge in path (one not recently seen in the RIB):
++ response) label the route with BGP_INFO_SUSPICIOUS_E and avoid for 24 hours
++ if possible
++
++ case 3) New prefix that is a sub-prefix of a prefix in recent history
++ and that path differs from the current less-specific's path
++ response) label the sub-prefix routes with BGP_INFO_IGNORED_P and
++ prevent it from entering FIB for 24 hours
++ response) label the super-net routes from the same next-hop as BGP_INFO_SUSPICIOUS_P
++ and try to avoid it for 24 hours if possible
++ response) while no super-net route is selected, remove the BGP_INFO_IGNORED_P flags
++
++
++ Normal Database (history)
++ -------------------------
++ Recently Seen) A route characteristic (edge, prefix/origin pair, prefix)
++ that has resided within the RIB within the last X hours
++ where X is user defined for each characteristic.
++ Storage) Prefix and Origin history are stored in bgp_node structs with the
++ "hist" pointer.
++ Edge information is stored in a separate hash table, where the edge
++ is the key to the hash.
++ Updates) The history's primary function is the keep track of when each route
++ characteristic was last seen. For each route announcement, update
++ the history's 'last seen' time. Periodically run the garbage collector
++ which updates 'last seen' times for objects currently in the RIB.
++
++ Garbage Collection
++ ------------------
++ Periodically the garbage collector (gc) is called to remove stale history
++ information and update the lastSeen time of objects that reside in the RIB
++ at the time of collection. This is relatively expensive as it walks
++ the RIB as well as the list of AS paths.
++
++ What is removed) Objects that have not been seen in the RIB within a user-defined
++ time.
++ Suspicious objcets that are 24 hours old that have not been in the RIB
++ since the last collection.
++
++ Reuse Priority Queue
++ --------------------
++ After 24 hours, routes that are flagged as suspicious have the flags removed.
++ This is not run on a timer. Instead, for each update that PGBGP is informed of,
++ it checks the reuse queue to determine if any routes need to be updated.
++
++*/
++
++
++/*
++ Things that must be ensured:
++ . GC updates lastSeen so it must be called at least twice as often as the lowest BUFFER_TIME
++ . GC should be called at least twice per day
++ . Delay times must be shorter than history window lengths
++*/
++
++
++/*
++ Changes made to original PGBGP thinking
++ . Don't check for things in the RIB all of the time, periodically
++ update the lastSeen values and just use lastSeen
++*/
++
++/*
++ Changes made to original protocol
++ . sub-prefixes are only ignored while the super-net has a selected
++ route and it's non-anomalous (not to a neighbor that announced
++ the sub-prefix)
++
++ . At point of reuse, don't delete the item if it's not in the RIB.
++ delete it if it hasn't been in the RIB since the last storage.
++ This saves a lot of processing time for new edges
++
++ . Changed heuristic from "if new sub-prefix and trusted AS on path
++ then it's okay" to "if new sub-prefix and same path is used to reach
++ super-prefix, then it's okay". Might be better to change to "if old
++ path is prefix of new path, then okay"
++*/
++
++#include
++#include
++
++#include "prefix.h"
++#include "memory.h"
++#include "command.h"
++#include "log.h"
++#include "pqueue.h"
++#include "table.h"
++#include "hash.h"
++#include "str.h"
++
++#include "bgpd/bgpd.h"
++#include "bgpd/bgp_aspath.h"
++#include "bgpd/bgp_pgbgp.h"
++#include "bgpd/bgp_table.h"
++#include "bgpd/bgp_route.h"
++#include "bgpd/bgp_attr.h"
++#include "bgpd/bgp_advertise.h"
++
++
++#define true 1
++#define false 0
++
++struct hash * ashash;
++
++static void *edge_hash_alloc (void *arg);
++static unsigned int edge_key_make (void *p);
++static int edge_cmp (const void *arg1, const void *args);
++
++// Helper Functions
++static struct bgp_pgbgp_pathSet bgp_pgbgp_pathOrigin (struct aspath *);
++static int bgp_pgbgp_pathLength (struct aspath *asp);
++static int bgp_pgbgp_gc (struct bgp_table *);
++static int bgp_pgbgp_clean (struct bgp_table *);
++static int bgp_pgbgp_reuse (time_t);
++static struct bgp_node *findSuper (struct bgp_table *table, struct prefix *p,
++ time_t t_now);
++static int bgp_pgbgp_store (struct bgp_table *table);
++static int bgp_pgbgp_restore (void);
++static struct bgp_info *bgp_pgbgp_selected (struct bgp_node *node);
++static int originInRIB (struct bgp_node *node, struct bgp_pgbgp_origin *origin);
++static int prefixInRIB (struct bgp_node *node, struct bgp_pgbgp_prefix *prefix);
++static int edgeInRIB (struct bgp_pgbgp_edge *e);
++
++// MOAS Functions
++static void bgp_pgbgp_logOriginAnomaly (as_t asn, struct bgp_node *rn,
++ struct attr *);
++static int bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_r_origin);
++static void bgp_pgbgp_cleanHistTable (struct bgp_table *);
++static int bgp_pgbgp_garbageCollectHistTable (struct bgp_table *);
++static void bgp_pgbgp_storeHistTable (struct bgp_table *table, FILE * file);
++static int bgp_pgbgp_updateOrigin (struct bgp_pgbgp_hist *, struct bgp_info *,
++ struct attr *, struct bgp_node *, time_t, int);
++
++
++// Sub-Prefix Hijack Detector Functions
++static int bgp_pgbgp_shouldIgnore (struct bgp_node *super, struct bgp_info *selected);
++static void bgp_pgbgp_logSubprefixAnomaly (as_t asn, struct bgp_node *rn,
++ struct attr *, struct bgp_node *super);
++static int bgp_pgbgp_reusePrefix (struct bgp_pgbgp_r_prefix);
++static int bgp_pgbgp_updatePrefix (struct bgp_pgbgp_hist *hist, struct bgp_node *,
++ struct bgp_info *, struct attr *,
++ struct bgp_node *, time_t, int);
++
++
++// Spoofed Edge Detector Functions
++static void bgp_pgbgp_cleanEdges (void);
++static void bgp_pgbgp_logEdgeAnomaly (struct bgp_node *rn, struct attr *,
++ struct edge *edge);
++static int bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_edge);
++static void bgp_pgbgp_storeEdges (struct bgp_table *, FILE *);
++static int bgp_pgbgp_garbageCollectEdges (struct bgp_table *);
++static int bgp_pgbgp_updateEdge (struct bgp_pgbgp_hist *hist, struct bgp_info *,
++ struct attr *, struct bgp_node *, time_t, int);
++static int bgp_pgbgp_restoreEdge (FILE * file);
++static void bgp_pgbgp_storeEdges (struct bgp_table *table, FILE * file);
++
++
++
++// New Peer Detector Functions
++static int bgp_pgbgp_updatePeer (struct bgp_info *binfo, time_t now);
++
++
++/* --------------- Global Variables ------------------ */
++struct bgp_pgbgp_config bgp_pgbgp_cfg;
++struct bgp_pgbgp_config *pgbgp = &bgp_pgbgp_cfg;
++/*! --------------- Global Variables ------------------ !*/
++
++/* --------------- VTY (others exist in bgp_route.c) ------------------ */
++
++struct nsearch
++{
++ struct vty *pvty;
++ time_t time;
++ as_t asn;
++};
++
++static void
++edge_neighbor_iterator (struct hash_backet *backet, struct nsearch *pns)
++{
++ struct bgp_pgbgp_edge *hedge = backet->data;
++ if ((hedge->e.a == pns->asn || hedge->e.b == pns->asn)
++ && hedge->e.a != hedge->e.b)
++ {
++ struct vty *vty = pns->pvty;
++ if (hedge->deprefUntil > pns->time)
++ vty_out (pns->pvty, "Untrusted: %d -- %d%s", hedge->e.a, hedge->e.b,
++ VTY_NEWLINE);
++ else
++ vty_out (pns->pvty, "Trusted: %d -- %d%s", hedge->e.a, hedge->e.b,
++ VTY_NEWLINE);
++ }
++}
++
++static int
++bgp_pgbgp_stats_neighbors (struct vty *vty, afi_t afi, safi_t safi, as_t asn)
++{
++ struct nsearch ns;
++ ns.pvty = vty;
++ ns.time = time (NULL);
++ ns.asn = asn;
++
++ hash_iterate (pgbgp->edgeT,
++ (void (*)(struct hash_backet *, void *))
++ edge_neighbor_iterator, &ns);
++ return CMD_SUCCESS;
++}
++
++static int
++bgp_pgbgp_stats_origins (struct vty *vty, afi_t afi, safi_t safi,
++ const char *prefix)
++{
++ struct bgp *bgp;
++ struct bgp_table *table;
++ time_t t_now = time (NULL);
++ bgp = bgp_get_default ();
++ if (bgp == NULL)
++ return CMD_WARNING;
++ if (bgp->rib == NULL)
++ return CMD_WARNING;
++ table = bgp->rib[afi][safi];
++ if (table == NULL)
++ return CMD_WARNING;
++
++ struct prefix p;
++ str2prefix (prefix, &p);
++ struct bgp_node *rn = bgp_node_match (table, &p);
++ vty_out (vty, "%s%s", prefix, VTY_NEWLINE);
++ if (rn)
++ {
++ if (rn->hist)
++ {
++ for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL;
++ cur = cur->next)
++ {
++ if (cur->deprefUntil > t_now)
++ vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS,
++ VTY_NEWLINE);
++ else
++ vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS,
++ VTY_NEWLINE);
++ }
++ }
++ bgp_unlock_node (rn);
++ }
++ return CMD_SUCCESS;
++}
++
++static int
++bgp_pgbgp_stats (struct vty *vty, afi_t afi, safi_t safi)
++{
++ struct bgp *bgp;
++ struct bgp_table *table;
++
++
++ bgp = bgp_get_default ();
++ if (bgp == NULL)
++ return CMD_WARNING;
++ if (bgp->rib == NULL)
++ return CMD_WARNING;
++ table = bgp->rib[afi][safi];
++ if (table == NULL)
++ return CMD_WARNING;
++
++ // bgp_pgbgp_store(table);
++
++ // Print out the number of anomalous routes
++ int anomalous = 0;
++ int routes = 0;
++ int num_selected = 0;
++ int num_origin = 0;
++ int num_super = 0;
++ int num_ignored = 0;
++ int num_edge = 0;
++
++ for (struct bgp_node * rn = bgp_table_top (table); rn;
++ rn = bgp_route_next (rn))
++ {
++ for (struct bgp_info * ri = rn->info; ri; ri = ri->next)
++ {
++ routes += 1;
++ if (ANOMALOUS (ri->flags))
++ {
++ anomalous += 1;
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
++ num_selected += 1;
++
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O))
++ num_origin += 1;
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E))
++ num_edge += 1;
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P))
++ num_super += 1;
++ if (CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P))
++ num_ignored += 1;
++ }
++ }
++ }
++
++ vty_out (vty, "%-30s: %10d%s", "Routes in the RIB", routes, VTY_NEWLINE);
++ vty_out (vty, "%-30s: %10d%s", "Anomalous routes in RIB", anomalous,
++ VTY_NEWLINE);
++ vty_out (vty, "%-30s: %10d%s", "Selected anomalous routes", num_selected,
++ VTY_NEWLINE);
++ vty_out (vty, "-----------------------------%s", VTY_NEWLINE);
++ vty_out (vty, "%-30s: %10d%s", "Routes with anomalous origins", num_origin,
++ VTY_NEWLINE);
++ vty_out (vty, "%-30s: %10d%s", "Routes with anomalous edges", num_edge,
++ VTY_NEWLINE);
++ vty_out (vty, "%-30s: %10d%s", "Routes ignored for sub-prefix", num_ignored,
++ VTY_NEWLINE);
++ vty_out (vty, "%-30s: %10d%s", "Less specific routes to avoid", num_super,
++ VTY_NEWLINE);
++ /*
++ vty_out (vty, "There are %d routes in the RIB.%s", routes, VTY_NEWLINE);
++ vty_out (vty, "%d are anomalous.%s", anomalous, VTY_NEWLINE);
++ vty_out (vty, "%d anomalous routes are selected.%s", num_selected, VTY_NEWLINE);
++ vty_out (vty, "%s", VTY_NEWLINE);
++ vty_out (vty, "Anomaly breakdown:%s", VTY_NEWLINE);
++ vty_out (vty, "%d contain anomalous origins%s", num_origin, VTY_NEWLINE);
++ vty_out (vty, "%d contain anomalous edges.%s", num_edge, VTY_NEWLINE);
++ vty_out (vty, "%d are for ignored sub-prefixes.%s", num_ignored, VTY_NEWLINE);
++ vty_out (vty, "%d are super-net routes through peers that announced anomalous sub-prefixes.%s", num_super, VTY_NEWLINE);
++ */
++ return CMD_SUCCESS;
++}
++
++
++DEFUN (show_ip_bgp_pgbgp,
++ show_ip_bgp_pgbgp_cmd,
++ "show ip bgp pgbgp",
++ SHOW_STR IP_STR BGP_STR "Display PGBGP statistics\n")
++{
++ return bgp_pgbgp_stats (vty, AFI_IP, SAFI_UNICAST);
++}
++
++DEFUN (show_ip_bgp_pgbgp_neighbors,
++ show_ip_bgp_pgbgp_neighbors_cmd,
++ "show ip bgp pgbgp neighbors WORD",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "BGP pgbgp\n"
++ "BGP pgbgp neighbors\n" "ASN whos neighbors should be displayed\n")
++{
++ return bgp_pgbgp_stats_neighbors (vty, AFI_IP, SAFI_UNICAST,
++ atoi (argv[0]));
++}
++
++DEFUN (show_ip_bgp_pgbgp_origins,
++ show_ip_bgp_pgbgp_origins_cmd,
++ "show ip bgp pgbgp origins A.B.C.D/M",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "BGP pgbgp\n"
++ "BGP pgbgp neighbors\n" "Prefix to look up origin ASes of\n")
++{
++ return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST, argv[0]);
++}
++
++
++
++
++/*! --------------- VTY (others exist in bgp_route.c) ------------------ !*/
++
++
++
++
++
++
++
++/* --------------- Helper Functions ------------------ */
++/*
++ If the origin hasn't been seen/verified lately, look for it in the RIB
++*/
++int
++originInRIB (struct bgp_node *node, struct bgp_pgbgp_origin *origin)
++{
++ for (struct bgp_info * ri = node->info; ri; ri = ri->next)
++ {
++ struct bgp_pgbgp_pathSet pathOrigins;
++ pathOrigins = bgp_pgbgp_pathOrigin (ri->attr->aspath);
++ for (int i = 0; i < pathOrigins.length; ++i)
++ {
++ if (pathOrigins.ases[i] == origin->originAS)
++ {
++ return true;
++ }
++ }
++ }
++ return false;
++}
++
++
++/*
++ If the prefix hasn't been seen/verified lately, look for it in the RIB
++*/
++int
++prefixInRIB (struct bgp_node *node, struct bgp_pgbgp_prefix *prefix)
++{
++ if (node->info)
++ return true;
++ return false;
++}
++
++static int
++edge_inRIB_iterator (struct hash_backet *backet, struct bgp_pgbgp_edge *hedge)
++{
++ struct aspath *p = backet->data;
++ char first = true;
++ struct edge curEdge;
++ curEdge.a = 0;
++ curEdge.b = 0;
++
++ struct assegment *seg;
++
++ for (seg = p->segments; seg; seg = seg->next)
++ {
++ for (int i = 0; i < seg->length; i++)
++ {
++ curEdge.a = curEdge.b;
++ curEdge.b = seg->as[i];
++ if (first)
++ {
++ first = false;
++ continue;
++ }
++ // Is this the edge we're looking for?
++ if (curEdge.a == hedge->e.a && curEdge.b == hedge->e.b)
++ {
++ hedge->lastSeen = time (NULL);
++ return false;
++ }
++ }
++ }
++
++ return true;
++}
++
++/*
++ If the edge hasn't been seen/verified lately, look for it in the AS path list
++ This function is expensive, use sparingly
++*/
++int
++edgeInRIB (struct bgp_pgbgp_edge *e)
++{
++ int completed;
++ completed = hash_iterate_until (ashash,
++ (int (*)(struct hash_backet *, void *))
++ edge_inRIB_iterator, e);
++ if (completed)
++ return false;
++
++ return true;
++}
++
++
++
++/*
++ Return the selected route for the given route node
++ */
++
++struct bgp_info *
++bgp_pgbgp_selected (struct bgp_node *node)
++{
++ for (struct bgp_info * ri = node->info; ri; ri = ri->next)
++ {
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
++ return ri;
++ }
++ return NULL;
++}
++
++static int
++reuse_cmp (void *node1, void *node2)
++{
++ struct bgp_pgbgp_reuse *a;
++ struct bgp_pgbgp_reuse *b;
++ a = (struct bgp_pgbgp_reuse *) node1;
++ b = (struct bgp_pgbgp_reuse *) node2;
++ return a->deprefUntil - b->deprefUntil;
++}
++
++int
++bgp_pgbgp_pathLength (struct aspath *asp)
++{
++ struct assegment *seg;
++ if ((asp == NULL) || (asp->segments == NULL))
++ return 0;
++ int count = 0;
++ seg = asp->segments;
++ while (seg->next != NULL)
++ {
++ count += seg->length;
++ seg = seg->next;
++ }
++ return count;
++}
++
++
++
++/* Find the origin(s) of the path
++ All ASes in the final set are considered origins */
++static struct bgp_pgbgp_pathSet
++bgp_pgbgp_pathOrigin (struct aspath *asp)
++{
++ struct assegment *seg, *last;
++ struct bgp_pgbgp_pathSet tmp;
++ tmp.length = 0;
++ tmp.ases = NULL;
++
++ assert (asp != NULL && asp->segments != NULL);
++
++ /* if ( (asp == NULL) || (asp->segments == NULL) )
++ return tmp;
++ */
++ seg = asp->segments;
++ last = NULL;
++ while (seg->next != NULL)
++ {
++ if (seg->type != AS_SET && seg->type != AS_CONFED_SET)
++ last = seg;
++ seg = seg->next;
++ }
++
++ if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
++ seg = last;
++
++ assert (seg);
++ tmp.length = 1;
++ tmp.ases = &seg->as[seg->length - 1];
++
++ /*
++ if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
++ {
++ tmp.length = seg->length;
++ tmp.ases = seg->as;
++ }
++ else
++ {
++ tmp.length = 1;
++ tmp.ases = &seg->as[seg->length - 1];
++ }
++ */
++ assert (tmp.length >= 1);
++ return tmp;
++ // return seg->as[seg->length-1];
++}
++
++int
++bgp_pgbgp_reuse (time_t t_now)
++{
++
++ struct bgp_pgbgp_reuse *cur = NULL;
++
++ while (pgbgp->rq_size > 0)
++ {
++ cur = pqueue_dequeue (pgbgp->reuse_q);
++ pgbgp->rq_size -= 1;
++
++ // Is the next item ready to be reused?
++ if (t_now < cur->deprefUntil)
++ {
++ pqueue_enqueue (cur, pgbgp->reuse_q);
++ pgbgp->rq_size += 1;
++ break;
++ }
++
++ // Okay, it needs to be reused now
++ if (cur->type == PGBGP_REUSE_ORIGIN)
++ bgp_pgbgp_reuseOrigin (cur->data.origin);
++
++ else if (cur->type == PGBGP_REUSE_PREFIX)
++ bgp_pgbgp_reusePrefix (cur->data.prefix);
++
++ else if (cur->type == PGBGP_REUSE_EDGE)
++ bgp_pgbgp_reuseEdge (cur->data.edge);
++
++
++ XFREE (MTYPE_BGP_PGBGP_REUSE, cur);
++ }
++ return 0;
++}
++
++/* Check bit of the prefix. */
++static int
++check_bit (u_char * prefix, u_char prefixlen)
++{
++ int offset;
++ int shift;
++ u_char *p = (u_char *) prefix;
++
++ assert (prefixlen <= 128);
++
++ offset = prefixlen / 8;
++ shift = 7 - (prefixlen % 8);
++
++ return (p[offset] >> shift & 1);
++}
++
++/*
++ Find a super-net in the tree that's not currently anomalous if one exists
++*/
++struct bgp_node *
++findSuper (struct bgp_table *table, struct prefix *p, time_t t_now)
++{
++ struct bgp_node *node;
++ struct bgp_node *matched;
++
++ matched = NULL;
++ node = table->top;
++
++ while (node && node->p.prefixlen < p->prefixlen &&
++ prefix_match (&node->p, p))
++ {
++ // Node may not yet have its info set when reading in from pgbgp log files
++ if (node->hist && node->p.prefixlen >= 8)
++ {
++ if (node->hist->p != NULL && node->hist->p->ignoreUntil < t_now)
++ //if (node->hist->p != NULL && prefixInRIB (node, NULL))
++ //if (node->hist->p != NULL)
++ matched = node;
++ }
++ node = node->link[check_bit (&p->u.prefix, node->p.prefixlen)];
++ }
++ if (matched)
++ return bgp_lock_node (matched);
++ return NULL;
++}
++
++
++
++
++
++/*! --------------- Helper Functions ------------------ !*/
++
++
++
++
++
++
++
++/* --------------- Public PGBGP Interface ------------------ */
++int
++bgp_pgbgp_enable (struct bgp *bgp, afi_t afi, safi_t safi,
++ int ost, int est, int sst, int oht, int pht, int eht,
++ const char *file, const char *anoms)
++{
++
++ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
++ {
++ if (pgbgp->storage && pgbgp->anomalies)
++ {
++ if (pgbgp->origin_sus_time == ost
++ && pgbgp->edge_sus_time == est
++ && pgbgp->sub_sus_time == sst
++ && pgbgp->origin_hist_time == oht
++ && pgbgp->prefix_hist_time == pht
++ && pgbgp->edge_hist_time == eht
++ && strcmp (pgbgp->storage, file) == 0
++ && strcmp (pgbgp->anomalies, anoms) == 0)
++
++ return 0;
++ }
++ }
++
++ SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP);
++
++#ifndef PGBGP_DEBUG
++ time_t hour = 3600;
++ time_t day = 86400;
++#endif
++#ifdef PGBGP_DEBUG
++ time_t hour = 2;
++ time_t day = 5;
++#endif
++
++ pgbgp->origin_sus_time = ost * hour;
++ pgbgp->edge_sus_time = est * hour;
++ pgbgp->sub_sus_time = sst * hour;
++ pgbgp->origin_hist_time = oht * day;
++ pgbgp->prefix_hist_time = pht * day;
++ pgbgp->edge_hist_time = eht * day;
++ pgbgp->peer_hist_time = DEFAULT_ORIGIN_HIST;
++
++ if (file != NULL)
++ pgbgp->storage = strdup (file);
++ else
++ pgbgp->storage = NULL;
++
++ if (anoms != NULL)
++ pgbgp->anomalies = strdup (anoms);
++ else
++ pgbgp->anomalies = NULL;
++
++
++ pgbgp->reuse_q = pqueue_create ();
++ pgbgp->reuse_q->cmp = reuse_cmp;
++ pgbgp->rq_size = 0;
++ pgbgp->lastgc = time (NULL);
++ pgbgp->lastStore = time (NULL);
++ pgbgp->startTime = time (NULL);
++ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_cmd);
++ pgbgp->edgeT = hash_create_size (131072, edge_key_make, edge_cmp);
++ bgp_pgbgp_restore ();
++ return 0;
++}
++
++int
++bgp_pgbgp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
++{
++ UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP);
++
++ // Clean the tables
++ if (bgp->rib[afi][safi] != NULL)
++ bgp_pgbgp_clean (bgp->rib[afi][safi]);
++
++ bgp_pgbgp_cleanEdges ();
++
++ if (pgbgp->storage != NULL)
++ free (pgbgp->storage);
++
++ if (pgbgp->anomalies != NULL)
++ free (pgbgp->anomalies);
++
++ struct bgp_pgbgp_peerTime *pr = pgbgp->peerLast;
++ while (pr)
++ {
++ struct bgp_pgbgp_peerTime *cur = pr;
++ pr = pr->next;
++ XFREE (MTYPE_BGP_PGBGP_PEER, cur);
++ }
++
++ return 0;
++}
++
++int
++bgp_pgbgp_clean (struct bgp_table *table)
++{
++ struct bgp_pgbgp_reuse *rnode = NULL;
++
++ while (pgbgp->rq_size > 0)
++ {
++ rnode = (struct bgp_pgbgp_reuse *) pqueue_dequeue (pgbgp->reuse_q);
++ pgbgp->rq_size -= 1;
++ XFREE (MTYPE_BGP_PGBGP_REUSE, rnode);
++ }
++ pqueue_delete (pgbgp->reuse_q);
++
++ if (table == NULL)
++ return 0;
++
++ // Clean the detectors
++ bgp_pgbgp_cleanHistTable (table);
++
++ bgp_pgbgp_cleanEdges ();
++
++
++ // Clean up the RIB nodes
++ for (struct bgp_node * rn = bgp_table_top (table); rn;
++ rn = bgp_route_next (rn))
++ {
++ int changed = 0;
++ for (struct bgp_info * ri = rn->info; ri; ri = ri->next)
++ {
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O
++ | BGP_INFO_SUSPICIOUS_P | BGP_INFO_SUSPICIOUS_E
++ | BGP_INFO_IGNORED_P))
++ {
++ changed = 1;
++ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O
++ | BGP_INFO_SUSPICIOUS_P | BGP_INFO_SUSPICIOUS_E
++ | BGP_INFO_IGNORED_P);
++ }
++ }
++ if (changed && rn->info)
++ {
++ struct bgp_info *ri = rn->info;
++ bgp_process (ri->peer->bgp, rn, rn->table->afi, rn->table->safi);
++ }
++ }
++
++ hash_free (pgbgp->edgeT);
++ return 0;
++}
++
++
++int
++bgp_pgbgp_gc (struct bgp_table *table)
++{
++ struct bgp *bgp = bgp_get_default ();
++ if (!bgp)
++ return 0;
++
++ // Collect each AFI/SAFI RIB
++ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++)
++ for (safi_t safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
++ {
++ if (!CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
++ continue;
++ struct bgp_table *curTable = bgp->rib[afi][safi];
++ if (!curTable)
++ continue;
++ bgp_pgbgp_garbageCollectHistTable (curTable);
++ }
++
++ bgp_pgbgp_garbageCollectEdges (table);
++
++ return 0;
++}
++
++int
++bgp_pgbgp_restore (void)
++{
++
++ if (pgbgp->storage == NULL)
++ return 0;
++ FILE *file = fopen (pgbgp->storage, "r");
++ if (!file)
++ return 0;
++
++ int type = 0;
++ struct prefix p;
++ struct bgp *bgp = bgp_get_default ();
++ struct bgp_node *curNode = NULL;
++
++ // Get the log store time
++ long long int writetime;
++ fscanf (file, "%lld", &writetime);
++ time_t swtime = writetime;
++
++ // If it's too old (more than 1 week old), start fresh
++ if (time (NULL) - swtime > 86400 * 7)
++ {
++ fclose (file);
++ return 0;
++ }
++
++
++ // Get the PGBGP init time
++ long long int stime;
++ fscanf (file, "%lld", &stime);
++ pgbgp->startTime = stime;
++
++ while (fscanf (file, "%d", &type) != EOF)
++ {
++
++ if (type == PREFIX_ID)
++ {
++ char pre[128];
++ unsigned int afi;
++ unsigned int safi;
++ long long int time;
++ fscanf (file, "%s %u %u %lld", pre, &afi, &safi, &time);
++ str2prefix (pre, &p);
++ struct bgp_table *curTable = bgp->rib[afi][safi];
++ assert (curTable != NULL);
++
++ // Create and lock the node
++ curNode = bgp_node_get (curTable, &p);
++ assert (curNode->hist == NULL);
++
++ // bgp_lock_node(curNode);
++
++ curNode->hist =
++ XCALLOC (MTYPE_BGP_PGBGP_HIST, sizeof (struct bgp_pgbgp_hist));
++ assert (curNode->hist != NULL);
++
++ curNode->hist->p =
++ XCALLOC (MTYPE_BGP_PGBGP_PREFIX,
++ sizeof (struct bgp_pgbgp_prefix));
++ assert (curNode->hist->p != NULL);
++
++ curNode->hist->p->lastSeen = time;
++ }
++ else if (type == ORIGIN_ID)
++ {
++ unsigned int ASN;
++ long long int time;
++ fscanf (file, "%u %lld", &ASN, &time);
++ struct bgp_pgbgp_origin *or = XCALLOC (MTYPE_BGP_PGBGP_ORIGIN,
++ sizeof (struct
++ bgp_pgbgp_origin));
++ or->lastSeen = time;
++ or->originAS = ASN;
++ or->next = curNode->hist->o;
++ curNode->hist->o = or;
++ }
++ else if (type == EDGE_ID)
++ {
++ bgp_pgbgp_restoreEdge (file);
++ }
++ else if (type == PEER_ID)
++ {
++ struct bgp_pgbgp_peerTime *pr;
++ long long int time;
++ union sockunion su;
++ char szsu[128];
++ fscanf (file, "%s %lld", szsu, &time);
++ str2sockunion (szsu, &su);
++ pr =
++ XCALLOC (MTYPE_BGP_PGBGP_PEER,
++ sizeof (struct bgp_pgbgp_peerTime));
++ pr->su = su;
++ pr->lastSeen = time;
++ pr->next = pgbgp->peerLast;
++ pgbgp->peerLast = pr;
++ }
++ }
++
++ fclose (file);
++ return 0;
++}
++
++int
++bgp_pgbgp_store (struct bgp_table *table)
++{
++ if (pgbgp->storage == NULL)
++ return 0;
++ char *tmpname = malloc (sizeof (char) * (1 + 4 + strlen (pgbgp->storage)));
++ strcpy (tmpname, pgbgp->storage);
++ strcat (tmpname, ".tmp");
++ FILE *file = fopen (tmpname, "w");
++
++ if (!file)
++ {
++ free (tmpname);
++ return 0;
++ }
++
++ // Store the current time
++ fprintf (file, "%lld\n", (long long int) time (NULL));
++
++ // Store the init time
++ fprintf (file, "%lld\n", (long long int) pgbgp->startTime);
++
++ // Store the peer times
++ for (struct bgp_pgbgp_peerTime * pr = pgbgp->peerLast; pr; pr = pr->next)
++ {
++ char strSock[128];
++ sockunion2str (&pr->su, strSock, sizeof (strSock));
++
++ if (pr->deprefUntil < time (NULL))
++ {
++ fprintf (file, "%d %s %lld\n", PEER_ID, strSock,
++ (long long int) pr->lastSeen);
++ }
++ }
++
++ // Store the tables
++ bgp_pgbgp_storeHistTable (table, file);
++ bgp_pgbgp_storeEdges (table, file);
++
++ fclose (file);
++
++ rename (tmpname, pgbgp->storage);
++
++ free (tmpname);
++ return 0;
++}
++
++/*
++ Check to see if we've seen the peer recently
++ If not, then we need to return true and not delay routes
++ for awhile
++*/
++int
++bgp_pgbgp_updatePeer (struct bgp_info *binfo, time_t now)
++{
++ int status = false;
++ // Find the peer
++ struct bgp_pgbgp_peerTime *pr = pgbgp->peerLast;
++ for (; pr; pr = pr->next)
++ if (sockunion_same (&pr->su, &binfo->peer->su))
++ break;
++
++ // If this is a new peer, create it
++ if (pr == NULL)
++ {
++ pr = XCALLOC (MTYPE_BGP_PGBGP_PEER, sizeof (struct bgp_pgbgp_peerTime));
++ pr->su = binfo->peer->su;
++ pr->next = pgbgp->peerLast;
++ pgbgp->peerLast = pr;
++
++ }
++ // Is it currently marked as new?
++ if (pr->deprefUntil > now)
++ goto UPPEER_DEPREF;
++
++ // Have we seen the peer recently?
++ if (pr->lastSeen + pgbgp->peer_hist_time > now)
++ goto UPPEER_CLEAN;
++
++ // It must not have been seen lately, depref it
++ pr->deprefUntil = now + PGBGP_PEER_GRACE;
++
++
++UPPEER_DEPREF:
++ status = true;
++
++UPPEER_CLEAN:
++ pr->lastSeen = now;
++
++ return status;
++}
++
++
++/*
++ Returns whether or not the sub-prefix should be ignored
++*/
++int
++bgp_pgbgp_shouldIgnore (struct bgp_node *super, struct bgp_info *selected)
++{
++ if (!selected || CHECK_FLAG (selected->flags, BGP_INFO_SUSPICIOUS_P))
++ return false;
++ return true;
++}
++
++/*
++ This is a special case function for smoothly handling sub-prefix hijacks.
++
++ It handles the following 2 events:
++
++ Event 1: The super-prefix of an anomalous prefix has a route through a non-anomalous
++
++ Event 1: An anomalous sub-prefix is ignored, but no best route for the super-prefix exists
++ Response: Announce the sub-prefix until the super-prefix comes back
++
++ Event 2: A super-prefix comes back to the RIB and its anomalous sub-prefix is in use
++ Response: Ignore the sub-prefix again
++ */
++
++
++int
++bgp_pgbgp_rib_updated (struct bgp_node *rn, struct bgp_info *old_best,
++ struct bgp_info *new_best)
++{
++ // return 0;
++ struct bgp_pgbgp_hist *hist = rn->hist;
++ if (!hist)
++ return 0;
++ if (!hist->p)
++ return 0;
++ time_t t_now = time (NULL);
++
++ /*
++ If we can't avoid the sub-prefix by routing to the super-prefix,
++ then route as normal to the sub-prefix
++ */
++ if (!bgp_pgbgp_shouldIgnore (rn, new_best))
++ {
++ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur;
++ cur = cur->next)
++ {
++ if (cur->avoidUntil > t_now)
++ {
++ int changed = false;
++ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next)
++ {
++ if (CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P))
++ {
++ changed = true;
++ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
++ }
++ }
++ if (changed)
++ {
++ struct bgp_info *ri = cur->sub->info;
++ if (ri && ri->peer && ri->peer->bgp)
++ bgp_process (ri->peer->bgp, cur->sub,
++ cur->sub->table->afi, cur->sub->table->safi);
++
++ }
++
++ }
++ }
++ }
++
++ /*
++ If we can avoid the sub-prefix by routing to the super-prefix,
++ then do so
++ */
++
++ else
++ {
++ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur;
++ cur = cur->next)
++ {
++ if (cur->avoidUntil > t_now)
++ {
++ int changed = false;
++ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next)
++ {
++ if (!CHECK_FLAG (ri->flags, BGP_INFO_IGNORED_P))
++ {
++ changed = true;
++ SET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
++ }
++ }
++ if (changed)
++ {
++ struct bgp_info *ri = cur->sub->info;
++ if (ri && ri->peer && ri->peer->bgp)
++ bgp_process (ri->peer->bgp, cur->sub,
++ cur->sub->table->afi, cur->sub->table->safi);
++ }
++ }
++ }
++ }
++
++ /*
++ if (old_best && !new_best)
++ {
++ time_t t_now = time(NULL);
++ for (struct bgp_pgbgp_avoid * cur = hist->p->avoid; cur;
++ cur = cur->next)
++ {
++ if (cur->avoidUntil > t_now)
++ {
++ for (struct bgp_info * ri = cur->sub->info; ri; ri = ri->next)
++ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
++
++ struct bgp_info *ri = cur->sub->info;
++ if (ri && ri->peer && ri->peer->bgp)
++ bgp_process (ri->peer->bgp, cur->sub, cur->sub->table->afi,
++ cur->sub->table->safi);
++ }
++ }
++ }
++
++
++ else if (!old_best && new_best)
++ {
++ time_t t_now = time(NULL);
++ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av; av = av->next)
++ {
++ struct bgp_info * ri = av->sub->info;
++ if (av->avoidUntil > t_now && ri && !CHECK_FLAG(ri->flags, BGP_INFO_IGNORED_P))
++ {
++ for (; ri; ri = ri->next)
++ SET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
++ ri = av->sub->info;
++ if (ri && ri->peer && ri->peer->bgp)
++ bgp_process (ri->peer->bgp, av->sub,
++ av->sub->table->afi, av->sub->table->safi);
++
++ }
++ }
++ }
++ */
++ return 0;
++}
++
++int
++bgp_pgbgp_update (struct bgp_info *binfo, struct attr *at,
++ struct bgp_node *rn)
++{
++ time_t t_now = time (NULL);
++
++ // Clean up the reuse list
++ bgp_pgbgp_reuse (t_now);
++
++
++ if (!rn->hist)
++ {
++ rn->hist =
++ XCALLOC (MTYPE_BGP_PGBGP_HIST, sizeof (struct bgp_pgbgp_hist));
++ // Get the PGBGP history lock on rn
++ bgp_lock_node (rn);
++ }
++
++ struct bgp_node *superhn = NULL;
++
++ // implicit lock from node_get
++ superhn = findSuper (rn->table, &rn->p, t_now);
++
++ int newPeer = bgp_pgbgp_updatePeer (binfo, t_now);
++ bgp_pgbgp_updateOrigin (rn->hist, binfo, at, rn, t_now, newPeer);
++ bgp_pgbgp_updatePrefix (rn->hist, superhn, binfo, at, rn, t_now, newPeer);
++ bgp_pgbgp_updateEdge (rn->hist, binfo, at, rn, t_now, newPeer);
++
++ if (superhn != NULL)
++ bgp_unlock_node (superhn);
++
++
++
++ // GC and storage must be last, as they update lastSeen values of objects
++ // which would cause new routes to be recently seen, which is undesired behavior
++ // Make sure you don't collect anything that might be in use!
++ if (t_now >= pgbgp->lastgc + PGBGP_GC_DELTA)
++ {
++ bgp_pgbgp_gc (rn->table);
++ pgbgp->lastgc = t_now;
++ }
++
++ if (t_now >= pgbgp->lastStore + PGBGP_STORE_DELTA)
++ {
++ bgp_pgbgp_store (rn->table);
++ pgbgp->lastStore = t_now;
++ }
++
++
++
++ return 0;
++}
++
++
++
++
++/*! --------------- Public PGBGP Interface ------------------ !*/
++
++
++
++
++
++
++
++
++
++/* --------------- MOAS Detection ------------------ */
++void
++bgp_pgbgp_storeHistTable (struct bgp_table *table, FILE * file)
++{
++ time_t t_now;
++ t_now = time (NULL);
++
++ struct bgp *bgp = bgp_get_default ();
++ if (!bgp)
++ return;
++
++ // Store each AFI/SAFI RIB
++ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++)
++ for (safi_t safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
++ {
++ if (!CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
++ continue;
++ struct bgp_table *curTable = bgp->rib[afi][safi];
++ if (!curTable)
++ continue;
++
++ for (struct bgp_node * rn = bgp_table_top (curTable); rn;
++ rn = bgp_route_next (rn))
++ {
++ struct bgp_pgbgp_hist *hist = rn->hist;
++ if (hist == NULL)
++ continue;
++ char szPrefix[128];
++ prefix2str (&rn->p, szPrefix, sizeof (szPrefix));
++
++
++ struct bgp_pgbgp_prefix *pre = hist->p;
++ if (pre && pre->ignoreUntil <= t_now)
++ {
++ if (pre->lastSeen + pgbgp->prefix_hist_time > t_now)
++ fprintf (file, "%d %s %u %u %lld\n", PREFIX_ID, szPrefix,
++ (unsigned int) afi, (unsigned int) safi,
++ (long long int) pre->lastSeen);
++ else
++ continue;
++ }
++ /* Need a prefix in the file before the origins,
++ if no prefix.. skip origins */
++ else
++ continue;
++
++ for (struct bgp_pgbgp_origin * cur = hist->o; cur;
++ cur = cur->next)
++ {
++ if (cur->deprefUntil > t_now)
++ continue;
++
++ if (cur->lastSeen + pgbgp->origin_hist_time > t_now)
++ fprintf (file, "%d %u %lld\n", ORIGIN_ID, cur->originAS,
++ (long long int) cur->lastSeen);
++ }
++
++ }
++ }
++}
++
++
++int
++bgp_pgbgp_garbageCollectHistTable (struct bgp_table *table)
++{
++ time_t t_now;
++ t_now = time (NULL);
++
++
++ for (struct bgp_node * rn = bgp_table_top (table); rn;
++ rn = bgp_route_next (rn))
++ {
++ int collect = false;
++ struct bgp_pgbgp_hist *hist = rn->hist;
++ if (hist == NULL)
++ continue;
++
++ struct bgp_pgbgp_origin *cur = hist->o;
++ struct bgp_pgbgp_prefix *pre = hist->p;
++ struct bgp_pgbgp_origin *parent = NULL;
++
++ int used = false;
++ if (cur != NULL || pre != NULL)
++ used = true;
++
++ while (cur != NULL)
++ {
++ // Update the lastSeen time w/ originInRIB
++ if (originInRIB (rn, cur))
++ cur->lastSeen = t_now;
++
++ collect = false;
++
++ // Collect if old
++ if (cur->lastSeen + pgbgp->origin_hist_time <= t_now)
++ collect = true;
++
++ // Collect if anomaly just became okay but not seen since last collection
++ if (cur->deprefUntil != 0 && cur->deprefUntil < t_now)
++ {
++ if (cur->lastSeen < pgbgp->lastgc)
++ collect = true;
++ cur->deprefUntil = 0;
++ }
++
++ if (collect)
++ {
++ if (parent == NULL)
++ hist->o = cur->next;
++ else
++ parent->next = cur->next;
++
++ // Delete cur, parent doesn't change
++ struct bgp_pgbgp_origin *del = cur;
++ cur = cur->next;
++ XFREE (MTYPE_BGP_PGBGP_ORIGIN, del);
++ }
++ else
++ {
++ parent = cur;
++ cur = cur->next;
++ }
++ }
++
++ // Update the lastSeen time w/ prefixInRIB
++ if (pre && prefixInRIB (rn, pre))
++ pre->lastSeen = t_now;
++
++ collect = false;
++
++ // Collect if old
++ if (pre && pre->lastSeen + pgbgp->prefix_hist_time <= t_now)
++ collect = true;
++
++ // Collect if anomaly just became okay but not seen since last collection
++ if (pre && pre->ignoreUntil != 0 && pre->ignoreUntil < t_now)
++ {
++ if (pre->lastSeen < pgbgp->lastgc)
++ collect = true;
++ pre->ignoreUntil = 0;
++ }
++
++ if (collect)
++ {
++ for (struct bgp_pgbgp_avoid * av = pre->avoid; av;)
++ {
++ struct bgp_pgbgp_avoid *del = av;
++ av = av->next;
++ bgp_unlock_node (del->sub);
++ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
++ }
++
++ XFREE (MTYPE_BGP_PGBGP_PREFIX, pre);
++ hist->p = NULL;
++ }
++
++ // If the node isn't in use, remove it
++ if (used && hist->o == NULL && hist->p == NULL)
++ {
++ XFREE (MTYPE_BGP_PGBGP_HIST, hist);
++ rn->hist = NULL;
++ bgp_unlock_node (rn);
++ }
++ }
++
++ return 0;
++}
++
++void
++bgp_pgbgp_cleanHistTable (struct bgp_table *table)
++{
++ // Clean up the RIB nodes
++ for (struct bgp_node * rn = bgp_table_top (table); rn;
++ rn = bgp_route_next (rn))
++ {
++ struct bgp_pgbgp_hist *hist = rn->hist;
++ if (hist == NULL)
++ continue;
++
++ if (hist->p)
++ {
++ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av;)
++ {
++ struct bgp_pgbgp_avoid *del = av;
++ av = av->next;
++ bgp_unlock_node (del->sub);
++ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
++ }
++ hist->p->avoid = NULL;
++ XFREE (MTYPE_BGP_PGBGP_PREFIX, hist->p);
++ hist->p = NULL;
++ }
++
++ for (struct bgp_pgbgp_origin * cur = hist->o; cur;)
++ {
++ struct bgp_pgbgp_origin *next = cur->next;
++ XFREE (MTYPE_BGP_PGBGP_ORIGIN, cur);
++ cur = next;
++ }
++ hist->o = NULL;
++ XFREE (MTYPE_BGP_PGBGP_HIST, hist);
++ rn->hist = NULL;
++ bgp_unlock_node (rn);
++ }
++}
++
++void
++bgp_pgbgp_logOriginAnomaly (as_t asn, struct bgp_node *rn, struct attr *at)
++{
++ assert (pgbgp);
++ if (!pgbgp->anomalies)
++ return;
++ FILE *file = fopen (pgbgp->anomalies, "a");
++ if (!file)
++ return;
++
++ char pre[256];
++ prefix2str (&rn->p, pre, sizeof (pre));
++
++ // MOAS | TIME | NEXTHOP | PREFIX | SUSPICIOUS_ORIGIN | TRUSTED_ORIGINS | PATH
++ fprintf (file, "%d|%lld|%s|%s|%d|", MOAS, (long long int) time (NULL),
++ inet_ntoa (at->nexthop), pre, asn);
++
++
++ // Print the trusted origins
++ assert (rn->hist);
++ assert (rn->hist->o);
++
++ struct bgp_pgbgp_hist *hist = rn->hist;
++
++ for (struct bgp_pgbgp_origin * cur = hist->o; cur != NULL; cur = cur->next)
++ {
++ if (cur->deprefUntil > time (NULL))
++ continue;
++ fprintf (file, "%d", cur->originAS);
++ if (cur->next != NULL)
++ fprintf (file, " ");
++ }
++
++ fprintf (file, " |%s\n", aspath_print (at->aspath));
++ fclose (file);
++}
++
++int
++bgp_pgbgp_updateOrigin (struct bgp_pgbgp_hist *hist, struct bgp_info *binfo,
++ struct attr *at, struct bgp_node *rn, time_t t_now,
++ int newPeer)
++{
++ struct bgp_pgbgp_pathSet pathOrigins;
++ struct bgp_pgbgp_origin *pi = NULL;
++ int status = 0;
++ struct bgp_pgbgp_reuse *r;
++ pathOrigins = bgp_pgbgp_pathOrigin (at->aspath);
++
++
++ for (int i = 0; i < pathOrigins.length; i++)
++ {
++ as_t pathOrigin = pathOrigins.ases[i];
++
++ /* Is the Origin AS in the history? */
++ for (pi = hist->o; pi; pi = pi->next)
++ if (pi->originAS == pathOrigin)
++ break;
++
++ if (pi == NULL)
++ {
++ pi =
++ XCALLOC (MTYPE_BGP_PGBGP_ORIGIN,
++ sizeof (struct bgp_pgbgp_origin));
++ pi->next = hist->o;
++ pi->originAS = pathOrigin;
++ hist->o = pi;
++ }
++
++ // If this is our first origin for the prefix, let the sub-prefix
++ // check take care of it
++ if (pi->next == NULL)
++ goto UPO_CLEAN;
++
++ /* Is the origin currently marked as suspicious? */
++ if (pi->deprefUntil > t_now)
++ goto UPO_DEPREF;
++
++ /* Have we seen the origin recently? */
++ if (pi->lastSeen + pgbgp->origin_hist_time > t_now)
++ goto UPO_CLEAN;
++
++#ifndef PGBGP_DEBUG
++ /* Are we within the initial grace period? */
++ if (newPeer)
++ goto UPO_CLEAN;
++#endif
++
++ /* It must not be in recent history, depref origin for first time */
++ pi->deprefUntil = t_now + pgbgp->origin_sus_time;
++ bgp_pgbgp_logOriginAnomaly (pathOrigin, rn, at);
++
++ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
++ r->type = PGBGP_REUSE_ORIGIN;
++ r->deprefUntil = pi->deprefUntil;
++ r->data.origin.originAS = pathOrigin;
++ r->data.origin.rn = rn;
++ bgp_lock_node (rn);
++ pqueue_enqueue (r, pgbgp->reuse_q);
++ pgbgp->rq_size += 1;
++
++
++ UPO_DEPREF:
++ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_O);
++ status = BGP_INFO_SUSPICIOUS_O;
++
++ UPO_CLEAN:
++ pi->lastSeen = t_now;
++ }
++ return status;
++}
++
++int
++bgp_pgbgp_reuseOrigin (struct bgp_pgbgp_r_origin data)
++{
++ struct bgp_info *ri;
++ int numChanged = 0;
++ time_t t_now = time (NULL);
++ assert (data.rn->hist != NULL);
++
++ // Repreference paths for this prefix that are now okay
++ for (ri = data.rn->info; ri; ri = ri->next)
++ {
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O))
++ {
++ struct bgp_pgbgp_pathSet pathOrigins;
++ pathOrigins = bgp_pgbgp_pathOrigin (ri->attr->aspath);
++ int numOkay = 0;
++ for (int i = 0; i < pathOrigins.length; i++)
++ {
++ as_t pathOrigin = pathOrigins.ases[i];
++ // Find the origin
++ struct bgp_pgbgp_origin *o = NULL;
++ for (o = data.rn->hist->o; o != NULL; o = o->next)
++ if (o->originAS == pathOrigin)
++ break;
++ /*
++ if (o == NULL) {
++ for(struct bgp_pgbgp_origin * z = data.rn->hist->o; z != NULL; z = z->next)
++ printf("Known origin: %d\n", z->originAS);
++ char pre[128];
++ prefix2str(&data.rn->p, pre, 128);
++ printf("%s : %s : %d\n", pre, ri->attr->aspath->str, pathOrigin);
++ }
++ */
++ assert (o != NULL);
++
++ if (o->deprefUntil <= t_now)
++ numOkay += 1;
++ }
++ if (numOkay == pathOrigins.length)
++ {
++ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_O);
++ numChanged += 1;
++ }
++ }
++ }
++
++ ri = data.rn->info;
++
++ // Rerun the decision process?
++ if (numChanged > 0)
++ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
++ data.rn->table->safi);
++
++
++ /*
++ // Remove this (origin,prefix) pair from the normal database
++ // if it's not still in the RIB
++ struct bgp_pgbgp_hist *hist = rn->hist;
++ struct bgp_pgbgp_origin * cur = hist->o;
++ struct bgp_pgbgp_origin * parent = NULL;
++
++ // Find the origin AS node
++ while(cur != NULL)
++ {
++ if (cur->originAS == data.originAS)
++ {
++ // Delete the node if it hasn't been seen
++ // since the last storage run
++ if (cur->lastSeen < pgbgp->lastStore) {
++ // Delete this node
++ if (parent == NULL)
++ hist->o = cur->next;
++ else
++ parent->next = cur->next;
++
++ XFREE(MTYPE_BGP_PGBGP_ORIGIN, cur);
++ }
++ break;
++ }
++ parent = cur;
++ cur = cur->next;
++ }
++ */
++
++ bgp_unlock_node (data.rn);
++ return 0;
++}
++
++/*! --------------- MOAS Detection ------------------ !*/
++
++
++/* --------------- Sub-Prefix Detection ------------------ */
++
++
++
++
++
++void
++bgp_pgbgp_logSubprefixAnomaly (as_t asn, struct bgp_node *rn, struct attr *at,
++ struct bgp_node *super)
++{
++ assert (pgbgp);
++ if (!pgbgp->anomalies)
++ return;
++ FILE *file = fopen (pgbgp->anomalies, "a");
++ if (!file)
++ return;
++
++ char pre[256];
++ prefix2str (&rn->p, pre, sizeof (pre));
++
++ char superpre[256];
++ prefix2str (&super->p, superpre, sizeof (superpre));
++
++ // SUBPREFIX | TIME | NEXTHOP | PREFIX | SUPER-PREFIX | SUSPICIOUS_ORIGIN | TRUSTED_ORIGINS | PATH
++ fprintf (file, "%d|%lld|%s|%s|%s|%d|", SUBPREFIX,
++ (long long int) time (NULL), inet_ntoa (at->nexthop), pre,
++ superpre, asn);
++
++ // Print the trusted origins
++ assert (super->hist);
++ assert (super->hist->o);
++
++ struct bgp_pgbgp_hist *hist = super->hist;
++
++ for (struct bgp_pgbgp_origin * cur = hist->o; cur != NULL; cur = cur->next)
++ {
++ if (cur->deprefUntil > time (NULL))
++ continue;
++ fprintf (file, "%d", cur->originAS);
++ if (cur->next != NULL)
++ fprintf (file, " ");
++ }
++
++ fprintf (file, " |%s\n", aspath_print (at->aspath));
++ fclose (file);
++}
++
++/*
++ If the first path is a prefix of the second, then return true
++ */
++
++static int
++bgp_pgbgp_pathIsPrefix(struct aspath *trusted, struct aspath * new)
++{
++ if (trusted == new)
++ return true;
++
++ struct assegment *seg1 = trusted->segments;
++ struct assegment *seg2 = new->segments;
++
++ while (seg1 || seg2)
++ {
++ if ((!seg1 && seg2) || (seg1 && !seg2))
++ return false;
++ if (seg1->type != seg2->type)
++ return false;
++
++ if (seg1->length > seg2->length)
++ return false;
++
++ for(int i = 0; i < seg1->length; i++)
++ if (seg1->as[i] != seg2->as[i])
++ return false;
++
++ seg1 = seg1->next;
++ seg2 = seg2->next;
++ }
++
++ return true;
++}
++
++int
++bgp_pgbgp_updatePrefix (struct bgp_pgbgp_hist *hist,
++ struct bgp_node *supernode, struct bgp_info *binfo,
++ struct attr *at, struct bgp_node *rn, time_t t_now,
++ int newPeer)
++{
++ struct bgp_pgbgp_prefix *pre = NULL;
++ struct bgp_pgbgp_reuse *r = NULL;
++ int status = 0;
++ int changed = false;
++
++ pre = hist->p;
++
++
++ /* Do we have this prefix? */
++ if (pre == NULL)
++ {
++ pre =
++ XCALLOC (MTYPE_BGP_PGBGP_PREFIX, sizeof (struct bgp_pgbgp_prefix));
++ hist->p = pre;
++ }
++
++ /* Is the prefix currently marked as suspicious? */
++ if (pre->ignoreUntil > t_now)
++ {
++ goto UPP_IGNORE;
++ }
++
++ /* Should this neighbor be avoided for this prefix because it
++ sent us info. about a suspicious sub-prefix? */
++ for (struct bgp_pgbgp_avoid * av = hist->p->avoid; av; av = av->next)
++ {
++ if (binfo->peer->as == av->peerASN && av->avoidUntil > t_now)
++ {
++ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_P);
++ status = BGP_INFO_SUSPICIOUS_P;
++ goto UPP_DONE;
++ }
++ }
++
++ /* Have we seen the prefix recently? */
++ if (pre->lastSeen + pgbgp->prefix_hist_time > t_now)
++ goto UPP_DONE;
++
++#ifndef PGBGP_DEBUG
++ /* Are we within the initial grace period? */
++ if (newPeer)
++ goto UPP_DONE;
++#endif
++
++ /* Is there a less specific *in recent history* that this could be hijacking? */
++ if (supernode == NULL)
++ goto UPP_DONE;
++
++ /* Does this path the super-net's non-anomalous path from this peer? If so it's okay */
++ int found = false;
++ for (struct bgp_info * ri = supernode->info; ri; ri = ri->next)
++ {
++ if (ri->peer->as == binfo->peer->as)
++ {
++ if (!ANOMALOUS(ri->flags) && bgp_pgbgp_pathIsPrefix(ri->attr->aspath, at->aspath))
++ found = true;
++ break;
++ }
++ }
++
++ if (found)
++ goto UPP_DONE;
++
++ /*
++ It's not in recent history, and there is a less specific currently in use
++ Response:
++ . Ignore this prefix
++ . Make the less specific's route for this neighbor suspicious
++ */
++
++
++ pre->ignoreUntil = t_now + pgbgp->sub_sus_time;
++
++ struct bgp_pgbgp_pathSet pathOrigins;
++ pathOrigins = bgp_pgbgp_pathOrigin (at->aspath);
++ for (int i = 0; i < pathOrigins.length; i++)
++ bgp_pgbgp_logSubprefixAnomaly (pathOrigins.ases[i], rn, at, supernode);
++
++
++
++ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
++ r->type = PGBGP_REUSE_PREFIX;
++ r->deprefUntil = pre->ignoreUntil;
++ r->data.prefix.rn = rn;
++ r->data.prefix.rnsuper = supernode;
++ bgp_lock_node (rn);
++ bgp_lock_node (supernode);
++ pqueue_enqueue (r, pgbgp->reuse_q);
++ pgbgp->rq_size += 1;
++
++UPP_IGNORE:
++ // Sanity check
++ if (supernode == NULL)
++ goto UPP_DONE;
++
++ /* Set the less specific's route from this peer to suspicious */
++ changed = false;
++
++ for (struct bgp_info * ri = supernode->info; ri; ri = ri->next)
++ {
++ if (ri->peer->as == binfo->peer->as)
++ {
++ if (!CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P))
++ {
++ SET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P);
++ changed = true;
++ }
++ break;
++ }
++ }
++
++ // Make note of it in the less specific's history information
++ found = false;
++ struct bgp_pgbgp_hist *superhist = supernode->hist;
++
++ if (superhist && superhist->p)
++ {
++ for (struct bgp_pgbgp_avoid * av = superhist->p->avoid; av;
++ av = av->next)
++ {
++ if (av->peerASN == binfo->peer->as)
++ {
++ if (av->avoidUntil < pre->ignoreUntil)
++ av->avoidUntil = pre->ignoreUntil;
++ found = true;
++ break;
++ }
++ }
++ if (!found)
++ {
++ struct bgp_pgbgp_avoid *newavoid =
++ XCALLOC (MTYPE_BGP_PGBGP_AVOID, sizeof (struct bgp_pgbgp_avoid));
++ newavoid->peerASN = binfo->peer->as;
++ newavoid->avoidUntil = pre->ignoreUntil;
++ newavoid->next = superhist->p->avoid;
++ newavoid->sub = rn;
++ bgp_lock_node (rn);
++ superhist->p->avoid = newavoid;
++ }
++ }
++ /*
++ ignore this route unless the supernet's node
++ is only a placeholder from loaded pgbgp data
++ */
++ if (bgp_pgbgp_shouldIgnore (supernode, bgp_pgbgp_selected (supernode)))
++ {
++ SET_FLAG (binfo->flags, BGP_INFO_IGNORED_P);
++ status = BGP_INFO_IGNORED_P;
++ }
++ if (changed)
++ {
++ struct bgp_info *ri = supernode->info;
++ bgp_process (ri->peer->bgp, supernode, supernode->table->afi,
++ supernode->table->safi);
++ }
++
++UPP_DONE:
++ pre->lastSeen = t_now;
++
++ return status;
++}
++
++int
++bgp_pgbgp_reusePrefix (struct bgp_pgbgp_r_prefix data)
++{
++ struct bgp_info *ri = NULL;
++
++ time_t t_now = time (NULL);
++
++ // Repreference all routes for this node
++ for (ri = data.rn->info; ri; ri = ri->next)
++ UNSET_FLAG (ri->flags, BGP_INFO_IGNORED_P);
++ ri = data.rn->info;
++
++ // Rerun the decision process
++ if (ri != NULL)
++ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
++ data.rn->table->safi);
++
++
++ // Remove the avoid nodes from the super
++ struct bgp_pgbgp_hist *superhist = data.rnsuper->hist;
++ if (superhist != NULL && superhist->p != NULL)
++ {
++ struct bgp_pgbgp_avoid *parent = NULL;
++ for (struct bgp_pgbgp_avoid * av = superhist->p->avoid; av;)
++ {
++ int numChanged = 0;
++ if (av->avoidUntil <= t_now)
++ {
++ struct bgp_pgbgp_avoid *del = av;
++ av = av->next;
++ if (parent == NULL)
++ superhist->p->avoid = av;
++ else
++ parent->next = av;
++
++ // Repreference any routes
++ for (ri = data.rnsuper->info; ri; ri = ri->next)
++ {
++ if (ri->peer->as == del->peerASN)
++ {
++ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_P);
++ numChanged += 1;
++ break;
++ }
++ }
++ ri = data.rnsuper->info;
++
++ if (numChanged > 0 && ri != NULL)
++ bgp_process (ri->peer->bgp, data.rnsuper,
++ data.rnsuper->table->afi,
++ data.rnsuper->table->safi);
++ bgp_unlock_node (del->sub);
++ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
++ }
++ else
++ {
++ parent = av;
++ av = av->next;
++ }
++ }
++ }
++
++ // Remove this prefix from the normal database
++ // if it hasn't been seen in the RIB since the last
++ // storage run
++ /*
++ struct bgp_pgbgp_hist *hist = rn->hist;
++ struct bgp_pgbgp_prefix * pre = hist->p;
++
++ if (pre && pre->lastSeen < pgbgp->lastStore)
++ {
++ // Delete this node
++ for(struct bgp_pgbgp_avoid * av = hist->p->avoid; av;)
++ {
++ struct bgp_pgbgp_avoid *del = av;
++ av = av->next;
++ bgp_unlock_node(del->sub);
++ XFREE (MTYPE_BGP_PGBGP_AVOID, del);
++ }
++ XFREE(MTYPE_BGP_PGBGP_PREFIX, pre);
++ hist->p = NULL;
++ }
++ */
++ bgp_unlock_node (data.rn);
++ bgp_unlock_node (data.rnsuper);
++ return 0;
++}
++
++/*! --------------- Sub-Prefix Detection ------------------ !*/
++
++
++
++
++
++/* --------------- Edge Detection ------------------ */
++
++static void
++edge_store_clear_iterator (struct hash_backet *backet, void *file)
++{
++ struct bgp_pgbgp_edge *hedge = backet->data;
++}
++
++static void
++edge_store_iterator (struct hash_backet *backet, FILE * file)
++{
++ struct bgp_pgbgp_edge *hedge = backet->data;
++ time_t t_now = time (NULL);
++ if (hedge->deprefUntil > t_now)
++ return;
++ if (hedge->lastSeen + pgbgp->edge_hist_time > t_now)
++ {
++ fprintf (file, "%d %u %u %lld\n", EDGE_ID, hedge->e.a, hedge->e.b,
++ (long long int) hedge->lastSeen);
++ }
++}
++
++
++void
++bgp_pgbgp_storeEdges (struct bgp_table *table, FILE * file)
++{
++ hash_iterate (pgbgp->edgeT,
++ (void (*)(struct hash_backet *, void *))
++ edge_store_iterator, file);
++ return;
++}
++
++
++int
++bgp_pgbgp_restoreEdge (FILE * file)
++{
++ unsigned int a, b;
++ long long int lastSeen;
++ fscanf (file, "%u %u %lld", &a, &b, &lastSeen);
++ struct bgp_pgbgp_edge finder;
++ finder.e.a = a;
++ finder.e.b = b;
++ finder.lastSeen = lastSeen;
++ struct bgp_pgbgp_edge *hedge =
++ hash_get (pgbgp->edgeT, &finder, edge_hash_alloc);
++ hedge->lastSeen = finder.lastSeen;
++ return 0;
++}
++
++unsigned int
++edge_key_make (void *p)
++{
++ struct bgp_pgbgp_edge *pe = p;
++ struct edge *e = &pe->e;
++ return (e->a << 16) + e->b;
++}
++
++static int
++edge_cmp (const void *arg1, const void *arg2)
++{
++
++ const struct edge *e1 = &((const struct bgp_pgbgp_edge *) arg1)->e;
++ const struct edge *e2 = &((const struct bgp_pgbgp_edge *) arg2)->e;
++ if (e1->a == e2->a && e1->b == e2->b)
++ return 1;
++ return 0;
++}
++
++static void *
++edge_hash_alloc (void *arg)
++{
++ struct bgp_pgbgp_edge *hedge =
++ XCALLOC (MTYPE_BGP_PGBGP_EDGE, sizeof (struct bgp_pgbgp_edge));
++ struct bgp_pgbgp_edge *lookup = arg;
++ if (hedge == NULL)
++ return NULL;
++ hedge->e = lookup->e;
++ return hedge;
++}
++
++
++static void
++edge_gc_iterator (struct hash_backet *backet, time_t * time)
++{
++ time_t t_now = *time;
++ struct bgp_pgbgp_edge *hedge = backet->data;
++
++ int collect = false;
++
++ // Collect if we haven't seen it in awhile
++ if (hedge->lastSeen + pgbgp->edge_hist_time <= t_now)
++ collect = true;
++
++ // Collect if it has just gotten out of anomaly stage
++ // but hasn't been in the RIB since the last GC
++ if (hedge->deprefUntil != 0 && hedge->deprefUntil < t_now)
++ {
++ if (hedge->lastSeen < pgbgp->lastgc)
++ collect = true;
++ hedge->deprefUntil = 0;
++ }
++
++ if (collect)
++ {
++ struct bgp_pgbgp_edge *ret = hash_release (pgbgp->edgeT, hedge);
++ assert (ret != NULL);
++ XFREE (MTYPE_BGP_PGBGP_EDGE, hedge);
++ }
++}
++
++
++
++static void
++edge_update_iterator (struct hash_backet *backet, void *v)
++{
++ struct aspath *p = backet->data;
++ time_t t_now = time (NULL);
++ int first = true;
++
++ struct edge cur;
++ cur.a = 0;
++ cur.b = 0;
++ struct assegment *seg;
++ struct bgp_pgbgp_edge *hedge = NULL;
++ for (seg = p->segments; seg; seg = seg->next)
++ {
++ for (int i = 0; i < seg->length; i++)
++ {
++ cur.a = cur.b;
++ cur.b = seg->as[i];
++ if (first)
++ {
++ first = false;
++ continue;
++ }
++ if (cur.a == cur.b)
++ continue;
++ // printf("%d -- %d\n", cur.a, cur.b);
++ struct bgp_pgbgp_edge finder;
++ finder.e = cur;
++ hedge = hash_lookup (pgbgp->edgeT, &finder);
++
++ if (!hedge)
++ continue;
++ hedge->lastSeen = t_now;
++ }
++ }
++}
++
++int
++bgp_pgbgp_garbageCollectEdges (struct bgp_table *table)
++{
++ // Update the timings
++ hash_iterate (ashash,
++ (void (*)(struct hash_backet *, void *))
++ edge_update_iterator, NULL);
++
++ // Perform the collection
++ time_t t_now = time (NULL);
++ hash_iterate (pgbgp->edgeT,
++ (void (*)(struct hash_backet *, void *))
++ edge_gc_iterator, &t_now);
++ return 0;
++}
++
++static void
++edge_clean_iterator (struct hash_backet *backet, void *a1)
++{
++ struct bgp_pgbgp_edge *hedge = backet->data;
++ struct bgp_pgbgp_edge *ret = hash_release (pgbgp->edgeT, hedge);
++ assert (ret != NULL);
++ XFREE (MTYPE_BGP_PGBGP_EDGE, hedge);
++}
++
++static void
++bgp_pgbgp_cleanEdges (void)
++{
++ if (pgbgp->edgeT != NULL)
++ {
++ hash_iterate (pgbgp->edgeT,
++ (void (*)(struct hash_backet *, void *))
++ edge_clean_iterator, NULL);
++ hash_free (pgbgp->edgeT);
++ }
++ return;
++}
++
++void
++bgp_pgbgp_logEdgeAnomaly (struct bgp_node *rn, struct attr *at,
++ struct edge *edge)
++{
++ assert (pgbgp);
++ if (!pgbgp->anomalies)
++ return;
++ FILE *file = fopen (pgbgp->anomalies, "a");
++ if (!file)
++ return;
++
++ char pre[256];
++ prefix2str (&rn->p, pre, sizeof (pre));
++
++ // EDGE | TIME | NEXTHOP | PREFIX | PATH | Edge.a | Edge.b
++
++ fprintf (file, "%d|%lld|%s|%s|%s|%d|%d\n", EDGE,
++ (long long int) time (NULL), inet_ntoa (at->nexthop), pre,
++ aspath_print (at->aspath), edge->a, edge->b);
++
++ fclose (file);
++}
++
++
++int
++bgp_pgbgp_updateEdge (struct bgp_pgbgp_hist *hist, struct bgp_info *binfo,
++ struct attr *at, struct bgp_node *rn, time_t t_now,
++ int newPeer)
++{
++
++ char first = true;
++ struct edge curEdge;
++ curEdge.a = 0;
++ curEdge.b = 0;
++
++
++ if (at->aspath == NULL)
++ return 0;
++ struct assegment *seg = at->aspath->segments;
++ if (seg == NULL)
++ return 0;
++ time_t max_depref = 0;
++ for (seg = at->aspath->segments; seg; seg = seg->next)
++ {
++ for (int i = 0; i < seg->length; i++)
++ {
++ curEdge.a = curEdge.b;
++ curEdge.b = seg->as[i];
++ if (first)
++ {
++ first = false;
++ continue;
++ }
++ if (curEdge.a == curEdge.b)
++ continue;
++
++ // We have an edge to consider
++ struct bgp_pgbgp_edge finder;
++ finder.e = curEdge;
++ struct bgp_pgbgp_edge *hedge =
++ hash_get (pgbgp->edgeT, &finder, edge_hash_alloc);
++
++ // Is this edge marked as suspicious?
++ if (hedge->deprefUntil > t_now)
++ goto UPE_DEPREF;
++
++ // Have we seen the edge recently?
++ if (hedge->lastSeen + pgbgp->edge_hist_time > t_now)
++ goto UPE_CLEAN;
++#ifndef PGBGP_DEBUG
++ /* Are we within the initial grace period? */
++ if (newPeer)
++ goto UPE_CLEAN;
++#endif
++ // It must not be in recent history, depref edge for first time
++ hedge->deprefUntil = t_now + pgbgp->edge_sus_time;
++ bgp_pgbgp_logEdgeAnomaly (rn, at, &curEdge);
++
++
++ UPE_DEPREF:
++ if (hedge->deprefUntil > max_depref)
++ max_depref = hedge->deprefUntil;
++ UPE_CLEAN:
++ hedge->lastSeen = t_now;
++ }
++ }
++ if (max_depref)
++ {
++ SET_FLAG (binfo->flags, BGP_INFO_SUSPICIOUS_E);
++ if (!hist->pEdgeReuse)
++ {
++ struct bgp_pgbgp_reuse *r;
++ r =
++ XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
++ r->type = PGBGP_REUSE_EDGE;
++ r->deprefUntil = max_depref;
++ r->data.edge.rn = rn;
++ bgp_lock_node (rn);
++ pqueue_enqueue (r, pgbgp->reuse_q);
++ pgbgp->rq_size += 1;
++ hist->pEdgeReuse = r;
++ }
++ return BGP_INFO_SUSPICIOUS_E;
++ }
++
++ return 0;
++}
++
++int
++bgp_pgbgp_reuseEdge (struct bgp_pgbgp_r_edge data)
++{
++
++ // Okay, go through all of the paths for the prefix
++ // and find the path that needs to be updated next and
++ // enqueue it
++ time_t minMax = 0;
++ int numChanged = 0;
++ time_t t_now = time (NULL);
++
++ for (struct bgp_info * ri = data.rn->info; ri; ri = ri->next)
++ {
++ char first = true;
++ struct edge curEdge = { 0, 0 };
++ struct assegment *seg;
++ time_t max_depref = 0;
++
++ for (seg = ri->attr->aspath->segments; seg; seg = seg->next)
++ {
++ for (int i = 0; i < seg->length; i++)
++ {
++ curEdge.a = curEdge.b;
++ curEdge.b = seg->as[i];
++ if (first)
++ {
++ first = false;
++ continue;
++ }
++ struct bgp_pgbgp_edge finder;
++ finder.e = curEdge;
++ struct bgp_pgbgp_edge *hedge =
++ hash_lookup (pgbgp->edgeT, &finder);
++ if (!hedge)
++ continue;
++ // Is this edge suspicious?
++ if (hedge->deprefUntil > t_now
++ && hedge->deprefUntil > max_depref)
++ max_depref = hedge->deprefUntil;
++ }
++ }
++
++ if (max_depref)
++ {
++ if (!minMax || max_depref < minMax)
++ minMax = max_depref;
++ }
++ else
++ {
++ if (CHECK_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E))
++ {
++ UNSET_FLAG (ri->flags, BGP_INFO_SUSPICIOUS_E);
++ numChanged += 1;
++ }
++ }
++ }
++ struct bgp_info *ri = data.rn->info;
++ if (numChanged > 0 && ri)
++ bgp_process (ri->peer->bgp, data.rn, data.rn->table->afi,
++ data.rn->table->safi);
++
++ struct bgp_pgbgp_hist *hist = data.rn->hist;
++ hist->pEdgeReuse = NULL;
++
++ if (minMax)
++ {
++ struct bgp_pgbgp_reuse *r;
++ r = XCALLOC (MTYPE_BGP_PGBGP_REUSE, sizeof (struct bgp_pgbgp_reuse));
++ r->type = PGBGP_REUSE_EDGE;
++ r->deprefUntil = minMax;
++ r->data.edge.rn = data.rn;
++ pqueue_enqueue (r, pgbgp->reuse_q);
++ pgbgp->rq_size += 1;
++ hist->pEdgeReuse = r;
++ }
++ else
++ {
++ bgp_unlock_node (data.rn);
++ }
++
++ return 0;
++}
+--- /dev/null
++++ b/bgpd/bgp_pgbgp.h
+@@ -0,0 +1,286 @@
++/* BGP Pretty Good BGP
++ Copyright (C) 2008 University of New Mexico (Josh Karlin)
++
++This file is part of GNU Zebra.
++
++GNU Zebra is free software; you can redistribute it and/or modify it
++under the terms of the GNU General Public License as published by the
++Free Software Foundation; either version 2, or (at your option) any
++later version.
++
++GNU Zebra is distributed in the hope that it will be useful, but
++WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with GNU Zebra; see the file COPYING. If not, write to the Free
++Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
++02111-1307, USA. */
++
++#ifndef _QUAGGA_BGP_PGBGP_H
++#define _QUAGGA_BGP_PGBGP_H
++
++#include "bgpd.h"
++#include "bgp_route.h"
++#include "table.h"
++
++#define MOAS 0
++#define SUBPREFIX 1
++#define EDGE 2
++
++/* Global PGBGP data */
++struct bgp_pgbgp_config
++{
++ /* Depref time for a new origin AS */
++ time_t origin_sus_time;
++
++ /* Depref time for a new edge */
++ time_t edge_sus_time;
++
++ /* Depref time for a new sub-prefix */
++ time_t sub_sus_time;
++
++ /* Origin AS Mapping History Length */
++ time_t origin_hist_time;
++
++ /* Prefix Mapping History Length */
++ time_t prefix_hist_time;
++
++ /* Edge Mapping History Length */
++ time_t edge_hist_time;
++
++ /* Peer Mapping History Length */
++ time_t peer_hist_time;
++
++ /* The list of depreferenced routes */
++ struct pqueue *reuse_q;
++ int rq_size;
++
++ /* Time that the last garbage collection (gc) took place */
++ time_t lastgc;
++
++ /* History table */
++ // struct route_table *histT;
++
++ /* Edge Hash Table */
++ struct hash *edgeT;
++
++ /* File path for history storage */
++ char *storage;
++
++ /* File path for dump of anomalous routes */
++ char *anomalies;
++
++ /* The time that we last stored to disk */
++ time_t lastStore;
++
++ /* The time that PGBGP started counting */
++ time_t startTime;
++
++ /* Last time each peer was seen */
++ struct bgp_pgbgp_peerTime *peerLast;
++
++};
++
++
++struct bgp_pgbgp_peerTime
++{
++ struct bgp_pgbgp_peerTime *next;
++ time_t lastSeen;
++ union sockunion su;
++ time_t deprefUntil;
++};
++
++struct edge
++{
++ as_t a;
++ as_t b;
++};
++
++/*
++ Avoid the neighbors for the less specific that told you about
++ the more specific
++ */
++struct bgp_pgbgp_avoid
++{
++ struct bgp_pgbgp_avoid *next;
++ time_t avoidUntil;
++ as_t peerASN;
++ struct bgp_node *sub;
++};
++
++/* A list of origin ASes for a path
++ Usually it's only one but if the last AS
++ in the path is an AS set, then the whole
++ set must be returned
++*/
++struct bgp_pgbgp_pathSet
++{
++ int length;
++ as_t *ases;
++};
++
++/*
++ Avoid paths with suspicious origins
++ */
++struct bgp_pgbgp_origin
++{
++ struct bgp_pgbgp_origin *next;
++ time_t lastSeen;
++ time_t deprefUntil;
++ as_t originAS;
++};
++
++/*
++ Ignore routes for this prefix
++ */
++struct bgp_pgbgp_prefix
++{
++ time_t lastSeen;
++ time_t ignoreUntil;
++ struct bgp_pgbgp_avoid *avoid;
++};
++
++struct bgp_pgbgp_edge
++{
++ time_t lastSeen;
++ time_t deprefUntil;
++ struct edge e;
++};
++
++struct bgp_pgbgp_hist
++{
++ struct bgp_pgbgp_origin *o;
++ struct bgp_pgbgp_prefix *p;
++ struct bgp_pgbgp_reuse *pEdgeReuse;
++};
++
++struct bgp_pgbgp_r_origin
++{
++ as_t originAS;
++ struct bgp_node *rn;
++};
++
++struct bgp_pgbgp_r_prefix
++{
++ struct bgp_node *rn;
++ struct bgp_node *rnsuper;
++};
++
++/*
++ This node contained a route with a bad edge, check
++ it again for bad edges in 24 hours
++*/
++struct bgp_pgbgp_r_edge
++{
++ struct bgp_node *rn;
++};
++
++
++union reuseTypes
++{
++ struct bgp_pgbgp_r_origin origin;
++ struct bgp_pgbgp_r_prefix prefix;
++ struct bgp_pgbgp_r_edge edge;
++};
++
++struct bgp_pgbgp_reuse
++{
++ union reuseTypes data;
++ short type;
++ time_t deprefUntil;
++};
++
++#define ANOMALOUS(V) \
++(CHECK_FLAG(V, BGP_INFO_SUSPICIOUS_O | BGP_INFO_SUSPICIOUS_P \
++ | BGP_INFO_SUSPICIOUS_E | BGP_INFO_IGNORED_P))
++
++#define PGBGP_REUSE_ORIGIN 0
++#define PGBGP_REUSE_PREFIX 1
++#define PGBGP_REUSE_EDGE 2
++
++#define BGP_PGBGP_NONE 0
++#define BGP_PGBGP_DEPREFFED 1
++
++// For storage
++#define ORIGIN_ID 0
++#define PREFIX_ID 1
++#define EDGE_ID 2
++#define PEER_ID 3
++
++/* Default timing values */
++#define DEFAULT_ORIGIN_SUS (86400 * 1)
++#define DEFAULT_EDGE_SUS (86400 * 1)
++#define DEFAULT_SUB_SUS (86400 * 1)
++#define DEFAULT_ORIGIN_HIST (86400 * 30)
++#define DEFAULT_PREFIX_HIST (86400 * 10)
++#define DEFAULT_EDGE_HIST (86400 * 60)
++// Time between garbage collections
++#define PGBGP_GC_DELTA (3600)
++// Time between file stores
++#define PGBGP_STORE_DELTA (28800)
++// Time that a new peer's routes are not considered suspicious
++#define PGBGP_PEER_GRACE (86400 * 1)
++
++
++
++///////// PUBLIC PGBGP FUNCTIONS /////////
++
++/*
++ bgp_pgbgp_enable:
++ Enable PGBGP depreferencing / history tracking for this afi/safi
++
++ Arguments:
++ . ost: Depref. time of new prefix origins (in hours)
++ . est: Depref. time of new edges (in hours)
++ . sst: Depref. time of new sub-prefixes (in hours)
++ . oht: Storage time of known origins for prefixes (in days)
++ . pht: Storage time of known prefixes (in days)
++ . eht: Storage time of known edges (in days)
++ . storage: File to periodically store history in (can be /dev/null)
++ . anoms: File to store history of depreferenced routes (can be /dev/null)
++
++ Caution:
++ It is important that the storage times are longer than the depreference times
++*/
++extern int bgp_pgbgp_enable (struct bgp *, afi_t afi, safi_t safi, int ost,
++ int est, int sst, int oht, int pht, int eht,
++ const char *storage, const char *anoms);
++extern int bgp_pgbgp_disable (struct bgp *, afi_t afi, safi_t safi);
++
++/*
++ bgp_pgbgp_update:
++ Call on the event of an announcement update
++
++ Arguments:
++ bgp_info: The route
++ at: The new route's attributes
++*/
++extern int bgp_pgbgp_update (struct bgp_info *, struct attr *at,
++ struct bgp_node *);
++
++/*
++ bgp_pgbgp_rib_updated:
++ Call upon discovery of a new best path (or lack thereof)
++
++ This is a special case function for smoothly handling sub-prefix hijacks.
++
++ It handles the following 2 events:
++
++ Event 1: An anomalous sub-prefix is ignored, but no best route for the super-prefix exists
++ Response: Announce the sub-prefix until the super-prefix comes back
++
++ Event 2: A super-prefix comes back to the RIB and its anomalous sub-prefix is in use
++ Response: Ignore the sub-prefix again
++
++ Arguments:
++ rn: The route node that a new best path was found for
++ old_best: The old best route (NULL if one did not exist)
++ new_best: The current best route (NULL if one does not exist)
++ */
++extern int
++bgp_pgbgp_rib_updated (struct bgp_node *rn, struct bgp_info *old_best,
++ struct bgp_info *new_best);
++
++#endif
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -51,6 +51,7 @@ Software Foundation, Inc., 59 Temple Pla
+ #include "bgpd/bgp_mplsvpn.h"
+ #include "bgpd/bgp_nexthop.h"
+ #include "bgpd/bgp_damp.h"
++#include "bgpd/bgp_pgbgp.h"
+ #include "bgpd/bgp_advertise.h"
+ #include "bgpd/bgp_zebra.h"
+ #include "bgpd/bgp_vty.h"
+@@ -339,12 +340,19 @@ bgp_info_cmp (struct bgp *bgp, struct bg
+
+ *paths_eq = 0;
+
++
+ /* 0. Null check. */
+ if (new == NULL)
+ return 0;
+ if (exist == NULL)
+ return 1;
+
++ /* 0.5 PGBGP Depref. Check */
++ if (ANOMALOUS(exist->flags) && !ANOMALOUS(new->flags))
++ return 1;
++ if (!ANOMALOUS(exist->flags) && ANOMALOUS(new->flags))
++ return 0;
++
+ /* 1. Weight check. */
+ if (new->attr->extra)
+ new_weight = new->attr->extra->weight;
+@@ -1583,6 +1591,10 @@ bgp_process_main (struct work_queue *wq,
+ UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG);
+ }
+
++ /* PGBGP needs to know about selected routes */
++ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP))
++ bgp_pgbgp_rib_updated(rn, old_select, new_select);
++
+
+ /* Check each BGP peer. */
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+@@ -1906,6 +1918,11 @@ bgp_update_rsclient (struct peer *rsclie
+ /* If the update is implicit withdraw. */
+ if (ri)
+ {
++ /* Update PGBGP state, and mark the route as anomalous if necessary */
++ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)
++ && peer_sort(peer) == BGP_PEER_EBGP)
++ bgp_pgbgp_update(ri, attr_new, rn);
++
+ ri->uptime = bgp_clock ();
+
+ /* Same attribute comes in. */
+@@ -2337,6 +2354,11 @@ bgp_update_main (struct peer *peer, stru
+ /* Increment prefix */
+ bgp_aggregate_increment (bgp, p, new, afi, safi);
+
++ /* Update PGBGP state, and mark the route as anomalous if necessary */
++ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_PGBGP)
++ && peer_sort(peer) == BGP_PEER_EBGP)
++ bgp_pgbgp_update(new, attr_new, rn);
++
+ /* Register new BGP information. */
+ bgp_info_add (rn, new);
+
+@@ -5559,6 +5581,20 @@ enum bgp_display_type
+ static void
+ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
+ {
++ if (ANOMALOUS(binfo->flags))
++ {
++ vty_out(vty, "a[");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
++ vty_out(vty, "i");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
++ vty_out(vty, "p");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
++ vty_out(vty, "e");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
++ vty_out(vty, "s");
++ vty_out(vty, "] ");
++ }
++
+ /* Route status display. */
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED))
+ vty_out (vty, "R");
+@@ -6064,6 +6100,7 @@ route_vty_out_detail (struct vty *vty, s
+ }
+
+ #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s"
++#define BGP_SHOW_PCODE_HEADER "Status code: a (anomalous) of: [p] prefix hijack, [s] sub-prefix hijack,%s [i] informant of sub-prefix [e] new edge%s"
+ #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
+ #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
+ #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s"
+@@ -6095,7 +6132,8 @@ enum bgp_show_type
+ bgp_show_type_flap_route_map,
+ bgp_show_type_flap_neighbor,
+ bgp_show_type_dampend_paths,
+- bgp_show_type_damp_neighbor
++ bgp_show_type_damp_neighbor,
++ bgp_show_type_anomalous_paths
+ };
+
+ static int
+@@ -6262,11 +6300,17 @@ bgp_show_table (struct vty *vty, struct
+ || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
+ continue;
+ }
++ if (type == bgp_show_type_anomalous_paths)
++ {
++ if (! ANOMALOUS(ri->flags))
++ continue;
++ }
+
+ if (header)
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
++ vty_out (vty, BGP_SHOW_PCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ if (type == bgp_show_type_dampend_paths
+ || type == bgp_show_type_damp_neighbor)
+@@ -6344,6 +6388,7 @@ bgp_show (struct vty *vty, struct bgp *b
+ return bgp_show_table (vty, table, &bgp->router_id, type, output_arg);
+ }
+
++
+ /* Header of detailed BGP route information */
+ static void
+ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
+@@ -11904,6 +11949,64 @@ DEFUN (bgp_damp_set,
+ half, reuse, suppress, max);
+ }
+
++DEFUN (bgp_pgbgp_arg,
++ bgp_pgbgp_arg_cmd,
++ "bgp pgbgp <1-100> <1-100> <1-100> <1-365> <1-365> <1-365> WORD WORD",
++ "BGP Specific commands\n"
++ "Enable Pretty Good BGP\n"
++ "New origin depref time (in hours)\n"
++ "New edge depref time (in hours)\n"
++ "New sub-prefix depref time (in hours)\n"
++ "Origin history time (in days)\n"
++ "Prefix history time (in days)\n"
++ "Edge history time (in days)\n"
++ "Log file for history data\n"
++ "Log file of anomalies\n")
++{
++ struct bgp *bgp;
++
++ int ost = DEFAULT_ORIGIN_SUS;
++ int est = DEFAULT_EDGE_SUS;
++ int sst = DEFAULT_SUB_SUS;
++ int oht = DEFAULT_ORIGIN_HIST;
++ int pht = DEFAULT_PREFIX_HIST;
++ int eht = DEFAULT_EDGE_HIST;
++ const char* path = "/var/log/quagga/pgbgp_hist";
++ const char* anoms = "/var/log/quagga/pgbgp_anomalies";
++
++ if (argc == 8)
++ {
++ VTY_GET_INTEGER("origin depref time", ost, argv[0]);
++ VTY_GET_INTEGER("edge depref time", est, argv[1]);
++ VTY_GET_INTEGER("sub-prefix depref time", sst, argv[2]);
++ VTY_GET_INTEGER("origin history time", oht, argv[3]);
++ VTY_GET_INTEGER("prefix history time", pht, argv[4]);
++ VTY_GET_INTEGER("edge history time", eht, argv[5]);
++ path = argv[6];
++ anoms = argv[7];
++ }
++
++ bgp = vty->index;
++ return bgp_pgbgp_enable(bgp, bgp_node_afi (vty), bgp_node_safi (vty),
++ ost, est, sst, oht, pht, eht, path, anoms);
++}
++
++ALIAS (bgp_pgbgp_arg,
++ bgp_pgbgp_cmd,
++ "bgp pgbgp",
++ "BGP specific commands\n"
++ "Enable Pretty Good BGP\n")
++
++DEFUN (bgp_pgbgp_unset,
++ bgp_pgbgp_unset_cmd,
++ "no bgp pgbgp\n",
++ "BGP specific commands\n")
++{
++ struct bgp *bgp;
++ bgp = vty->index;
++ return bgp_pgbgp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty));
++}
++
+ ALIAS (bgp_damp_set,
+ bgp_damp_set2_cmd,
+ "bgp dampening <1-45>",
+@@ -11953,6 +12056,19 @@ DEFUN (show_ip_bgp_dampened_paths,
+ NULL);
+ }
+
++DEFUN (show_ip_bgp_anomalous_paths,
++ show_ip_bgp_anomalous_paths_cmd,
++ "show ip bgp anomalous-paths",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Display anomalous paths (less likely to be used)\n")
++{
++ return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_anomalous_paths,
++ NULL);
++}
++
++
+ DEFUN (show_ip_bgp_flap_statistics,
+ show_ip_bgp_flap_statistics_cmd,
+ "show ip bgp flap-statistics",
+@@ -12479,6 +12595,7 @@ bgp_route_init (void)
+ install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_anomalous_paths_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd);
+@@ -12612,6 +12729,7 @@ bgp_route_init (void)
+ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_anomalous_paths_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd);
+@@ -13002,6 +13120,10 @@ bgp_route_init (void)
+ install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd);
+ install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd);
+
++ install_element (BGP_NODE, &bgp_pgbgp_cmd);
++ install_element (BGP_NODE, &bgp_pgbgp_arg_cmd);
++ install_element (BGP_NODE, &bgp_pgbgp_unset_cmd);
++
+ /* Deprecated AS-Pathlimit commands */
+ install_element (BGP_NODE, &bgp_network_ttl_cmd);
+ install_element (BGP_NODE, &bgp_network_mask_ttl_cmd);
+--- a/bgpd/bgp_route.h
++++ b/bgpd/bgp_route.h
+@@ -1,3 +1,4 @@
++
+ /* BGP routing information base
+ Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro
+
+@@ -68,7 +69,7 @@ struct bgp_info
+ int lock;
+
+ /* BGP information status. */
+- u_int16_t flags;
++ u_int32_t flags;
+ #define BGP_INFO_IGP_CHANGED (1 << 0)
+ #define BGP_INFO_DAMPED (1 << 1)
+ #define BGP_INFO_HISTORY (1 << 2)
+@@ -82,6 +83,10 @@ struct bgp_info
+ #define BGP_INFO_COUNTED (1 << 10)
+ #define BGP_INFO_MULTIPATH (1 << 11)
+ #define BGP_INFO_MULTIPATH_CHG (1 << 12)
++#define BGP_INFO_SUSPICIOUS_O (1 << 13)
++#define BGP_INFO_SUSPICIOUS_P (1 << 14)
++#define BGP_INFO_IGNORED_P (1 << 15)
++#define BGP_INFO_SUSPICIOUS_E (1 << 16)
+
+ /* BGP route type. This can be static, RIP, OSPF, BGP etc. */
+ u_char type;
+@@ -126,7 +131,7 @@ struct bgp_static
+
+ /* Flags which indicate a route is unuseable in some form */
+ #define BGP_INFO_UNUSEABLE \
+- (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED)
++ (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED|BGP_INFO_IGNORED_P)
+ /* Macro to check BGP information is alive or not. Sadly,
+ * not equivalent to just checking previous, because of the
+ * sense of the additional VALID flag.
+--- a/bgpd/bgp_table.h
++++ b/bgpd/bgp_table.h
+@@ -65,6 +65,8 @@ struct bgp_node
+
+ int lock;
+
++ struct bgp_pgbgp_hist *hist;
++
+ u_char flags;
+ #define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
+ };
+--- a/bgpd/bgpd.h
++++ b/bgpd/bgpd.h
+@@ -123,6 +123,7 @@ struct bgp
+ /* BGP Per AF flags */
+ u_int16_t af_flags[AFI_MAX][SAFI_MAX];
+ #define BGP_CONFIG_DAMPENING (1 << 0)
++#define BGP_CONFIG_PGBGP (1 << 1)
+
+ /* Static route configuration. */
+ struct bgp_table *route[AFI_MAX][SAFI_MAX];
+--- a/lib/hash.c
++++ b/lib/hash.c
+@@ -166,6 +166,35 @@ hash_iterate (struct hash *hash,
+ }
+ }
+
++/*
++ Iterates until 0 is returned or until completion
++ Return: 1 if iteration completed
++ Return: 0 if iteration was interrupted
++*/
++
++int
++hash_iterate_until(struct hash *hash,
++ int (*func) (struct hash_backet *, void *), void *arg)
++{
++ unsigned int i;
++ struct hash_backet *hb;
++ struct hash_backet *hbnext;
++ int ret;
++
++ for (i = 0; i < hash->size; i++)
++ for (hb = hash->index[i]; hb; hb = hbnext)
++ {
++ /* get pointer to next hash backet here, in case (*func)
++ * decides to delete hb by calling hash_release
++ */
++ hbnext = hb->next;
++ ret = (*func) (hb, arg);
++ if (!ret)
++ return 0;
++ }
++ return 1;
++}
++
+ /* Clean up hash. */
+ void
+ hash_clean (struct hash *hash, void (*free_func) (void *))
+--- a/lib/hash.h
++++ b/lib/hash.h
+@@ -66,7 +66,8 @@ extern void *hash_release (struct hash *
+
+ extern void hash_iterate (struct hash *,
+ void (*) (struct hash_backet *, void *), void *);
+-
++extern int hash_iterate_until(struct hash *,
++ int (*) (struct hash_backet *, void *), void *);
+ extern void hash_clean (struct hash *, void (*) (void *));
+ extern void hash_free (struct hash *);
+
+--- a/lib/memtypes.c
++++ b/lib/memtypes.c
+@@ -148,6 +148,15 @@ struct memory_list memory_list_bgp[] =
+ { MTYPE_PEER_UPDATE_SOURCE, "BGP peer update interface" },
+ { MTYPE_BGP_DAMP_INFO, "Dampening info" },
+ { MTYPE_BGP_DAMP_ARRAY, "BGP Dampening array" },
++ { 0, NULL },
++ { MTYPE_BGP_PGBGP_ORIGIN, "BGP PGBGP Origin AS Node" },
++ { MTYPE_BGP_PGBGP_PREFIX, "BGP PGBGP Prefix AS Node" },
++ { MTYPE_BGP_PGBGP_EDGE, "BGP PGBGP Edge Node" },
++ { MTYPE_BGP_PGBGP_REUSE, "BGP PGBGP Reuse Node" },
++ { MTYPE_BGP_PGBGP_HIST, "BGP PGBGP History Node" },
++ { MTYPE_BGP_PGBGP_AVOID, "BGP PGBGP Avoid Peer Node" },
++ { MTYPE_BGP_PGBGP_PEER, "BGP PGBGP Peer Timing" },
++ { 0, NULL },
+ { MTYPE_BGP_REGEXP, "BGP regexp" },
+ { MTYPE_BGP_AGGREGATE, "BGP aggregate" },
+ { -1, NULL }
diff --git a/packages/qmp-quagga/patches/161-pgbgp-addon.patch b/packages/qmp-quagga/patches/161-pgbgp-addon.patch
new file mode 100644
index 0000000..817cdb0
--- /dev/null
+++ b/packages/qmp-quagga/patches/161-pgbgp-addon.patch
@@ -0,0 +1,318 @@
+From: Paul Jakma
+Date: Thu, 4 Sep 2008 22:27:13 +0000 (+0100)
+Subject: [bgp/pgbgp] Add some pgbgp commands to restricted-mode and other command tweaks
+X-Git-Url: http://git.ozo.com/?p=quagga-pgbg.git;a=commitdiff_plain;h=06ac72f9f6021635e9e1e5105c3e22bf7eb0d6c3
+
+[bgp/pgbgp] Add some pgbgp commands to restricted-mode and other command tweaks
+
+* bgp_pgbgp.c:
+ (edge_neighbor_iterator) make ASN==0 mean 'iterate over all ASNs'
+ (bgp_pgbgp_stats_origin_one) new function, to display one origin AS status.
+ (bgp_pgbgp_stats_origins) adapt to use previous.
+ Adapt to iterate over all stats if no prefix was giving.
+ (show_ip_bgp_pgbgp_neighbors_cmd) recognise no ASN argument case
+ (show_ip_bgp_pgbgp_neighbors_all_cmd) Iterate over all
+ (show_ip_bgp_pgbgp_origins_cmd) similar
+ (show_ip_bgp_pgbgp_origins_all_cmd)
+ (bgp_pgbgp_enable) install the lookup commands to ther new RESTRICTED_NODE
+* bgp_route.c:
+ (route_vty_short_status_out) only allowed to print one char for anomalous
+ status.
+ (route_vty_out_detail) Add support for printing out more detail on
+ PG-BGP status
+---
+
+--- a/bgpd/bgp_pgbgp.c
++++ b/bgpd/bgp_pgbgp.c
+@@ -227,7 +227,7 @@ static void
+ edge_neighbor_iterator (struct hash_backet *backet, struct nsearch *pns)
+ {
+ struct bgp_pgbgp_edge *hedge = backet->data;
+- if ((hedge->e.a == pns->asn || hedge->e.b == pns->asn)
++ if ((!pns->asn || hedge->e.a == pns->asn || hedge->e.b == pns->asn)
+ && hedge->e.a != hedge->e.b)
+ {
+ struct vty *vty = pns->pvty;
+@@ -254,13 +254,39 @@ bgp_pgbgp_stats_neighbors (struct vty *v
+ return CMD_SUCCESS;
+ }
+
++static void
++bgp_pgbgp_stats_origin_one (struct vty *vty, struct bgp_node *rn,
++ time_t t_now)
++{
++ char str[INET6_BUFSIZ];
++
++ if (!rn->hist)
++ return;
++
++ prefix2str (&rn->p, str, sizeof(str));
++ vty_out (vty, "%s%s", str, VTY_NEWLINE);
++
++ for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL;
++ cur = cur->next)
++ {
++ if (cur->deprefUntil > t_now)
++ vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS,
++ VTY_NEWLINE);
++ else
++ vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS,
++ VTY_NEWLINE);
++ }
++}
++
+ static int
+ bgp_pgbgp_stats_origins (struct vty *vty, afi_t afi, safi_t safi,
+ const char *prefix)
+ {
+ struct bgp *bgp;
+ struct bgp_table *table;
++ struct bgp_node *rn;
+ time_t t_now = time (NULL);
++
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ return CMD_WARNING;
+@@ -269,28 +295,22 @@ bgp_pgbgp_stats_origins (struct vty *vty
+ table = bgp->rib[afi][safi];
+ if (table == NULL)
+ return CMD_WARNING;
+-
+- struct prefix p;
+- str2prefix (prefix, &p);
+- struct bgp_node *rn = bgp_node_match (table, &p);
+- vty_out (vty, "%s%s", prefix, VTY_NEWLINE);
+- if (rn)
++
++ if (prefix)
+ {
++ struct prefix p;
++ str2prefix (prefix, &p);
++ rn = bgp_node_match (table, &p);
+ if (rn->hist)
+- {
+- for (struct bgp_pgbgp_origin * cur = rn->hist->o; cur != NULL;
+- cur = cur->next)
+- {
+- if (cur->deprefUntil > t_now)
+- vty_out (vty, "Untrusted Origin AS: %d%s", cur->originAS,
+- VTY_NEWLINE);
+- else
+- vty_out (vty, "Trusted Origin AS: %d%s", cur->originAS,
+- VTY_NEWLINE);
+- }
+- }
++ bgp_pgbgp_stats_origin_one (vty, rn, t_now);
+ bgp_unlock_node (rn);
++ return CMD_SUCCESS;
+ }
++
++ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
++ if (rn->hist)
++ bgp_pgbgp_stats_origin_one (vty, rn, t_now);
++
+ return CMD_SUCCESS;
+ }
+
+@@ -377,7 +397,7 @@ bgp_pgbgp_stats (struct vty *vty, afi_t
+ DEFUN (show_ip_bgp_pgbgp,
+ show_ip_bgp_pgbgp_cmd,
+ "show ip bgp pgbgp",
+- SHOW_STR IP_STR BGP_STR "Display PGBGP statistics\n")
++ SHOW_STR IP_STR BGP_STR "Pretty-Good BGP statistics\n")
+ {
+ return bgp_pgbgp_stats (vty, AFI_IP, SAFI_UNICAST);
+ }
+@@ -385,29 +405,46 @@ DEFUN (show_ip_bgp_pgbgp,
+ DEFUN (show_ip_bgp_pgbgp_neighbors,
+ show_ip_bgp_pgbgp_neighbors_cmd,
+ "show ip bgp pgbgp neighbors WORD",
+- SHOW_STR
+- IP_STR
+- BGP_STR
+- "BGP pgbgp\n"
+- "BGP pgbgp neighbors\n" "ASN whos neighbors should be displayed\n")
++ SHOW_STR IP_STR BGP_STR
++ "Pretty-Good BGP statistics\n"
++ "PG-BGP neighbor information\n"
++ "AS to show neighbors of\n")
+ {
+ return bgp_pgbgp_stats_neighbors (vty, AFI_IP, SAFI_UNICAST,
+- atoi (argv[0]));
++ argc == 1 ? atoi (argv[0]) : 0);
+ }
+
++ALIAS (show_ip_bgp_pgbgp_neighbors,
++ show_ip_bgp_pgbgp_neighbors_all_cmd,
++ "show ip bgp pgbgp neighbors",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Pretty-Good BGP statistics\n"
++ "PG-BGP neighbors information\n")
++
+ DEFUN (show_ip_bgp_pgbgp_origins,
+ show_ip_bgp_pgbgp_origins_cmd,
+ "show ip bgp pgbgp origins A.B.C.D/M",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+- "BGP pgbgp\n"
+- "BGP pgbgp neighbors\n" "Prefix to look up origin ASes of\n")
++ "Pretty-Good BGP statistics\n"
++ "PG-BGP prefix origin information\n"
++ "Prefix to look up origin ASes of\n")
+ {
+- return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST, argv[0]);
++ return bgp_pgbgp_stats_origins (vty, AFI_IP, SAFI_UNICAST,
++ argc == 1 ? argv[0] : NULL);
+ }
+
+-
++ALIAS (show_ip_bgp_pgbgp_origins,
++ show_ip_bgp_pgbgp_origins_all_cmd,
++ "show ip bgp pgbgp origins",
++ SHOW_STR
++ IP_STR
++ BGP_STR
++ "Pretty-Good BGP statistics\n"
++ "PG-BGP prefixes origin information")
+
+
+ /*! --------------- VTY (others exist in bgp_route.c) ------------------ !*/
+@@ -749,12 +786,19 @@ bgp_pgbgp_enable (struct bgp *bgp, afi_t
+ pgbgp->lastgc = time (NULL);
+ pgbgp->lastStore = time (NULL);
+ pgbgp->startTime = time (NULL);
++ install_element (RESTRICTED_NODE, &show_ip_bgp_pgbgp_cmd);
++ install_element (RESTRICTED_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
++ install_element (RESTRICTED_NODE, &show_ip_bgp_pgbgp_origins_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_cmd);
+- install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
+- install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_neighbors_all_cmd);
++ install_element (VIEW_NODE, &show_ip_bgp_pgbgp_origins_all_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_neighbors_all_cmd);
++ install_element (ENABLE_NODE, &show_ip_bgp_pgbgp_origins_all_cmd);
+ pgbgp->edgeT = hash_create_size (131072, edge_key_make, edge_cmp);
+ bgp_pgbgp_restore ();
+ return 0;
+--- a/bgpd/bgp_route.c
++++ b/bgpd/bgp_route.c
+@@ -5581,20 +5581,6 @@ enum bgp_display_type
+ static void
+ route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo)
+ {
+- if (ANOMALOUS(binfo->flags))
+- {
+- vty_out(vty, "a[");
+- if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
+- vty_out(vty, "i");
+- if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
+- vty_out(vty, "p");
+- if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
+- vty_out(vty, "e");
+- if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
+- vty_out(vty, "s");
+- vty_out(vty, "] ");
+- }
+-
+ /* Route status display. */
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED))
+ vty_out (vty, "R");
+@@ -5610,6 +5596,17 @@ route_vty_short_status_out (struct vty *
+ /* Selected */
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+ vty_out (vty, "h");
++ else if (ANOMALOUS(binfo->flags))
++ {
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
++ vty_out(vty, "p");
++ else if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
++ vty_out(vty, "P");
++ else if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
++ vty_out(vty, "a");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
++ vty_out(vty, "a");
++ }
+ else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+ vty_out (vty, "d");
+ else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
+@@ -6088,7 +6085,22 @@ route_vty_out_detail (struct vty *vty, s
+ if (binfo->extra && binfo->extra->damp_info)
+ bgp_damp_info_vty (vty, binfo);
+
+- /* Line 7 display Uptime */
++ /* 8: PGBGP status */
++ if (ANOMALOUS(binfo->flags))
++ {
++ vty_out (vty, " Anomalous:");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_P))
++ vty_out (vty, " divergent sub-prefixes,");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_O))
++ vty_out (vty, " origin AS (prefix hijack?),");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_SUSPICIOUS_E))
++ vty_out (vty, " new edge in path,");
++ if (CHECK_FLAG(binfo->flags, BGP_INFO_IGNORED_P))
++ vty_out (vty, " origin AS (sub-prefix hijack?),");
++ vty_out (vty, "%s", VTY_NEWLINE);
++ }
++
++ /* Line 9 display Uptime */
+ #ifdef HAVE_CLOCK_MONOTONIC
+ tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
+ vty_out (vty, " Last update: %s", ctime(&tbuf));
+@@ -6099,8 +6111,9 @@ route_vty_out_detail (struct vty *vty, s
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+-#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale, R Removed%s"
+-#define BGP_SHOW_PCODE_HEADER "Status code: a (anomalous) of: [p] prefix hijack, [s] sub-prefix hijack,%s [i] informant of sub-prefix [e] new edge%s"
++#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s" \
++ " r RIB-failure, S Stale, R Removed, %s" \
++ " p prefix hijack, P sub-prefix hijack, a other anomaly%s"
+ #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
+ #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
+ #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s"
+@@ -6309,8 +6322,7 @@ bgp_show_table (struct vty *vty, struct
+ if (header)
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);
+- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+- vty_out (vty, BGP_SHOW_PCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
++ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ if (type == bgp_show_type_dampend_paths
+ || type == bgp_show_type_damp_neighbor)
+@@ -9842,7 +9854,7 @@ show_adj_route (struct vty *vty, struct
+ PEER_STATUS_DEFAULT_ORIGINATE))
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
++ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+
+ vty_out (vty, "Originating default network 0.0.0.0%s%s",
+@@ -9859,7 +9871,7 @@ show_adj_route (struct vty *vty, struct
+ if (header1)
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
++ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ header1 = 0;
+ }
+@@ -9883,7 +9895,7 @@ show_adj_route (struct vty *vty, struct
+ if (header1)
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
+- vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
++ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ header1 = 0;
+ }
diff --git a/packages/qmp-quagga/patches/170-use-supported-pagers.patch b/packages/qmp-quagga/patches/170-use-supported-pagers.patch
new file mode 100644
index 0000000..d42e145
--- /dev/null
+++ b/packages/qmp-quagga/patches/170-use-supported-pagers.patch
@@ -0,0 +1,29 @@
+--- a/vtysh/vtysh.c
++++ b/vtysh/vtysh.c
+@@ -269,7 +269,7 @@ vtysh_pager_init (void)
+ if (pager_defined)
+ vtysh_pager_name = strdup (pager_defined);
+ else
+- vtysh_pager_name = strdup ("more");
++ vtysh_pager_name = strdup ("cat");
+ }
+
+ /* Command execution over the vty interface. */
+@@ -1885,7 +1885,7 @@ DEFUN (vtysh_terminal_length,
+ {
+ int lines;
+ char *endptr = NULL;
+- char default_pager[10];
++ char default_pager[12];
+
+ lines = strtol (argv[0], &endptr, 10);
+ if (lines < 0 || lines > 512 || *endptr != '\0')
+@@ -1902,7 +1902,7 @@ DEFUN (vtysh_terminal_length,
+
+ if (lines != 0)
+ {
+- snprintf(default_pager, 10, "more -%i", lines);
++ snprintf(default_pager, 12, "head -n %i", lines);
+ vtysh_pager_name = strdup (default_pager);
+ }
+
--
2.30.2