]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
Initial revision
authorMichael Brown <mcb30@etherboot.org>
Tue, 17 May 2005 16:44:57 +0000 (16:44 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 17 May 2005 16:44:57 +0000 (16:44 +0000)
164 files changed:
COPYING [new file with mode: 0644]
Copyrights [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LOG [new file with mode: 0644]
RELNOTES [new file with mode: 0644]
VERSION [new file with mode: 0644]
contrib/3c90xutil/Makefile [new file with mode: 0644]
contrib/3c90xutil/README [new file with mode: 0644]
contrib/3c90xutil/bromutil.c [new file with mode: 0644]
contrib/3c90xutil/cromutil.c [new file with mode: 0644]
contrib/3c90xutil/romutil.txt [new file with mode: 0644]
contrib/Diskless-From-NT/Config.txt [new file with mode: 0644]
contrib/Diskless-From-NT/Diskless-From-NT.txt [new file with mode: 0644]
contrib/Diskless-From-NT/furtmayr.html [new file with mode: 0644]
contrib/auto-default/mail [new file with mode: 0644]
contrib/auto-default/main.c.patch [new file with mode: 0644]
contrib/award_plugin_roms/README [new file with mode: 0644]
contrib/award_plugin_roms/award_plugin_roms.pl [new file with mode: 0755]
contrib/baremetal/Makefile [new file with mode: 0644]
contrib/baremetal/main.c [new file with mode: 0644]
contrib/baremetal/marini.txt [new file with mode: 0644]
contrib/baremetal/misc.c [new file with mode: 0644]
contrib/baremetal/startmpcc.S [new file with mode: 0644]
contrib/bin2intelhex/Makefile [new file with mode: 0644]
contrib/bin2intelhex/bin2intelhex.c [new file with mode: 0644]
contrib/bin2intelhex/bin2intelhex.c.simple [new file with mode: 0644]
contrib/bochs/.cvsignore [new file with mode: 0644]
contrib/bochs/Makefile [new file with mode: 0644]
contrib/bochs/README [new file with mode: 0644]
contrib/bochs/bochsrc.txt [new file with mode: 0644]
contrib/bochs/ifup.tun [new file with mode: 0755]
contrib/bochs/serial-console [new file with mode: 0755]
contrib/bochs/serial-console.1 [new file with mode: 0644]
contrib/bootptodhcp/bootptodhcp.pl [new file with mode: 0755]
contrib/compressor/COPYING [new file with mode: 0644]
contrib/compressor/algorithm.doc [new file with mode: 0644]
contrib/compressor/loader.h [new file with mode: 0644]
contrib/compressor/lzhuf.c [new file with mode: 0644]
contrib/dhcpdconfeg/dhcpd.conf [new file with mode: 0644]
contrib/dhcpdconfeg/vendorclassid.txt [new file with mode: 0644]
contrib/dhcpid/dhcpid.txt [new file with mode: 0644]
contrib/eepro100notes/flash-1.txt [new file with mode: 0644]
contrib/eepro100notes/flash-2.txt [new file with mode: 0644]
contrib/eepro100notes/flash-3.txt [new file with mode: 0644]
contrib/flashimg/Makefile [new file with mode: 0644]
contrib/flashimg/flashimg.asm [new file with mode: 0644]
contrib/flashimg/flashimg.img [new file with mode: 0644]
contrib/hdload/Makefile [new file with mode: 0644]
contrib/hdload/hdload.S [new file with mode: 0644]
contrib/hdload/petr.msg [new file with mode: 0644]
contrib/initrd/ChangeLog [new file with mode: 0644]
contrib/initrd/Makefile [new file with mode: 0644]
contrib/initrd/Manifest [new file with mode: 0644]
contrib/initrd/README [new file with mode: 0644]
contrib/initrd/dhcpd.conf.etherboot.include [new file with mode: 0644]
contrib/initrd/include-modules [new file with mode: 0755]
contrib/initrd/linux-wlan.cfg [new file with mode: 0644]
contrib/initrd/linuxrc [new file with mode: 0644]
contrib/initrd/mkinitrd-net [new file with mode: 0755]
contrib/initrd/mkinitrd-net.spec [new file with mode: 0644]
contrib/initrd/mknbi-set [new file with mode: 0755]
contrib/initrd/mknbi-set.conf [new file with mode: 0644]
contrib/initrd/script.c.patch [new file with mode: 0644]
contrib/initrd/udhcpc-post [new file with mode: 0644]
contrib/linux-2.0-transname.lsm [new file with mode: 0644]
contrib/linux-3c503-patch/3c503.patch [new file with mode: 0644]
contrib/linux-3c503-patch/README [new file with mode: 0644]
contrib/mini-slamd/COPYING [new file with mode: 0644]
contrib/mini-slamd/Makefile [new file with mode: 0644]
contrib/mini-slamd/mini-slamd.c [new file with mode: 0644]
contrib/mkQNXnbi/Makefile [new file with mode: 0644]
contrib/mkQNXnbi/README [new file with mode: 0644]
contrib/mkQNXnbi/examples/bootptab [new file with mode: 0644]
contrib/mkQNXnbi/examples/ws.etherboot [new file with mode: 0644]
contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly [new file with mode: 0644]
contrib/mkQNXnbi/mkQNXnbi.c [new file with mode: 0644]
contrib/mkffwnb/2.0.10/linuxrc [new file with mode: 0755]
contrib/mkffwnb/Extendinitrd.pm [new file with mode: 0644]
contrib/mkffwnb/README [new file with mode: 0644]
contrib/mkffwnb/mkffwnb.pl [new file with mode: 0755]
contrib/mklrpnb/README.txt [new file with mode: 0644]
contrib/mklrpnb/extractdach.pl [new file with mode: 0644]
contrib/mklrpnb/mklrpnb [new file with mode: 0755]
contrib/mntnbi/mntnbi.pl [new file with mode: 0755]
contrib/nfs-swap/README [new file with mode: 0644]
contrib/p910nd-0.8/Makefile [new file with mode: 0644]
contrib/p910nd-0.8/banner.pl [new file with mode: 0755]
contrib/p910nd-0.8/client.pl [new file with mode: 0755]
contrib/p910nd-0.8/p910nd.8 [new file with mode: 0644]
contrib/p910nd-0.8/p910nd.c [new file with mode: 0644]
contrib/p910nd-0.8/p910nd.sh [new file with mode: 0755]
contrib/ppmtoansi/Makefile [new file with mode: 0644]
contrib/ppmtoansi/demo/dos.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/dos.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/dos.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/etherboot.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/etherboot.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/etherboot.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/flash.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/flash.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/flash.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/floppy.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/floppy.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/floppy.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/hd.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/hd.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/hd.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/ibmmap.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/ibmmap.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/linux-logo.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/linux-logo.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/linux-logo.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/make-ansi.sh [new file with mode: 0755]
contrib/ppmtoansi/demo/text.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/text.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/text.xpm [new file with mode: 0644]
contrib/ppmtoansi/demo/x.ansi [new file with mode: 0644]
contrib/ppmtoansi/demo/x.ppm [new file with mode: 0644]
contrib/ppmtoansi/demo/x.xpm [new file with mode: 0644]
contrib/ppmtoansi/ppmtoansi.c [new file with mode: 0644]
contrib/ppmtoansi/ppmtoansi.man [new file with mode: 0644]
contrib/rom-scan/Makefile [new file with mode: 0644]
contrib/rom-scan/rom-scan.c [new file with mode: 0644]
contrib/romid/pktdrv.bat [new file with mode: 0644]
contrib/romid/readme [new file with mode: 0644]
contrib/romid/romid.c [new file with mode: 0644]
contrib/romid/setenvs.c [new file with mode: 0644]
contrib/smc9462tx-flash/Makefile [new file with mode: 0644]
contrib/smc9462tx-flash/README [new file with mode: 0644]
contrib/smc9462tx-flash/dp83820_write.c [new file with mode: 0644]
contrib/smc9462tx-flash/dp83820flash.c [new file with mode: 0644]
contrib/t2hproxy/README [new file with mode: 0644]
contrib/t2hproxy/T2hproxy.java [new file with mode: 0644]
contrib/t2hproxy/build.xml [new file with mode: 0644]
contrib/t2hproxy/runT2proxy.sh [new file with mode: 0755]
contrib/t2hproxy/t2hproxy.pl [new file with mode: 0755]
contrib/t2hproxy/t2hproxy.xinetd [new file with mode: 0644]
contrib/tftp/Makefile [new file with mode: 0644]
contrib/tftp/README [new file with mode: 0644]
contrib/tftp/arpa/tftp.h [new file with mode: 0644]
contrib/tftp/main.c [new file with mode: 0644]
contrib/tftp/tftp.1 [new file with mode: 0644]
contrib/tftp/tftp.c [new file with mode: 0644]
contrib/tftp/tftpd.8 [new file with mode: 0644]
contrib/tftp/tftpd.c [new file with mode: 0644]
contrib/tftp/tftpsubs.c [new file with mode: 0644]
contrib/tomsrtbt/tomsrtbt-net.txt [new file with mode: 0644]
contrib/wakeonlan/Makefile [new file with mode: 0644]
contrib/wakeonlan/README [new file with mode: 0644]
contrib/wakeonlan/maclist.txt [new file with mode: 0644]
contrib/wakeonlan/mp-form.pl [new file with mode: 0644]
contrib/wakeonlan/mp-form.txt [new file with mode: 0644]
contrib/wakeonlan/mp-form1.pl [new file with mode: 0644]
contrib/wakeonlan/readme.txt [new file with mode: 0644]
contrib/wakeonlan/wake.pl [new file with mode: 0644]
contrib/wakeonlan/wakeserver.patch [new file with mode: 0644]
contrib/wakeonlan/wakeup.pl [new file with mode: 0644]
contrib/wakeonlan/wakeup.txt [new file with mode: 0644]
contrib/wakeonlan/wol.c [new file with mode: 0644]
eb.png [new file with mode: 0644]
index-berlios.html [new file with mode: 0644]
index.html [new file with mode: 0644]
index.xhtml [new file with mode: 0644]
style.css [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Copyrights b/Copyrights
new file mode 100644 (file)
index 0000000..8de2acb
--- /dev/null
@@ -0,0 +1,20 @@
+Unless specifically noted, a file is under the GPL.  GPLed files are in
+general either from Linux or have been explicitly put under GPL by the
+authors.  A few files are inherited from FreeBSD netboot and therefore
+can be used under BSD or GPL.
+
+File                           Copyright status
+
+core/misc.c                    BSD
+drivers/net/3c509.c            BSD
+drivers/net/3c509.h            BSD
+drivers/net/3c595.c            BSD
+drivers/net/3c595.h            BSD
+drivers/net/3c90x.c            Open Source
+drivers/net/epic100.c          None
+drivers/net/epic100.h          None
+drivers/net/ns8390.c           BSD
+drivers/net/ns8390.h           BSD
+drivers/net/tulip.c            BSD
+arch/i386/include/bits/string.h        None
+util/lzhuf.c                   Open Source
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..720aa03
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,28 @@
+If you don't want to install development tools, and have access to the
+Web, you can get ROM images made on demand from http://rom-o-matic.net/
+
+The documentation tarballs should be extracted in the top directory (the
+one you are reading this INSTALL document from). A top directory called
+doc will be populated. This way the links from index.html will work
+properly.
+
+More likely if you are unfamiliar with Etherboot you should read the
+documentation starting with index.html if you have a Web browser, or
+doc/text/userman.txt (after installing the documentation tarball) if you
+just have a plain text terminal.
+
+Also read RELNOTES for any additional recent information.
+
+Don't forget to check out the contrib/ directory which contains much
+contributed software and documentation. Please contact the authors of
+those packages directly for queries.
+
+If you are booting FreeBSD, enable -DELF_IMAGE (and optionally
+-DAOUT_IMAGE) in Config. This should happen automatically now.
+
+The index.html file is the same as the one on the Etherboot home page at
+the time the distribution was made. Therefore some of the local file:/
+links from the Distribution section may not work.
+
+Etherboot was built using gcc 3.3.3 and binutils 2.15.91 from SuSE 9.2 but
+earlier 3.x versions will generally work.
diff --git a/LOG b/LOG
new file mode 100644 (file)
index 0000000..79ad4c0
--- /dev/null
+++ b/LOG
@@ -0,0 +1,2863 @@
+Major changes from 1.0 to 1.1
+
++ Everywhere: Can compile two versions of the code, under gcc or bcc
+(Bruce Evan's cc), so that 16-bit boot PROMs can be made. See
+netboot-16/README.16 for more details.
+
++ Everywhere: Removed duplicate defines, e.g. everybody defined their
+own ID for ethernet address size (6). Put IDs for magic numbers in
+various places.  Still some inconsistency, ETH_ and ETHER_ are used.
+
++ Everywhere: Added prototypes of functions to netboot.h.  Removed
+unused variables.
+
++ Makefiles: Rewritten.
+
++ netboot.h: Added define for TFTP_MAX_PACKET = 512. Increased TIMEOUT
+for tftp packets to 180 (about 10 seconds) so that tftp servers would
+be able to retransmit blocks.
+
++ main.c: Rewrote tftp(). Original was intended to get only one block
+and the strain on the structure due to modifications was showing.
+Increased config_buffer size to TFTP_MAX_PACKET+1 to avoid special
+casing data length=512.
+
++ linuxloader.c: Cleaned up the code in some places, especially
+linux_tftp.  Moved the bootp reply block into bss space instead of a
+fixed location such as 0x90000.
+
++ ns8390.c: Removed one bug regarding packet length. packetlen was
+wrongly shortened when packets wraparound the ring buffer.
+
++ 3c509.c: Changed some of the gotos to returns.  Removed ARP code since
+that's already done elsewhere.  Removed interrupt enable and Rx early
+notification (we can't do anything with the packet until it's complete
+anyway).
+
+Major changes from 1.1 to 1.2
+
++ Small bug in makerom.c. Extra semicolon shortened for loop and made
+double checking code invalid.
+
++ Added version identification to startup string.
+
++ Gathered external declarations into netboot.h.
+
++ New compile time option for netboot-32. If INT19H is not defined,
+then boot ROM takes control as soon as BIOS scans it. This may solve
+the problem of some BIOSes not calling the boot ROM at INT19H. This
+may be when disks are detected by the BIOS, i.e. the machine is not
+truly diskless.
+
++ Added a new program, test.c, for making test ROMs to verify that
+the BIOS recognises the ROM.
+
++ New directory contrib contains contributed code. Currently contains
+masq by Gerd Knorr: make a boot floppy without DOS
+comboot-1.0 by Adam J. Richter: also make a boot floppy without DOS.
+
++ New mknbi-1.4 from Gero Kuhlmann and Markus Gutschke. This one handles
+the new bzImage format.
+
+Bumped up version to 2.0 because we are so listed in the Linux 2.0
+distribution and this would avoid confusion.
+
+Major changes from 2.0 to 2.1
+
++ Added LSM for transname-patch to contrib.
+
++ Added patch for serial console from Claus Heine
+<claus AT momo PERIOD math PERIOD rwth-aachen PERIOD de>.
+
++ Claus Heine contributed patches to the 2.0.21/22 kernel sources to
+allow NFS swap.
+
++ Markus Gutschke provided fixes to start2.S so that main can return to
+the ROM code if user doesn't want to ROM boot.
+
++ Added code to main.c to timeout on the prompt and assume Y or N
+for the answer. Timeout and answer configurable.
+
++ Made NE1/2000 probe addresses configurable from Makefile. Fixed up
+autoscan code.
+
++ Made NFS_BOOT a configurable option. By undefining it, only tagged
+file load is supported but ROMs are under 8k.
+
++ ROMSIZE is not used by makerom now. -s flag controls size of ROM
+at runtime.  So don't need to recompile makerom if ROMSIZE changes.
+
++ Updated netboot-16 for the latest dev tools from the Linux-MT
+project. Use the size.c from there.
+
++ Got rid of _main() in main.c, instead using #ifdef ELF in start2.S.
+ELF is preferred now anyway.
+
++ Changed bcompare to standard bcmp and reversed sense of result.
+Reason: to use standard library if available, e.g. Netboot-16.
+
++ Common Makefile for 32 bit and 16 versions, with differences in
+Config files.
+
+Major changes from 2.1 to 2.2
+
++ New device driver for the Crystal Semiconductor CS89x0 chipset family.
+  (because of legal problems, this code is currently in the "contrib"
+  directory.)
+
++ Added support for loading BOOTP extension files (c.f. RFC1533).
+
++ If we have to go thru a gateway, then use the one that has been used for
+  the BOOTP daemon. If the BOOTP daemon is directly accessible, then use
+  the first entry in the "gw" gateway list instead.
+
++ For all retries, back off according to RFC951 by randomizing the timeouts
+  and exponentially increasing them until an average of one minute is
+  reached.
+
++ Warn if code will not fit into chosen ROM size. Happens only if the
+  autosizing in the Makefile somehow fails.
+
++ Modified the code for enabling the A20 gate; this could increase
+  compatibility, but I still have to hear from users.
+
++ The copyright message will now reflect, which features have been
+  enabled at compile time.
+
++ Added support for selecting different boot images from a menu. As a side
+  effect, this can be used to upgrade the ROM without having to burn a new
+  image (c.f. README.VendorTags).
+
++ Display a "message of the day" that is provided by the BOOTP daemon.
+
++ The sanity check for detecting a Linux kernel was too strong to properly
+  recognize a 2.1.x kernel; this has been fixed.
+
++ Trys to negotiate for 1432 octect blocks, if the TFTP daemon knows
+  about RFC1783.
+
++ We can optionally boot from local disk, if the BOOTP server cannot
+  be contacted.
+
++ Restructured directories: got rid of netboot-freebsd to reduce confusion
+  with Gero Kuhlmann's netboot, moved documentation to doc and renamed
+  directories to be more in line with Unix conventions. Edited documentation.
+
++ Created a dispatch table for NIC routines so that we can include one
+  or more drivers in one binary. Renamed all entry points in the driver
+  sources. Created two new files, config.c, which holds the dispatch
+  table and can be conditionally compiled; and nic.c which contains the
+  extern variables referenced by the drivers.
+
++ Automatically decide what size ROM is needed by doing a size and then
+  choosing the correct startup object. Currently caters for 8k, 16k and
+  32k ROMs.
+
++ Optionally include a simple interpreter for ANSI escape sequences. This
+  allows for fancier boot menus.
+
++ Remove patches directory which is mostly relevant to 1.x kernels only.
+  Everybody should use 2.x kernels now. If for some reason you need those
+  patches, get an older release of etherboot.
+
++ Fix Makefile to work even if . not on PATH.
+
++ Sadly, 32 bit ROMs are now > 8kb. We will try to reduce the size by
+  conditionals in a later release. For now, use version 2.1 if your NIC
+  won't take > 8kb ROMs.
+
++ Release as 3.0b1 because of the large amount of changes.
+
++ Fixed a few problems with the code for ANSI escape sequences and
+  added optional support for displaying graphics.
+
++ Optional support for password protected boot images.
+
++ Optional support for booting from block devices (floppy, hd).
+
++ The bootp server can pass additional parameters to the loaded kernel
+  image (currently, this only  applies to Linux)  and the user can  be
+  allowed to edit a commandline; the latter is optionally protected by
+  a password scheme.
+
++ Set the warm-boot flag when the main routine is entered.
+
++ Release as 3.0b2
+
++ Added code for updating the FlashCard EPROM over the network
+  (contrib/flashimg).
+
++ Added very simple code for turning a ROM image into a network loadable image.
+  This is useful for debugging, but some users without flash EPROMs might
+  appreciate the possibility to load a fully fledged image from a very basic
+  configuration.
+
++ Optional support for compressing the ROM images. Please read
+  doc/COPYING.compressor before using this feature.
+
++ Sync'd our source tree with Gero's netboot-0.5; this means that you now need
+  the as86 from the ELKs project in order to recompile all of the files. This
+  should not affect normal usage, though.
+
++ Added "mknbi-blkdev" for booting from local block devices.
+
++ Fixed some bugs in ppmtoansi.c and bootmenu.c
+
++ Renamed reference compressor implementation to compressor.exp otherwise
+  make tries to use it and it should not be turned on by default.
+
++ Zero'ing BSS in 16-bit version has to be done to _end, not to A0000
+  because it's executing in a segment, not in flat address space in 16
+  bit mode.
+
++ Ken Yap contributed a quick and dirty Perl script for people who use
+  netboot to test ELKS.  So far I'm the only one I know of; maybe the
+  others are silent. :-(
+
++ Release as 3.0
+
+Major changes from 3.0 to 3.1
+
++ 4 versions of etherboot can be built for a NIC: .com for testing and
+  .rom for burning into EPROM, and corresponding compressed versions:
+  .lzcom and .lzrom.
+
++ The loaders are now separate programs which are prepended to the
+  etherboot binary. This allows them (plain and uncompressing versions) to
+  be maintained separately and gives a bit more RAM to the etherboot code.
+
++ No need to define ROMSIZE in the build. makerom automatically discovers
+  the ROM size needed and fills in the size field in the ROM. This
+  simplifies the build procedure.
+
++ 16 bit versions use the same loaders as the 32 bit version. Also fixed
+  two bugs in the 16 bit versions: (1) a non-8086 instruction in zloader,
+  (2) setting warm-boot flag in main which zapped some code.
+
++ Fixed a documentation bug on the ANSI escape sequences.
+
++ Include netboot-0.5.3 distribution from Gero Kuhlmann.
+
++ Included some contributions from Dickon.Reed AT cl PERIOD cam PERIOD
+ac PERIOD uk: Running display of Kbytes loaded, line of delimiters after
+loading complete, a temporary hack to address timing problems with the
+3C509, and some Makefile cleanup. The first two changes need to be
+enabled in Config with defines.
+
++ mknbi-blkdev seems to have been left out by Gero Kuhlmann. Add to
+  contrib directory. You probably have to make a symlink to it from
+  the netboot-0.5.2 directory.
+
++ Release as 3.1
+
+Major changes from 3.1 to 3.2
+
++ 16 bit version now can load to extended memory, if it exists. On
+  a 8086/8 this will silently fail.
+
++ Cleaned up interface between main body of code and NIC drivers. No
+  global variables referenced in NIC driver, everything is passed
+  through a structure. Only the probe function is visible outside,
+  pointers to the others are returned in the structure.
+
++ Implemented autoprobe for 3c503. Also simplifies code at same time.
+
++ Removed ARP response code in ns8390.c. Don't think we need to respond
+  to ARP requests because other machines will do gratuituous ARP when
+  boot code sends out bootp request. Are there cases where this is not
+  true? Gateways?
+
++ Added 1 second timeout to routine that clears the keyboard buffer
+  in case there is no keyboard.
+
++ Added a skeleton driver that can be used as a template for new NIC
+  drivers.
+
++ ./lzhuf in Makefile so that it will run even if . is not on path.
+
++ Fixed comboot to work on 286s also. Won't work yet on 8086/8.
+
++ Fixed mknbi-blkdev to configure properly under netboot-0.7.
+
++ Added David Munro's PCI code adapted from Linux. Currently has entries
+  for PCI NE2000 clones. Generalised it to probe other PCI cards later on.
+
++ Moved twiddle() outside NIC driver except where used to provide a delay.
+
++ Fixed bug in Makefile spotted by Ton Biegstraaten. Should prepend
+  ZLOADER to make all.lzcom, not LOADER.
+
++ Charlie Brady donated a NE2100 (LANCE) card, so Ken Yap wrote a driver
+  for it. Should work for other LANCE (7990, etc) based cards with some
+  modifications.
+
++ Markus Gutschke wrote rom-scan, and it is in contrib/.
+
++ Hack rom-scan.c so that a DOS version can be compiled.
+
++ Removed all.* targets from Makefile. The NIC specific loaders should be
+  used in preference as the all.* loaders can run out of memory.
+
++ Added a disable routine to dispatch table so that cards can be turned
+  off before the loaded code is executed.
+
++ Make INT19H the default.
+
++ Rogier Wolff persuaded AW computer systems to contribute the Intel
+  EtherExpressPro 100 driver. The binary to hex converter in contrib/
+  is also from Rogier Wolff. Part of the work is sponsored by BitWizard
+  NL (www.bitwizard.nl).
+
++ Distribute with a subset of netboot-0.7.2 that doesn't have the bootrom
+  portion.
+
++ Release as 3.2.
+
+Major changes from 3.2 to 4.0
+
++ Merged in Vlad Lungu's patches for DHCP support, ifdef'ed by DHCP_SUPPORT.
+
++ XID matching fix also provided by Vlad Lungu.
+
++ Merged in William Arbaugh's patches to make eepro driver work properly.
+
++ Add to contrib/ better bin2intelhex from Jean Marc Lacroix.
+
++ Patches from Jim Hague (thanks!) for the following:
+
+* Added PIO mode for 3c503 to ns8390.c. Changed the card detection to
+  detect shared memory or PIO and use the selected one, and removed
+  a jumper check that failed on the Bull (no jumpers).
+
+* Added more #ifdefs to ns8390.c to include only code relevant to the
+  card being compiled, and removed unnecessary run-time card vendor
+  behaviour branches - it's all now #ifdefd.
+
+* Added a -3 parameter to makerom to set the last two bytes to 0x80.
+  These are the values they have in the 3Com Etherboot image that was
+  in the Bull. (Also on the 3c503 card I have - Ken.) Also altered the
+  Makefile to add this parameter when building a 3c503 image.
+
+* Modifies lzhuf.c, objdump86.c & size86.c to work on either-endian systems.
+
+* Adds a -DT503_AUI config paramter to let you choose AUI or BNC on
+  3c503s.  Previously it defaulted to AUI, and you had to change the
+  code to alter it.
+
+* Changed the BCC include directory to /usr/bcc/include. If you use the
+  BCC include files they don't define u_char, u_short etc. I've added
+  these into linuxdef.h, ifdef'd on BCC.
+
+* Adds a trivial Linux 3c503 driver patch to the contrib directory
+  to let it spot these 'ere Bull things.
+
++ Charlie Brady confirmed that the Lance driver works with PCI so there
+is a new lancepci driver now.
+
++ Removed support for NFS_BOOT; only TFTP booting supported now.
+
++ Removed support for linear images; only tagged images supported now.
+
++ Removed PRIORIZEBOOTPKERNEL and BOOTPKERNELONLY. Bootp reply must
+specify kernel name.
+
++ Bug fix for 16 bit version of 3c509 driver: sign bit propagation bug.
+
++ Revert to non-pausing versions of out[bw] and inb for NEx000 driver
+because of reports of timimg problems on some cards.
+
++ New driver for NI6510. Just a simple tweak of the lance driver for
+different ID bytes and different register offsets. According to the
+NI6510 driver in Linux, the NI6510 Etherblaster is more like the NE2100
+and would be detected by the NE2100 driver. So use that one instead.
+
++ New drivers for 3c507 and NI5210, both of which use the i82586 chip. It
+works properly for both now. I needed to have enough receive buffers to
+make sure i82586 never goes into an out of resources state. 3c507 driver
+has one quirk, it only responds after second bootp request. I seem to
+remember something about this problem of losing the first packet after
+initialisation in early Linux discussions.  I am also now convinced
+that Intel designers have weird minds. BTW, NI5210 driver assumes 8k
+RAM because if you put the ROM on the NIC you can only have 8k RAM. If
+you are putting the ROM off-board and you want 16k, well, talk to me.
+
++ Call nic_disable routine just before jumping to loaded image. This
+does nothing in most drivers, but may have side effects as the nic_reset
+routine used to be called instead.
+
++ One of those "why I didn't think of it before" ideas: A modified version
+of comboot, called floppyload, that is prepended to the .rom image rather
+than the .com image and then both written raw to a floppy for testing the
+bootrom. All we have to do is jump to an entry point in (z)loader that
+skips the INT19H stuff. Relocation will happen automatically.  Now the
+.com images and comboot are superfluous, unless one is masochistic enough
+to want to try to test under DOS.
+
+Added .fd0 targets to Makefile. Saying make <card>.fd0 will make
+floppyload.bin and <card>.rom, and cat both to /dev/fd0. Naturally the
+drive must be writable and you must have a floppy in the drive.
+
++ New driver for Tiara (Fujitsu EtherStar). This was one of the easiest
+drivers to write. But the chip apparently has some quirks; there is no
+Linux driver for it in the standard distribution and the email address
+of someone who wrote an alpha driver is invalid. Perhaps I'll bump into
+an AT1700 (which has a similar chip) one day and be able to reuse a lot
+of the code.
+
++ Updated contrib/mkelksnbi for ELKS 0.0.68.
+
++ Confirmed that the SMC8216 driver works. 8416 not tested, it's a PnP
+card. Can anybody confirm this?
+
++ New contributed software: p910nd, a tiny printer daemon suitable for
+diskless hosts.
+
++ Made ANSIESC work for Etherboot/16.
+
++ Fixed Makefile and Config.* so that it works with old binutils.
+
++ Included a subset of netboot-0.7.3.
+
++ Released as version 4.0.
+
+Changes between 4.0 and 4.1
+
++ Patches by Andrew Coulthurst for eepro100b.
+
++ Patches by Doug Ambrisko for booting Windows95 after answering N to
+the boot from network question. Added conditional code to cope with
+broken DHCP server and TAG 128.
+
++ Put version and driver identifier at end of ROM image if it fits,
+to help identify ROMs in future.
+
++ Capture ROM segment address and length to help choose between multiple
+NICs later.
+
++ Don't clear all of memory because it will destroy return address
+on stack.
+
++ Changes to comboot-1.2 (although obsolete) to run on 8088s.
+
++ New version 0.2 of p910nd, a non-spooling printer daemon.
+
++ Patches by Alex Harin to prepended loaders and makerom to generate PnP
+ready ROMs. Modified makerom to automatically detect PnP and PCI headers
+and do the right thing. Added option to change the vendor and device IDs.
+
++ Augmented documentation for 2.1 and above kernels. Kernel now wants to
+mount /tftpboot/<hostname in bootptab> rather than /tftpboot/<ip address>
+as the root FS.
+
++ Changed all the outb* and outw calls in drivers (except eepro) to be
+OUTB* and OUTW, then defined macros to translate to out[bp]* for both
+Etherboot/32 and Etherboot/16, instead of pasting macros from Linux
+include files because apparently they've changed in 2.1. At the same
+time reversed the arguments in start16.S for outb and outw to match the
+Linux convention. Unfortunately the out[bw] usage came that way from
+FreeBSD. Someday I'll reverse the arguments in the C files properly.
+For any new driver writers, you should use the Linux order now.
+
++ New contributed utility, disnbi for decoding and extracting network
+boot images.
+
++ Martin Atkins contributed mntnbi for mounting DOS NBIs.
+
++ Peter Dobcsanyi contributed vendor and device IDs for the Netvin
+NE2000/PCI clone.
+
++ adam AT mudlist PERIOD eorbit PERIOD net contributed RARP code as
+alternative to BOOTP/DHCP. Activated by RARP_NOT_BOOTP define.
+
++ Added link to Claus-Justus Heine's NFS swap Web page and updated the
+contrib directory.
+
++ Disabled max packet length check in ns8390.c. Caused spurious Bogus
+packet messages in some cases and doesn't seem that useful a sanity
+check anyway.
+
++ Daniel Engstrom contributed a SMC9000 driver.
+
++ Didier Poirot contributed an Etherpower II (EPIC 100) driver.
+
++ Added bug fix by Attila Bogár for bootmenu.c and patch to main.c to
+remove looping menus on failure. Also code for ARP replies and TFTP
+block retransmit (#ifdefed because controversial).
+
++ Code cleanup of tftp and tftpd also by Attila Bogár.
+
++ Nathan R. Neulinger fixed a bug with block being declared short instead
+of u_short in tftpd.c, which limited transfers to 32k blocks. Fixed
+problem with field tu_block being declared as signed short in many
+platforms by including fixed version of tftp.h. Fixed tftp also for
+good measure.
+
++ New mini-HOWTO on a "ssh terminal".
+
++ Andreas Mack pointed out that eepro100 doesn't compile on 2.1 and
+2.2 kernels. Removed unnecessary include of bios32.h and reliance on
+definition of virt_to_bus in kernel headers in eepro100.c, epic100.c
+and lance.c.
+
++ David Sharp contributed a Tulip driver written for FreeBSD netboot.
+Ken Yap ported to Etherboot. Not tested yet because no hardware.
+
++ Replaced references to arptable[ARP_CLIENT].node to nic->node_addr in
+eepro100.c and epic100.c as they should be.
+
++ Greg Beeley of LightSys Technology Services contributed a 3c905b
+driver. Be sure to read the release notes in 3c905b.txt.
+
++ Günter Knauf suggested making the prompt strings more generic and to
+put a newline after the answer. Beware, N now means Network boot and
+not No to network boot.
+
++ Alex Nemirovsky contributed some patches for BIOSes that use an extended
+space at the top of 640k. Also some code for BIOSes that don't implement
+BIOS32 correctly or at all.
+
++ Use PCI extension BIOS header only for PCI cards, all others use legacy
+extension BIOS header.
+
++ Klaus Espenlaub contributed various cleanup patches to the code.  Also
+introduced Rainer Bawidamann's code, see next paragraph.
+
++ Rainer Bawidamann contributed a Realtek 8139 driver.
+
++ Simplified rules for building .bin files, use -b of as86 so we
+don't need ld86 or objdump86 now. But later found that a fixed as86 is
+required. So supply preassembled binaries. The keen hackers can get the
+fixed tools.
+
++ Georg Baum contributed a Schneider & Koch G16 driver. Only the
+32 bit version works at the moment; even though the 16 bit version
+compiles, it won't work because the current code assumes flat memory
+addressing. Anybody who needs the 16 bit version should feel free to
+fix it.
+
++ Reduce size of ROM image loaded by floppyboot.bin from 64kB to 32kB
+for a slight speedup in loading. None of the images are even 32kB anyway.
+
++ Updated some of the documents in doc/sgml.
+
++ Klaus Espenlaub sent in a totally revamped start32.S, using the code16
+and code32 directives in recent GNU as (so if this file won't assemble
+maybe your as version is not recent enough). Also patches to the menu
+handling code.
+
++ jluke AT deakin PERIOD edu PERIOD au sent in a fix for the WD/SMC8013
+long ago which I finally got around to verifying.
+
++ start16.o and start32.o are supplied for those people who have problems
+compiling start*.S with as/as86.
+
+Released as Etherboot-4.2.0
+
++ One line fix to 3c509b by Greg Beeley for Wake-On-LAN support.
+
++ Added patches by Klaus Espenlaub that I forgot.
+
++ Made AS_PSEUDOS not the default, assume that people have sufficiently
+up-to-date GNU as. If not they can uncomment that line.
+
+Released as Etherboot-4.2.1
+
++ Disable 3c509 after loading finished or port may be unusable.
+
++ Woops, forgot to up the version's last digit in the last release.
+
++ Stephan Bauer sent in a device ID for config.c for 21142 chip Tulips.
+
++ Ifdef out input overrun recovery code (it's really only needed for
+NE2000s) and use SHMEM by default for 3c503s to bring the ROM size down
+below 8kB.
+
++ Added code to start32.S to detect < 386 and exit so it doesn't hang
+the computer. Doesn't print a message yet.
+
++ Changed README.sgml to recommend that TFTP use a separate directory
+from NFS, /tftpdir. Added sample configuration file for DHCPD and caveat
+about the name of the root directory when using DHCPD.
+
++ Revamped atnetboot.sgml: use mtools most of the time, write about a
+few example applications.
+
++ Quick Perl script for converting bootptab to dhcpd.conf.
+
+Released as Etherboot-4.2.2
+
++ Forgot to put new version of src/start32.o. Not urgent though, the
+extra code only guards against Etherboot/32 being executed on < 386.
+
++ Supply version preassembled start32.o with ANSIESC and FLOPPY defined
+for those with a deficient as. Define dummy handleansi routine in
+ansiesc.c so that it will still link even if this start32.o is used.
+
++ Edited *.asm so that they can be assembled by either as86 (ELKS version)
+or nasm.
+
++ Changed Makefile so that one can choose between no as86, as86 or nasm.
+
++ Added Mark Burazin's conditional code for Compex RL2000 PCI NIC.
+
++ Increase delay during probe phase to 10ms as 1ms is too low for some
+3c509 boards.  Donald Becker's Linux driver hints that > 2ms is needed
+to be safe. Also call t509_disable in case board was active.
+
++ Update README.sgml date and version.
+
+Released as Etherboot 4.2.3.
+
++ rtl8139.c: Reduce the number of transmit buffers to reduce footprint.
+Remove polling loop in *_loop(), caller already does the looping.
+
++ main.c: Fix code indentation in bootp().
+
++ Small corrections to documentation.
+
+Released as Etherboot 4.2.4.
+
++ Matthias Meixner found a longstanding bug in rtl8139.c where it was
+testing the wrong bit for the existence of a packet in the buffer.
+
++ Added paragraph to documentation about caveats for hosting NFS root
+on a different architecture.
+
+Released as Etherboot 4.2.5.
+
++ Updated mklnim for RH6.0 which uses a different floppy image and
+requires 'network' to be appended to kernel parameters.
+
++ Reversed sense of #ifdef DHCP_SUPPORT to #ifndef NO_DHCP_SUPPORT and
+so forth, i.e. the default is with DHCP support.
+
++ Suggest reducing options for rtl8139 driver to minimise footprint in
+release notes.
+
++ Jim McQuillan provided changes to support the SMC1211, which uses the
+RTL8139 chip.
+
++ Changed lret in start32.S to int $0x19 so that it doesn't depend on
+the return location being there.
+
+Released as Etherboot 4.2.6
+
++ Succeeded in booting FreeDOS with the kernel in the tagged image rather
+than on the ramdisk, i.e. the boot process jumps directly to the kernel
+in memory. The utility is mkfreedosnbi in contrib/.
+
++ Additions to the documentation.
+
+Released as Etherboot 4.2.7
+
++ Matt Hortman pointed out that the BIOS clock value returned by INT1AH
+rolls over at midnight, causing delay loops that cross midnight to
+fail. Fix was to keep track of midnight crossings in currticks so that
+currticks' return value is monotonically increasing.
+
++ Added paragraph to documentation about editing PCI vendor and device
+IDs in Makefile if needed.
+
++ Merged in FreeBSD support code supplied by Doug Ambrisko. Thanks!
+
+Released as Etherboot 4.2.8
+
++ Cleaned up the FreeBSD support in osloader.c. Symbols to use in Config
+are to select image type, not FreeBSD specific now.
+
++ Added simple signature checking code in floppyload.asm in case somebody
+forgets to append a ROM image or tries to load a non-ROM image.
+
++ Merged in 3c90x and multiple PCI bus support by Steve Smith. Thanks!
+
++ Included NT-Diskless-Terminal HOWTO by Pavel Tkatchouk.
+
++ Included snapshot of H. Peter Anvin's rewrite of tftp.
+
++ Combined tftp and tftpd directories, and touched up Makefile to reflect
+normal Linux install directories.
+
+Released as Etherboot 4.2.9
+
++ NT-Diskless-Terminal HOWTO renamed to Diskless-From-NT.
+
++ One line fix to mknbi-dos to recognise FAT16 filesystems as legal.
+Updated first.S in mknbi-dos so that it can be assembled by nasm and is
+also suitable for FreeDOS with the right define. Still backward compatible
+with as86. Bug fix at line starting getnm3:.
+
++ Updated first.S in mknbi-linux so that it can be assembled by nasm also.
+
++ Locate bootp data block at 0x93C00-0x93FFF to free up 1024+ bytes in
+[0x98000-0x9FFFF]. Etherboot/32 only, business as usual for Etherboot/16.
+
++ Patch from Attila Bogár to make CONGESTED a compile option for
+TFTP_TIMEOUT. Also corrected spelling of his name in README.
+
++ Fixed start32.S to assemble correctly with gas version 2.95. Must
+define GAS295 in CFLAGS.
+
++ Add contrib/3c90xutil containing a utility for handling 3c90x EEPROMs
+in situ.
+
++ Update p910nd to 0.3. client.pl now checks if hostname is known and
+uses more convenient routines from Socket module.
+
++ Moved the Flashcard directory into a separate package as it's of
+limited interest.
+
+Released as Etherboot 4.2.10
+
++ Fixed bug introduced in 4.2.10 in code for handling bootp extension
+files.
+
++ Change in 3c90x.c so that it can compile under FreeBSD.
+
++ Patch to tulip.c from Nick Lopez to handle Macronix 98715 (Tulip clone).
+
+Released as Etherboot 4.2.11
+
++ Prefer RFC1533_GATEWAY to giaddr for routing tftp packets.
+
++ Print out both relay address and gateway address.
+
++ Stored arptable ipaddrs in network byte order. Makes everything simpler
+and we can get rid of convert_ipaddr. Now %I in printf and inet_ntoa
+have to deal with NBO. We reduce the footprint by ~100 bytes.
+
++ Renamed setip to more standard inet_ntoa and change argument type to
+suit, using in_addr.
+
++ Replaced bcmp by memcmp, bzero by memset, and bcopy by memcpy. Allows
+us to use optimised versions in inline assembler.
+
++ Replaced OUTB and OUTW by outb and outw with arguments reversed.
+Finally all the out macros are the same form as for Linux.
+
++ Replaced \r\n and \n\r in output strings with \n since putchar
+now prints \r before \n. Then changed printf("\n") to putchar('\n').
+Like Unix convention for strings now.
+
++ Got rid of test.c and Makefile rules connected with it.
+
++ Added patch to eepro100.c by Matt Hortman to correct PCI latency.
+
++ Merged in Marty Connor's ntulip.c. Now supports Macronix 98715 and
+Linksys LNE100TX.
+
+Released as Etherboot 4.2.12
+
++ Anders Larsen contributed mkQNXnbi, for generating tagged images from
+QNX kernels.
+
++ Bernd Wiebelt contributed code to request vendor tags in DHCP.
+
++ Fixed more bugs introduced in 4.2.10 in code for handling bootp
+extension files.
+
+Released as Etherboot 4.2.13
+
++ Marty Connor reduced RTL8139 footprint by using only one transmit
+buffer instead of 4. Now RTL8139 is reliable.
+
++ Moved initialised data declaration from ns8390.h to ns8390.c.
+
++ Contributed utilities for wake-on-LAN: wol.c (Bob Edwards) and wake.pl.
+
++ Makefile for 3c90xutil/romutil.c. -O is essential when compiling.
+
++ Happy year 2000!
+
+Released as Etherboot 4.4.0
+
++ VIA-Rhine driver contributed by Paolo Marini. Footprint reduced by
+Marty Connor.
+
++ Netgear FA310TX (Tulip clone, LC82C168 chip) support added by Marty
+Connor.
+
++ Support for 3C905C added by Marty Connor.
+
++ mklnim updated to support SuSE 6.x also.
+
+Released as Etherboot 4.4.1
+
++ New configuration file scheme to specify what ROMs are built.
+
++ Adam Fritzler contributed 3c529 (MCA version of 3c509) support in
+driver.
+
++ Marty Connor wrote a version of 3c90xutil/romutil for 905C NICs.
+
++ Günter Knauf contributed a wake on LAN CGI script.
+
++ Notes in contrib/eepro100notes on how to flash the EEPROM.
+
++ Happy Australia Day, 2000-01-26.
+
+Released as Etherboot 4.4.2
+
++ hwilmer AT gmx PERIOD de found a probe error in 3c507.c, shouldn't
+mask memory size with 0xffffL, this fails with 64kB memory.  Also
+changed to use real-time-clock to timeout on initialisation of i82586
+rather than relying on decrementing a variable (which is CPU speed
+dependent).
+
++ James Pearson pointed out that ~ should be escaped as &tilde; in
+vendortags.sgml. Also cleaned up the 8-bit characters while I was at it.
+
++ Günter Knauf pointed out that if ASK_BOOT is defined, then key input
+echos twice. Also, CR doesn't select the default. Problem was that getchar
+converts all \r to \n then main.c was testing against \r instead of \n,
+and also that getchar() was echoing when it should leave it to the caller.
+Deleted code from getchar() and made it a function with no arguments.
+Also sent me a new version of mp-form.pl with mp-form.txt. Also suggested
+the good idea that the gateway and relay fields not be displayed if they
+are not used.
+
++ Bob Edwards sent in patches to ntulip.c to autodetect 100 Mb media
+for 21142/3 NICs.
+
++ Okuji Yoshinori found a small bug in main.c: for (retry1 = 0; retry < ..
+Don't know what effect it had.
+
++ Klaus Espenlaub sent patches which make the RTL8139 driver more
+reliable, see notes in rtl8139.c.
+
++ Russ Nelson gave permission to release cs89x0 driver with Etherboot.
+It's normally under GPL. Moved cs89x0 driver to src directory, removed
+cs89x0.sgml.
+
++ Clarified copyrights of files in distribution.
+
+Released as Etherboot 4.4.3
+
++ Klaus Espenlaub sent in some patches to overcome the 64K block rollover
+problem in tftp.
+
++ Bob Edwards, Paul Mackerras and Marty Connor worked out fixes to
+ntulip.c to handle 21142/3 Tulips properly.
+
++ Karsten Tinnefeld sent in a Makefile fragment for doc/sgml/Makefile
+to generate DVI and PS files using sgml2latex.
+
++ tulip.* renamed to otulip.*, ntulip.* renamed to tulip.*
+
++ Added FAQ and Writing an Etherboot Driver sections to README.
+
++ Woops, if and of swapped in dd command in atnetboot.sgml.
+
+Released as Etherboot 4.4.4
+
++ FUKUHARA Makoto supplied a patch for 4.4.4 for FreeBSD ELF booting
+with large tftp blocks which I missed putting in.
+
++ Small patch by Marty Connor to tulip.c to handle fast Tulips better.
+
++ Wrote small loader to load images from .com files.
+
++ Shusuke Nisiyama contributed a 3c595 (and may work for 3c590) driver.
+
+Released as Etherboot 4.4.5
+
+A major reorganisation by Klaus Espenlaub. Here are his notes, verbatim:
+
+The biggest change is the almost rewritten Makefiles (both in src and in
+doc - the one in doc is still reasonably simple).  If you want to get
+an overview - basically one Makefile now builds both /16 and /32 ROMs.
+This involves quite a few make variables (similarly in Config), but it
+should be mostly self-explaining.  I also converted the suffix rules to
+pattern rules, because it is the only way to keep the build directories
+for /16 and /32 apart.
+
+Generally all /32 code is compiled in bin32, all /16 code is compiled
+in bin16, and the code that works for both is in bin.
+
+The names (object files, images, but NOT the final ROMs) used during
+the build process for some PCI cards have changed (especially lancepci
+and nepci).
+
+I eliminated the driver.a file by adding yet more ugly code to genrules.pl
+(no, I'm not very proud of the code I added there - I hate perl, but
+at least it works), which now generates all sorts of make rules and
+dependency information.  This eliminates the redundant recompile of all
+other drivers if you specified a specific target at the make command line.
+
+There are now automatic checks for the generated ROM size (3K safety
+margin are used to allow for 1K BIOS EBDA and 2K stack).  This should
+avoid most of the cases in which the stack overwrites code and/or data,
+causing strange crashes.
+
+On to the real code - I rewrote both the ELF and a.out loading (the
+blocksize is now properly handled for all formats), and now most of the
+code is identical.  Someone might want to merge the two.  I verified that
+both a.out and ELF FreeBSD loading still works by booting the FreeBSD
+2.2.8 and 3.4 install kernels (the ELF kernel you gave me didn't work
+for whatever reason).  Actually I tested everything except NBI, but that
+code is completely unchanged.
+
+I eliminated config.h and created cards.h - just have a look and you
+should get the idea.  The PCI/ISA prototype matching hack is now buried
+in there.  All PCI drivers (and skel.c) have been converted to the new
+include file.
+
+The only file that is really new is nfs.c, which contains the code where
+I started my journey.
+
+The loader code is now merged into one file for both the normal and
+compressed case.  Some bugs have been fixed along the way (the normal
+loader copied too much data, potentially crashing the machine).  BTW: I
+removed the block copy from comboot, because the first thing the loader
+code does is - to copy the code to the right place.  Also copying it to
+0x80000 prevents compressed ROMs (though there is no way in the Makefile
+to create such a beast).  Also the stack changing code was wrong -
+the overflow handling is missing: 0x9fxxxx-0x800000 is truncated to
+fit in the 16 bit register, which is not quite what one would expect.
+The stack pointer must be in the same segment, so for overflows just
+load 0.  Anyway, we don't need a new stack for 4 bytes (the return
+address).  Also the shifts won't work on an 8086/8088.  The ROM segment
+and length code is also done once more in loader.S.  Finally the org
+0x100 didn't work with my version of as86 - it prepended 256 null bytes.
+Don't get me wrong - I see that comboot was just a quick and dirty hack.
+It's now working...
+
+I also fixed floppyload to read exactly the right amount of data (not
+up to 65520 bytes more like the Linux code did) and ripped out some
+unused code.
+
+3c509.c: includes fixed, const added, static added, removed redundant code
+
+3c90x.c: includes fixed, const added, shortened messages to save space,
+made the transceiver selection bootrom fix optional (default: off),
+updated 3c90x.txt
+
+ansiesc.c: de-tftpified (now uses "download")
+
+config.c: moved the driver prototypes to separate file, added a few const
+
+cs89x0.c: ansified, const added, fixed timeout handling
+
+eepro100.c: includes fixed, const added, static added, USE_INTERNAL_BUFFER
+hack, passing globals as a parameter removed, timeout handling fixed,
+comments fixed
+
+epic100.c: comments fixed, const added, static added, USE_INTERNAL_BUFFER
+hack, removed unused variables, changed debug code to use macro instead
+of variable, allow broadcasts to be received (after all how did it
+work before???)
+
+etherboot.h: dual/serial console "cleanups", added NFS support, fixed
+INTERNAL_BOOTP_DATA for pathologic cases, removed prototype within comment
+(how did that end up there?), moved prototypes for config.c code here,
+added consts all over the place
+
+floppy.c: added static, changed cleanup code
+
+floppyload.S: renamed from .asm
+
+genrules.pl: I didn't write this :)
+
+i82586.c: fixed includes, added const
+
+lance.c: fixed DMA for PCI cards, removed leftovers from Linux driver,
+USE_INTERNAL_BUFFER hack
+
+linux-asm-io.h: added prototypes
+
+linux-asm-string.h: added prototypes
+
+loader.S: renamed from loader.asm, more comments see elsewhere in
+this mail
+
+loader.inc: removed
+
+main.c: includes fixed, static and const added, Etherboot/32 now prints
+relocaddr, hooks for NFS support, drain the Rx queue in some strategic
+places (after sleep), changed interface to await_reply: timeout handling,
+new cleanup code
+
+misc.c: ansified, twiddle code changed, strcasecmp enabled for
+Etherboot/16 (smaller than the 16 bit libc version), clear A20 before
+kernel is started (only for NBI), dual console fixes, removed bogus
+comment about interrupt enabling using iskey()
+
+nic.h: include guard added, added const
+
+ns8390.c: fixed includes for PCI version, added const, ansified, renamed
+internal functions
+
+osdep.h: removed #include <asm/byteorder.h> - probably all #ifdef
+__linux__ and __FreeBSD__ may be removed now.
+
+osloader.c: see elsewhere in this mail. removed loads of debugging code.
+
+otulip.c: removed unused variables, USE_INTERNAL_BUFFER hack, ansified,
+added const
+
+otultip.h: added const
+
+pci.c: fixed signed comparison
+
+pci.h: include guard added, const added
+
+rtl8139.c: static added, const added, globals are no longer passes as
+parameters, fixed probe loop
+
+serial.S: removed the Makefile hack to calculate the divisor and replace
+it by a CPP hack
+
+sk_g16.c: added static/const
+
+skel.c: updated
+
+smc9000.c: fixed includes, added const, fixed timeout, removed unused
+variables
+
+start16.S: changed stack pointer reloading
+
+start32.S: cleaned up GAS295 support, fixed CPU detection, fixed memsize
+for > 64MB, added basememsize()
+
+tiara.c: fixed includes, added const, removed unused variable
+
+tulip.c: fixed includes, added const, decreased oversized frame tolerance,
+USE_INTERNAL_BUFFER hack, converted to C comments, fixed prototypes,
+removed unused variable
+
+via-rhine.c: fixed includes, converted to C comments, removed unused
+functions, fixed timeout, USE_INTERNAL_BUFFER hack, removed unused
+variable, const added
+
+lzhuf.c was modified not to output ':' characters, because I find it
+useful to search for them in a make log to spot all error messages.
+
+Finally all symlinks have gone
+
+I fixed sgml/vendortags.sgml (maybe it's more a workaround): sgml2txt
+didn't like the ~~' sequence and ignored a whole line, making the .txt
+file incomplete.  Also freebsd.txt was converted to sgml.
+
+My standard patch to netboot-0.8.1/configure (to remove the "unknown") is
+again in place - how is this file created? By hand?  I added serial/dual
+console support to mknbi-linux.
+
+Oh, and something I almost forgot: Etherboot now works under VMware.
+VMware has a rather large EBDA (3K instead of 1K like most other
+BIOS versions), so one might have to sacrifice a few nifty options.
+Note that the Makefile check cannot detect this - maybe we should add a
+runtime check, too?  One thing that doesn't work with VMware is the "Boot
+Local" stuff - it's not terribly useful if you have to boot from disk,
+but it shouldn't crash the machine (I've seen several triple faults,
+depending on RELOCADDR and the stack usage).  I tracked it down to the
+fact that VMware crashes on int 0x19 if the memory area 0x98000-0x9f3ff
+is overwritten.  If one changes RELOCADDR to 0x8f000, everything works
+nicely.  Someone should report the bug to VMware.  Also proper boot ROM
+support should be added to VMware and they should upgrade the virtual
+card to 100Mbps (don't laugh - they limit the bandwidth to 10Mbps even
+if you have a real 100Mbps card!).  Maybe one could even use the flash
+utility for the recent AMD PCnet cards...
+
+Released as Etherboot 4.5.5
+
++ More fixes from Klaus Espenlaub, based on bug reports by Doug Ambrisko
+and others. Small cleanups in tulip.c. He also added a BACKOFF_LIMIT
+parameter to the exponential backoff for retry intervals.
+
++ Christoph Willing sent in a fix for PCI NE2000s which forces 16-bit
+transfer mode for PCI. This might make it work on some PCI NE2000s that
+failed before, please test if you can.
+
++ Moved commercial links off main web page into web page of its own.
+
++ Merged in TRY_FLOPPY_FIRST code from <as AT bart PERIOD nl>.
+
+Released as Etherboot 4.5.6
+
++ Frank Mehnert spotted a bug in tulip.c where the sole transmit buffer
+was not tagged as the last one in the chain.
+
++ Hacked serial.S to check if a serial interface is present and to disable
+the routines if not, so that Etherboot does not hang on a machine without
+a serial interface, even if the option has been compiled in.
+
++ Wrote mkromnbi for making a network bootable image from a ROM image
+(for using Etherboot to test another Etherboot driver).
+
++ Krzysztof Halasa found a small bug in nfs.c in the handling of BOOTP
+extension files.
+
++ Some instructions on adding Etherboot to a main BIOS were contributed
+by Dirk von Suchodoletz.
+
++ Some commentary on cbrom.exe versions posted by Rapp Informatik Systeme
+GmbH to the Netboot mailing list included.
+
+Released as Etherboot 4.5.7
+
++ Patrick Auge pointed out that -DT503_SHMEM option should be not used
+by default, as the comments say.
+
++ Heinrich Rebehn pointed out that the documentation needed to be updated
+for the new bin32 and bin16 prefixes for targets.
+
++ Christoph Plattner found that node_addr in struct nic should be unsigned
+char * or problems occur in the handling of the MAC address in cs89x0.c.
+
++ Greg Hudson pointed out that inet_ntoa is misnamed, it should be
+inet_aton.
+
++ Vsevolod Sipakoff suggested that the probe address list for NE2000
+should match that of Linux. Done, with the deletion of 0x360 which often
+conflicts with the parallel port at 0x378.
+
++ Created mknbi, a Perl utility that replaces mknbi-dos, mknbi-linux,
+mkfreedosnbi, and mkromnbi. Removed mk{freedos,rom,elks}nbi/ from
+contrib/.  (ELKS has its own tagged image creation method now.)
+
++ Removed obsolete/ from contrib/.
+
+Released as Etherboot 4.5.8
+
++ Some small enhancements to mknbi. Merged in disnbi and mklnim. Changed
+version to 1.0.
+
++ netboot-0.8.1 directories distributed separately now.
+
+Released as Etherboot 4.6.0
+
++ Nick Lopez discovered that the Davicom 9102 is Yet Another Tulip Clone
+and a few appropriate initialisations will make it work.
+
++ Matthew Reimer sent in patches for contrib/3c90xutil.c/bromutil.c to
+compile and run under FreeBSD.
+
++ Krzysztof Halasa found that the number of buffers in epic100.c needed
+to be raised to 2 each for operation at 10 Mb for the PCI EtherPower
+9432B-TX using the SMC 83C171.
+
++ Klaus Espenlaub fixed the root path handling in main.c, it wasn't
+requesting option 17 in DHCP. Also removed one prototype warning in
+tftp().
+
++ Daniel Shane sent in code for for adding identifiers to a DHCP request,
+using a user specified DHCP option. The patch is in contrib/dhcpid.
+
++ Bug fix in mknbi-1.0 for the ipaddrs=rom option, warnings about badly
+formed specification to ipaddrs= or unresolvable names.
+
+Released as Etherboot 4.6.1
+
++ Stuart Lynne sent in patches to allow - to mean reuse kernel filename
+in menu specifications. Also fixed DHCP request to ask for tags 129 and
+130 (Ken added this), as the mknbi man page promised.
+
++ Fixed URL for Richard Ferri's LUI.
+
++ Added URL for Gregory R. Warnes' ClusterNFS.
+
++ Changed RFC2132_MAX_SIZE option in main.c to allow maximum size DHCP
+replies.
+
++ Matthias Schniedermeyer submitted an optional feature to use numbers
+instead of letters for bootmenu entries.
+
++ Brought some FAQs up to date with mknbi-1.0.
+
++ Wrote perl script mklrpnb for making netboot image from Linux Router
+Project floppy.  Tested on Coyote Linux (based on LRP).
+
+Released as Etherboot 4.6.2
+
++ Re-enabled tulip.c:tulip_disable() code.
+
++ Minor fix to SHOW_NUMERIC code in bootmenu.c.
+
++ Minor spelling corrections to vendortags.sgml.
+
++ andreas.kabel AT slac PERIOD stanford PERIOD edu pointed out that to
+be RFC951 compliant, the broadcast BOOTP request near line 705 of main.c
+should use port BOOTP_CLIENT and thus stand a better chance of going
+through firewalls.
+
++ Christoph Plattner found that the 16 bit bus width fix for NEPCI cards
+introduced in 4.5.6 breaks operation for other NEPCI cards. So now the
+#define symbol is NS8390_FORCE_16BIT, to be used when the NIC requires
+16 bit bus width but Etherboot guesses wrong. This needs to be fixed
+later to autodetect adapter bus width.
+
++ Shusuke Nisiyama sent me the PCI IDs for 3C595 NICs so that ROM images
+could be generated for them.
+
++ Jim McQuillan sent in modifications to tulip.c to reject bad packets.
+
++ Klaus Espenlaub suggested changing the filename substition macro in the
+IDENT16 and IDENT32 strings to $(@F) so that only the filename portion of
+the pathname is inserted.  Otherwise the contributed romid program breaks.
+
++ Added author ident and copyright status to contrib/bin2intelhex.c.simple
+at Rogier Wolff's request.
+
++ Günter Knauff sent updates to romid and mp-form.
+
+Released as Etherboot 4.6.3
+
++ Marty Connor contributed patches to tulip.c to support the LinkSys
+LNE100TX v4 NICs.
+
++ Added rmrd.com to mknbi-1.0 directory.
+
++ Added experimental changes to allow RELOCADDR to be changed to 0x88000
+to avoid Disk On Chip drivers. See RELNOTES and Makefile for details.
+
+Released as Etherboot 4.6.4
+
++ Chris Johns found a long-standing bug in first-linux.S. ES would
+sometimes != CS, making the ramdisk moving fail.
+
++ Made --harddisk work for mknbi-fdos.
+
+Released as Etherboot 4.6.5
+
++ Bug in mknbi-dos, last sector omitted in ramdisk image.
+
++ Use ceil() for computing number of rootdir sectors.
+
++ --harddisk now works for mknbi-dos also.
+
++ Should work on FAT16 partitions now.
+
++ New driver for Winbond W89C840 by Igor V. Kovalenko.
+
++ Modification to loader.S by Steve Smith for some PCI BIOSes that don't
+handle INT19H well.
+
++ Small bug in osloader.c, j not defined in two places if DELIMITERLINES
+defined.
+
+Released as Etherboot 4.7.6 (developmental)
+
++ All the changes from 4.6.5 to 4.6.6 back propagated except for the
+loader.S change.
+
++ Removed -nostdlib from ld flags. Seems to be a vestige from when we
+were calling gcc as it's not an ld option.
+
+Released as Etherboot 4.6.6
+
++ Contributed one-line patch to allow booting from SCSI disks also (sd).
+
++ Grzegorz Jablonski sent in a fix for long-standing bug in loader.S that
+prevented booting on some BIOSes.
+
++ More updates to documentation.
+
+Released as Etherboot 4.6.7
+
++ Rick Kennell pointed out that there is another place in main.c where
+the DHCP request is sent with a source port of 0, which may not elicit
+replies from some DHCP servers or pass gateways. Changed to
+BOOTP_CLIENT.
+
++ Depca driver finally works.
+
++ Changed unsigned int len; to int len; in 3c595.c transmit routine
+which was generating a warning from gcc.
+
++ Removed warning about ljmp indirect without * in start32.S by putting
+in the *. Checked that generated code has not changed by comparing
+binaries. Later: But only for gas 2.9.5 and above, gas 2.9.1 doesn't
+like *.
+
++ Wanted to do the same for the lcall's in pci.c but discovered that
+gas 2.9.1 chokes on *, and as I don't want to introduce more #ifdefs
+into pci.c, we'll just live with the warnings until gas 2.9.1 is dead
+or the incorrect syntax is rejected by a current gas release.
+
++ Reversed #define so that GAS291 indicates gas 2.9.1. Rationale: gas
+2.10 probably behaves like gas 2.9.5 so the default should be the new
+behaviour.
+
++ NI5010 driver finally works. Weird NIC, has only 2kB memory on board
+so if you don't switch to the receiver immediately after transmitting
+you will lose the reply packet. (This is a very ancient board, I was
+doing the driver for kicks.)
+
++ Implemented a low-overhead timer routine for implementing timeouts in
+drivers. This timer should be used instead of hacks with integer loops
+(which are CPU speed dependent) or calling currticks(), which has
+relatively high overhead because it reads the BIOS timer, and has a
+resolution of only 1/18th of a second.  Timer 2 of the 8254 timer chip
+can be loaded with an unsigned 16-bit value that will be decremented at
+about 1193 counts per ms (constant TICKS_PER_MS in timer.h). So the
+maximum timeout that can be implemented with a single call is about 54
+ms. Call load_timer(u16) to load and start the timer (0 == 65536). Call
+int timer2_running() to check if it is still active. timer2_running can
+be interleaved with other tests, e.g. on the NIC hardware registers.
+When the timer runs down to 0, it will return 0. If you just need to
+delay a short time, call waiton_timer2(u16) to load and delay that many
+ticks.
+
++ Removed slowdownio() from sources. It's called in only one place and
+is followed by a call to currticks() which will result in a large delay
+anyway. It's also not clear if the strategy in slowdownio (a couple of
+local jumps) will even work on fast CPUs with instruction caches.
+
++ Removed support for %i (alias for %d) in printf. Nobody uses it, if
+they do they should just edit the format string to use %d, and removing
+it means one less non-standard format in printf; we have %X, %b and %I
+as it is.
+
++ Simplified currticks() by accessing BIOS variables directly instead of
+calling timeofday BIOS interrupt.
+
+Released as Etherboot 4.6.8
+
++ I'm pissed off with the inconsistency between gas 2.9.1 and gas 2.9.5
+re ljmp * (indirect jump). Some assemblers claiming to be 2.9.5 dislike
+the * (RH6.2's is one). I'm going to just make it ljmp and live with the
+warning message until the gas 2.9.1 syntax is totally dead.
+
++ Various fixes from Klaus Espenlaub: Fix for NFS booting from *BSD
+platforms, fix for Lance driver, interrupt was being turned on, fix for
+serial.S and code cleanups.
+
++ Paul Robertson of Locsoft found that if the top half of %esp contains
+garbage just before the first call to real_to_prot in start32.S, it can
+affect booting on some BIOSes. Inserted andl to clear top half.
+
++ Sleep for 2 seconds after failure to load file to avoid pounding the
+server if the file does not exist and thus shutting down the tftp
+service (inetd has rather poor rate controls).
+
++ Shredda of gmx.de reported a discrepancy between the Macronix MX98715
+device IDs used in pci.h and NIC. Marty Connor has ruled that the id in
+NIC is a typo.  If booting works from floppy but not from ROM, this may
+be the reason.
+
+Released as Etherboot 4.6.9
+
++ Oops, a brown paper bag bug in start32.S. Forgot that the currticks()
+needs interrupts enabled to work. Calling the BIOS allowed interrupts to
+happen by going into real mode (interrupts are disabled in protected
+mode). So inserted prot_to_real and real_to_prot pair inside
+currticks().
+
+Released as Etherboot 4.6.10
+
++ Marty Connor and Gary Byers of thinguin.org contributed a LILO prefix
+file that makes the Etherboot image look like a Linux kernel to LILO and
+thus bootable from the LILO prompt.
+
++ Ifdefed out code in mknbi that falls back to the tftp directory for
+root-path. The result is that the options passed to the kernel specifies
+the tftp directory as nfsroot even if there is no root-path option in
+the DHCP or BOOT server configuration. This interacts badly with recent
+Linux kernels which actually pay attention to the root-path handed down
+and use that as nfsroot. People who were expecting the diskless kernel
+to use the default /tftpboot/<name of client> as nfsroot would have been
+surprised to find it trying to use the tftp directory (which often
+happens to be /tftpboot, although I recommend that it be different, to
+improve security).
+
++ Eric Biederman found an off-by-one bug in the ELF loader.
+
++ Christoph Plattner pointed out that the comments for COMCONSOLE in
+Config are wrong, the serial port is at 3F8, not 378.
+
++ A couple of updates to wol.c and wake.pl by Günter Knauff.
+
++ The Davicom 9009 and 9102 driver was contributed by Sten Wang of
+Davicom. It will be merged into tulip.c later.
+
++ Implement eepro100_disable. There have been reports of memory
+corruption after Etherboot has handed over to the booted image due to
+the live controller.
+
++ Matt Hortman reported a new Intel NIC, 82559ER, with different IDs.
+Added to file NIC.
+
++ Ranjan Parthasarathy reported another Tulip clone from ST Micro with
+different IDs.  Added to file NIC.
+
+Released as Etherboot 4.6.11
+
++ Stefan Lesicnik sent in a report from Intel which explains what is
+probably wrong with the PnP header. BEV should point to the mainline
+vector, not to the part that installs the INT19H vector.
+
++ Hopefully finally fixed DHCP option limit problem. It was requesting
+large packets but not parsing them fully due to the length limit passed
+into decode_rfc1533(). Thanks to shredda for testing this.
+
++ Added the # modifier to printf, it prefixes 0x to %x and %X making
+printf formats shorter throughout. 0x%[xX] changed to %#[xX] in lots of
+files.  Now if only I could make b,x,X the standard hhx,hx,x and get rid
+of I.
+
++ Andreas Neuhaus provided patches for multiple rx buffers for lance.c
+which made it work again with VMware.
+
++ Perl script to convert floppyfw floppies to netbootable images.
+
++ Marty Connor made some small changes to liloprefix and Makefile to
+make the LILO images SYSLINUX bootable also.
+
++ Make the default return value for _poll in skel.c 0 so that when
+driver writers implement _transmit first, it will not hang on garbage
+return values from _poll when it's called to flush the input queue
+before the first transmit.
+
++ EEPRO/10 driver now works. Âµs timer routines came in useful.
+
++ Anders Larsen sent in a patch to 3c90x.txt which makes it clearer.
+
++ Added more stuff to the documentation.
+
++ Fixed bug in mknbi that always did the equivalent of --ipaddrs=rom
+no matter what. Also removed undef from my variable list in TruncFD.pm
+so that it won't have problems with Perl interpreters.
+
+Released as Etherboot 4.6.12
+
++ Jim McQuillan sent in a patch for first-linux.S where it was assuming
+the argument in tag 129 (additional parameters) is a null terminated
+string, when it's a length counted string. A new routine, addkarg was
+created to handle this.
+
++ eepro100 should handle newer NICs with 256 byte EEPROMs now. This
+includes the onboard NICs on some motherboards, see file NIC. Thanks to
+Stephan Lauffer for helping with the fixes. WARNING: This code may have
+a bug that causes the onboard EEPROM to be corrupted. We believe we have
+found and removed the bug but please proceed with care.
+
++ DHCPDISCOVER was sending out one byte too many for PARAM_LIST.
+
++ In DHCPDISCOVER send "Etherboot" in VENDOR_CLASS_ID option (60).  Will
+add code later to check for "Etherboot" in vendor encapsulated options.
+
++ Used Âµs timer routines in 3c509 for more accurate timing and hence
+better hardware detection. Use COMMAND_IN_PROGRESS bit to detect
+transmit complete instead of waiting for a fixed amount of time. Get rid
+of eth_vendor and associated tests, it doesn't serve any useful purpose
+since the driver was modularised long ago and the 3c509 detection status
+is stored outside of the driver now. Got rid of some unused global
+statics in 3c509.c, leftovers when the drivers were monolithic. Wait 2
+seconds after enabling TP interface to give it time to come up. This
+allows us to get rid of T509HACK in main.c.
+
++ Get rid of eth_vendor and associated tests in cs89x0.c, same reasons
+as for 3c509.c.
+
++ Moved the rest of the VENDOR_ and FLAG_ defines into ns8390.h, as
+ns8390.c is the only file that uses them now.
+
++ Use lower 32 bits of node address + current time for xid (network byte
+order). More likely to be distinct from other clients than just the
+current time, which is similar for all clients booted at about the same
+time.
+
++ Support for 16-bit code has been removed.  XTs and ATs are pretty much
+dead now and in fact many Etherboot/16 drivers have been broken for a
+while but nobody noticed. This should make some of the code easier to
+maintain.  If you really wanted 16 bit support, use an older version of
+Etherboot, maybe 4.4 or something like that, not sure when things
+started breaking for 16 bit mode.
+
++ Should not store IP and UDP headers at BOOTP_DATA_ADDRESS. Redefined
+bootp_t without IP and UDP headers. Now requested size of bootp packet
+matches storage available. Do not add sizeof(iphdr) + sizeof(udphdr) to
+bootp pointer in start32.S:xstart now. start16.S:xstart was broken
+because it did not do this addition but nobody noticed.
+
++ Removed array kernel_buf, saving 128 bytes and replaced with
+KERNEL_BUF, a pointer into the bp_file of the bootp_reply structure at
+BOOTP_DATA_ADDR. Note: this depends on the server not sending Option
+Overload which would use the sname and file fields for options, but we
+don't request this option so it shouldn't.  Removed char *kernel,
+instead check KERNEL_BUF[0] just before booting and if null, use
+fallback filename.  (This is needed for future extensions to booting
+protocol.)
+
++ Define a shorter tftpreq_t type for making requests instead of using a
+full sized tftp_t packet to reduce stack usage.
+
++ Defined macros for htonl/htons/ntohl/ntohs for cases where the operand
+is a constant, saving a function call.
+
++ Started on first32.c, a protected mode 32-bit version of
+first-linux.S, which should be far easier to read and maintain. Will
+boot basic Linux kernels correctly but doesn't handle ramdisk or
+kernel arguments yet.
+
++ Updated nfs-swap documentation in contrib/nfs-swap to point to
+Claus-Justus Heine's new web page.
+
+Released as Etherboot 4.7.13 (development)
+
++ Added more IDs for eepro100 variants taken from the Linux 2.2.18
+source. Should handle the EEPROM properly now, a few defines were wrong
+in 4.7.13.  Loop counter timeouts in eepro100.c replaced with hardware
+timeouts.  Don't loop waiting for packet in _poll, return 0 immediately.
+
++ first32.linux works. Does kernel arguments and ramdisk but doesn't do
+appended parameters from menu selections, which should be replaced by a
+more elegant menu scheme anyway.  Needed gateA20 routines in
+mknbi-1.1/first32.c otherwise cannot access extended memory.
+first32.linux should be able to handle memory > 64 MB, which the old one
+couldn't.  Support for first32pm call protocol added.
+
++ 3c595.c changed to use hardware timer for delays. Transmit routine
+waits for a fixed period after transmitting. Changed to check
+S_COMMAND_IN_PROGRESS bit. It also contains some of the same unused
+variables as 3c509.c and mentions 3c509 in some comments. Cleaned up.
+
++ Hmm, how come this wasn't fixed long ago? Should discard BOOTP/DHCP
+replies that are not to broadcast or own MAC address. I guess xid caught
+practically all of the non-matching packets. (Later: Actually the NIC
+should filter out packets we don't want, but leave test in anyway, it's
+the last test.)
+
++ Removed last vestiges of ETHERBOOT32 and ETHERBOOT16.
+
++ ETHER_ADDR_SIZE => ETH_ALEN, ETHER_HDR_SIZE => ETH_HLEN,
+ETHER_MIN_PACKET => ETH_ZLEN, ETHER_MAX_PACKET => ETH_FRAME_LEN.  More
+Linuxy and therefore more familiar to programmers.
+
++ Cleared up confusion with 60/64 and 1514/1518 for minimum and maximum
+frame sizes. Practically always the right numbers are 60/1514, except
+that some chips count the FCS in the receive length, then we have to use
+64/1518.
+
++ Make __swap32 and __swap16 inline routines available globally as
+swap32 and swap16. eepro.c can use swap16 instead of making up one.
+
++ Make aui field in nic.h an int since it will be padded to a longword
+boundary anyway and call it flags so that other drivers can use it for
+their own purposes. Currently only 3c503 uses it to indicate AUI xcvr.
+
++ Make sprintf return number of characters written instead of a pointer
+to the last char written to be more consistent with standard C.
+
+Released as Etherboot 4.7.14 (development)
+
++ Thanks to Mark VandeWettering for the start of HomePNA (networking
+over phone lines) support for the AMD 79C978.
+
++ Bug fixed in first32.c handling of (ip|nfsroot)=X where X is not rom.
+
++ first32pm.linux works. No need to go into real mode to call first32pm
+and then it goes back to protected mode. Paves the way for extension
+routines to Etherboot.  Implement program returns to loader flag in
+header field.  Added option to mknbi to specify this.
+
++ first32*.linux: Check tag 128 present and correct before appending tag
+129. Also tag 129 should be appended to parameters before substitutions.
+
++ Merged cleanup_net into cleanup since they are always called together.
+
++ Floppy booting doesn't need to be passed BOOTP_DATA_ADDR.
+
++ Clean up variables associated with tagged image loading in osloader.c.
+
+Released as Etherboot 4.7.15 (development)
+
++ Duplicated 3c900 PCI IDs under 3c595 as some NICs apparently detect
+and work with the 3c595 driver but not the 3c90x driver, according to a
+report from Dirk Pfau. (The 3c90x series has two modes of operation,
+programmed I/O mode descended from the 3c509, good only for 10 Mb
+operation, and bus mastering mode, essential for 100 Mb operation. For
+network booting, either mode is acceptable.)
+
++ Removed auto from kernel parameters; it's the default already.
+
++ Use hardware timer instead of loop counter for transmit timeout in
+3c90x.c.
+
++ Define a jmpbuf type for setjmp and longjmp. Trim size to 7 longs,
+that's all that's needed. Standardise the return values from longjmp:
+-2: loader error, -1: timeout or ESC, 0...: various meanings to
+Etherboot main loader.
+
++ Ansify function headers in bootmenu.c.
+
++ Make _int10 return ax | (bx << 16) as result so that these can be
+accessed more efficiently in the following statements.
+
++ Make handleansi take unsigned int instead of unsigned char as
+argument, otherwise extra code will be generated to handle this
+according to ANSI rules.  (Quite significant saving of 55 bytes.) Rename
+it ansi_putc for clarity.
+
++ Prefix getc, putc and ischar with console_ to make things clearer and
+to avoid confusion with the Unix getc, putc.
+
++ Add menu as a target to mknbi. Started source code for menu extension.
+Successfully transferred control to menu at 0x10000 and back. ANSI
+colour controls work, at least. Return end needs more work.
+
++ Started on ELF support in mknbi.
+
+Released as Etherboot 4.7.16 (development)
+
++ Added atftp 0.2 (ftp://ftp.mamalinux.com/pub/atftp/) to contrib/.
+Supposedly contains a tftpd that runs multithreaded, which may help
+people having problems with *inetd shutting down tftpds that spawn too
+fast.
+
++ Added a few more Tulip entries to config.c and NIC, not all of them
+have been confirmed working.
+
++ Got ELF format creation in mkelf-linux working now. At least one empty
+section header is required to make a valid ELF file.
+
++ Added code to support non-MULTIBOOT ELF when IMAGE_ELF is selected but
+IMAGE_MULTIBOOT is not.  Booting from images created by mkelf-linux
+now works!
+
++ TAGGED_IMAGE is now not always selected. It's just the fallback if
+none of TAGGED_IMAGE, AOUT_IMAGE or ELF_IMAGE is selected. Therefore you
+must explicitly select TAGGED_IMAGE if you want it, and you have
+selected AOUT_IMAGE or ELF_IMAGE.  Startup banner line displays all
+image formats accepted.
+
++ exit() in mknbi/start32.S should copy argument to %eax first.
+
++ Images with 0xAA55 in bytes 510-511 are no longer accepted, which
+should reject invalid formats now, e.g. Linux kernel images, which have
+a boot sector in the first block. Strictly this does not conform to the
+original netboot spec by Jamie Honan, which specifies that non-tagged,
+linear images starting from 0x10000 are allowed, but that format is
+pretty useless now. Any decent loading scheme needs a roadmap to the
+blocks in the downloaded file, which is what tagged, a.out, or ELF
+images provide in the header. Q: What is config_buffer in main.c for?
+Nothing else seems to use it. Is it a relic of non-tagged images?
+
++ Clean up lots of obsolete prototypes in etherboot.h. Ansify lots of
+function headers in main.c. Make lots of functions and variables in
+main.c static.  Make bootmenu.c:getoptvalue() static.
+
++ Simple external menu program works!
+
++ More documentation cleanup, notably editing the compile options to
+match what has been done.
+
+Released as Etherboot 4.7.17 (development)
+
++ Marty Connor did it again! He found a long standing bug in the PnP ROM
+header which caused it not to be recognised by BIOSes. Now Etherboot ROM
+images are PnP compliant. I hacked makerom.c to fill in the offset of
+the ident string for the device string so that the BIOS can even print
+out "Etherboot" and the device ident on boot up.
+
++ Made demo menu program a bit more elaborate with timeout.
+
++ Igor V. Kovalenko fixed the Winbond W89C840 driver to use the hardware
+timer instead of CPU counter loops. Now none of the Etherboot drivers
+rely on CPU speed dependent loops.
+
++ Small fix to contrib/p910nd.c to not use getprotobyname which requires
+libnss_files.so, which may not be installed in all environments.
+
++ Small change to contrib/mkffwnb to allow the user to choose ELF format
+(by editing one line) instead of tagged format.
+
++ Patch to atftp-0.2 to make it accept a filename if the directory is a
+prefix of the filename. This is needed so that valid absolute pathnames
+will work. Patch sent to atftp authors.
+
++ Added support for filtering out replies which do not include a Vendor
+Class Identifier of "Etherboot" in the Vendor Encapsulated Options. This
+can be used to select only the DHCP servers which we want to get
+addresses from and reject the rest.  Select the compile option
+-DREQUIRE_VCI_ETHERBOOT. This requires ISC DHCPD 2 or 3 AFAIK.  (It's
+not documented in DHCPD 2, but it works.) Other DHCP servers may support
+VEO. (It's a RFC2132 option.)
+
++ Jim Thomas suggested a way, other than creating /fastboot, of
+preventing fsck from running on NFS root, ln -s /bin/true
+/sbin/fsck.nfs. Not verified but should work. Added to documentation.
+
+Released as Etherboot 4.7.18 (development)
+
++ Pavel Tkatchouk verifies that lance.c can handle PCnet-FAST III
+79c973. Added a new entry to lance.c and NIC. NIC entry not verified
+yet.
+
++ Enhanced disnbi to decode ELF images too.
+
++ Arrgh! There are old BIOSes that rely on the wrong order of the bytes
+in the device identifier in the PCIR and PnP structures. Wrote a Perl
+program swapdevids.pl to swap these bytes. Apply this to image file just
+before programming the EPROM.
+
++ Marty Connor suggested that the specs state that for PnP ROMs the
+unsuccessful return from boot should be int 0x18 rather than int 0x19.
+Using int 0x19, selecting L for local device doesn't work. Fixes needed
+in both loader.S and start32.S (get lret to work properly, instead of
+doing an int 0x19 directly, involved saving ss and sp in real mode
+instead of in protected mode).
+
++ Wrote a Perl program disrom.pl to display key structures of a ROM
+image.
+
++ Added call to binmode() in various Perl utilities so they should work
+under other OSes.
+
++ Added check in makerom.c to warn if 55 AA not found at start of image.
+It seems some people don't read the warning not to use the Linux
+supplied as86.
+
++ It seems Z is a recent addition to pack/unpack formats in Perl and
+even a Perl as recent as 5.004 doesn't implement it. Change Z5 in
+mknbi.pl and TruncFD.pm to a5 since we only need to compare it against
+'FAT12' and 'FAT16'.
+
++ Some errors found in osloader.c in the #ifdef IMAGE_MULTIBOOT
+sections.  kernel should be KERNEL_BUF and union info should have
+unsigned short s[256];. Also kernel -> KERNEL_BUF for IMAGE_FREEBSD,
+obviously few FREEBSD users have tried compiling it.
+
++ Explain in docs that .com and .(lz)lilo images can be generated and
+touch briefly on how to use them.
+
++ Donald Christensen contributed translations of floppyload.S and
+loader.S to gas syntax. Currently they are in contrib/gassyntax/.  They
+potentially allow us to throw away as86 and/or nasm and use GNU tools
+throughout, but I have to do some work on them: 1. I have to check what
+versions of gas accept the syntax, the 16-bit mode in gas was a recent
+enhancement; 2. I have to put back the #ifdef PCI_PNP_HEADER into
+loader.S and also bring it up to date to the recent patches.
+floppyload.S should be usable as is.
+
+Released as Etherboot 4.7.19 (development)
+
++ Donald Christensen completed the translation of loader.S and all the
+other .S files in the src directory that previously required as86 or
+nasm. No more futzing around with precompiled versions. Yipee!
+
++ Luigi Rizzo contributed a slightly hacked FreeBSD loader that works on
+floppy or hard disk. See boot1a.s for details. Makefile rules edited.
+Targets renamed .dsk and .lzdsk to indicate they're not floppy specific
+now. Documentation updated. I note that the loader is smart enough to
+figure out exactly how many sectors have to be read.
+
++ Renamed comload.S to comprefix.S which describes it better.
+
++ mknbi tools split out into separate package for independent
+development.
+
++ Use A32 instead of Z32 in unpack format in disrom.pl in case we
+encounter old Perl versions (< 5.005).
+
++ Vendor Class Identifier string that's sent out is now of the form
+Etherboot-x.y (13 bytes long).
+
++ Reduced size of ee_data in davicom.c to 32 bytes because we only need
+to access the MAC address in bytes 20:25.
+
++ Changed type of formal arguments to pci.[ch] routines to unsigned int
+except for the last argument, because in ANSI C parameter passing is
+like assignment and extra dummy variables and code may need to be
+generated if the formal argument type is not the the same size as the
+actual argument that gets pushed on the stack. Not insignificant
+overhead, reduction from 1853 to 1727 bytes due to change. Changed devfn
+and bus members of struct pci_device to unsigned char to enforce limit
+on type. Surprisingly this reduced the size further to 1667 bytes.
+Probably the compilier could do more optimisations after the last
+change.
+
++ Some drivers hardwired 0 for bus number in calls to pcibios_*
+functions. Changed to pci->bus, which is set in scan_bus. Only
+people with NICs not on bus 0 would have noticed.
+
++ Found a couple more old-style pre-ANSI C function declarations. Turned
+on -ansi and -pedantic for kicks and fixed some non-ANSIness, e.g.
+// comment in #define, text after #endif, casting memcpy arguments to
+void *, using void * instead of char *. Some char declarations changed
+to unsigned char.
+
+Released as Etherboot 4.7.20 (development)
+
++ I changed my mind. I think the format in disrom.pl should be Z32,
+otherwise it displays binary characters after the valid part of the
+string. For people with Perl < 5.005, please upgrade.
+
++ Moved RELOC down to 0x94000. Turned on USE_INTERNAL_BUFFER by default.
+Unless BOOTP_DATA_AT_0x93C00 is defined, use internal bootp strucutre.
+This gets Etherboot out of the area just below 0x10000 and the area from
+0x93C00-0x93FFF. DHCP packets can now be as large as the Ethernet
+payload. Later on, first32.c and the parameter area could expand a bit.
+In lance.c had to reduce RX_RING_SIZE (by reducing LANCE_LOG_RX_BUFFERS)
+from 16 to 4 to fit the driver. I'd like to hear feedback from lance
+users. Is 24kB of receive buffers really needed given that Etherboot
+uses stop-wait protocols?
+
++ Doug Ambrisko sent in some patches for FreeBSD: a correction for one
+typo I missed and changes to make compilation under FreeBSD easier.
+
++ Michael Sinz contributed patches to allow the FreeBSD loading code to
+load debugging symbols also.
+
++ Marty Connor contributed a SiS900 driver. Also pointed out that if
+ASK_BOOT <= 0, the prompt and read shouldn't even happen. Conditional
+code reworked.
+
++ Split documentation into user manual and developer manual. Added
+material.
+
+Released as Etherboot 4.7.21 (development)
+
++ Preston Wilson pointed out that ds.internic.net should be replaced by
+www.ietf.org in documentation URLs. Also RFC1090 should be RFC1094
+(NFS).
+
++ Marty Connor pointed out some broken links due to the split in
+documentation. Also comments don't match code in lance.c for change just
+above. Also passed on a bug found by a user of rom-o-matic.net where
+tftp was not defined when ANSIESC was defined. My mistake, I made it a
+static function when it needs to be exported to ansiesc.c.
+
++ Christoph Plattner found that the Etherboot startup messes up the
+flags while testing for a 386+. This doesn't affect Etherboot but it can
+cause the loaded operating system to crash. Fix: pushf before and popf
+after the CPU model testing.
+
++ Jean-Jacques Michel contributed patches to the via-rhine.c driver to
+make it work for the VT6102 model as used on some DFE530-TX Rev.A3 NICs.
+
++ Luigi Rizzo sent in a fixed boot1a.s that actually works on HDs now.
+
++ Stefan Furtmayr sent in a list of URLs to TFTP servers for NT. Added
+to directory contrib/Diskless-From-NT.
+
++ Paul Whittaker contributed a HOWTO in HTML format on booting with NT
+as the server.  Added to directory contrib/Diskless-From-NT.
+
++ CJ pointed out that the advertised message size is > 1500 bytes.
+Define MAX_BOOTP_EXTLEN so that the size of the structure matches the
+Ethernet payload size.
+
+Released as Etherboot 4.7.22 (development)
+
++ Reintroduce the old Via-Rhine PCI IDs into file NIC and give the
+corresponding ROM images -old suffixes, in case some people are using
+the old chips.
+
++ Peter Kögel contributed patches to the SiS900 driver to make it work
+for the SiS630e and SiS730s.
+
++ Charles Dobson pointed out that when booting from a PnP BIOS, the code
+should not hook or restore the INT19H entry point.  Put hooking code
+inside #ifndef PCI_PNP_HEADER and changed entry point in PnP structure
+from start19h to blockmove.
+
++ I have one report that gas 2.91 doesn't assemble loader.S because it
+can't handle all the 16-bit code. Since the benefits of using gas for
+all assembly code are great, and gas 2.95 has been out there for a long
+time, I regretfully say to affected users: upgrade your tools. Otherwise
+there may be a workaround by specifying the opcodes literally.  I leave
+it to interested parties to try. If you do this, put in an #ifdef
+GAS291, naturally.
+
++ Updated contrib/tftp-hpa to 0.16 from ftp.kernel.org.
+
+Released as Etherboot 4.7.23 (development)
+
++ Rename nepci entry in file NIC to rtl8029 to avoid giving the
+impression that nepci will work for all PCI NE2000 clones. Make the
+issue of PCI IDs in ROMs clearer in documentation, both in the
+configuration and troubleshooting sections.
+
++ Tania Oka and Hyun-Joon Cha at about the same time found that
+implementing the rtl_disable() routine in rtl8139.c stopped random
+crashes in Linux later. It is important to disable the NIC after network
+loading.
+
++ Implemented _disable() routine in w89c840, 3c90x and via-rhine drivers
+too. Don't know how to do it for epic100.
+
++ p910nd-0.4 in contrib/ has -f device option now to specify other
+printer ports, e.g.  USB.
+
++ Robb Main found a bug with the #ifdef logic in loader.S. This may fix
+problems with BIOS detection.
+
+Released as Etherboot 4.7.24 (development)
+
++ Paolo Marini sent in some code to make it work on his bare metal (no
+standard BIOS or peripherals) platform. This may be a useful starting
+point for some applications. See contrib/baremetal/.
+
++ Eric W. Biederman contributed a Perl script in
+contrib/award_plugin_roms/ to list flash BIOS plugin components.
+
++ Marty Connor rewrote the Tulip driver to handle many more variants.
+
++ For PCI ROMs loader.S can now detect if it's being called from a PnP
+BIOS and choose to hook INT19H if not.
+
++ Pass struct *rom_info in priv_data to probe routine. This is to allow
+drivers to decide, based on the ROM address, which one of multiple
+instances of identical network adaptors to activate. Started on 3c509
+code to use this but need to understand 3c509 contention resolution
+mechanism first.
+
++ Link src/lzhuf.c to contrib/compressor/lzhuf.c so that we don't need
+to refer to contrib/compressor/lzhuf.c anymore in Makefile.
+
+Released as Etherboot 4.7.25 (development)
+
++ Minor documentation edits, merged in NIC entries for newly supported
+Tulip variants from Marty Connor.
+
++ One last minute change, Robb Main suggested calling cs89x0_reset()
+from cs89x0_disable() to shutdown the hardware cleanly.
+
++ Updated tftp-hpa to 0.17.
+
++ Slight mod to lzhuf.c to make compression statistics report shorter.
+
+Released as Etherboot 5.0.0 (production)
+
++ Donald Christensen found a small bug in osloader.c. Not all context
+was cleared on tftp restart which caused restarted tftp loads to fail.
+
++ Correct a small error in setting %sp when not running at 0x9xxxx.
+Now relocation to 0x84000 works.
+
++ Marty Connor added a generic Tulip entry and renamed the Macronix
+entries because PHP doesn't like strings starting with digits (for
+rom-o-matic.net).
+
++ In loader.S, move code to save ROM segment and length to before jump
+to new segment, otherwise if MOVEROM is defined, then the ROM segment is
+always 0x8000. In etherboot.h, define an inline function to say if a ROM
+address is ok to boot from. Allow if < 0xC0000 or matches assigned ROM
+address of NIC.
+
++ Thomas Kessler found a bug in vendortags.sgml re option-NNN tags in
+dhcpd.conf, the wrong syntax was presented. However on trying the
+option-NNN syntax documented in the dhcp-options man page, it was
+discovered that option option-NNN is no longer supported in the old way
+in recent versions of ISC dhcpd v3; a new syntax should be used. Added
+note to vendortags.sgml to warn users.
+
++ Incorporated changes suggested by Hannu Martikka to #define
+DEFAULT_KERNELPATH in etherboot.h for rarp(), and display the TFTP
+server address before filename in Loading: message.
+
++ Split off documentation into separate package in anticipation of
+production/development series split. Moved previous LOG to top level.
+Moved distribution section of index.html into separate web page so that
+index.html will be less ephemeral.
+
+Released as Etherboot 5.0.1 (production)
+
++ Arkadiusz Miskiewicz pointed out that --oformat should be used instead
+of -oformat as old ld accepts both while new ld requires --oformat.
+
++ contrib/{tftp-hpa,atftp} are distributed separately from the
+distribution page to make them easy to update.
+
++ Eric Biederman contributed many small changes in the code to improve
+the behaviour in exceptions and generally improve the code structure:
+
+1) Cleanup etherboot restarting.  There is now only one place that needs
+to test for EMERGENCYBOOTDISK.
+
+2) Change pci.c as I have suggested.  It is setup to scan every possible
+pci bus until it finds an etherboot card.
+
+3) Change osloader.c so that if an image that can return, but isn't
+supposed to it restarts etherboot with -2 instead of the returned value.
+
+4) Rewrites the delay logic so that we compute how long we should sleep,
+and then sleep the whole time in await_reply so in a congested networks
+we don't miss slow packets.
+
+5) divides load into load & load_configuration.  This removes the need
+for the weird bootp_completed variable.  And makes it a little more
+explicit what we are doing.
+
+6) add an interruptible_sleep function so that we can sleep and still
+process keystrokes.
+
+7) rewrites the restart logic:
+   - renames jmp_bootmenu to restart_etherboot.
+   - removes bootmenu (The function isn't)
+   - It explicitly does an eth_reset & eth_probe pair to reinitialize
+     the interface.  This should help if someone has plugged the
+interface into a different switch since booting started.
+   - moves ASK_BOOT and TRY_FLOPPY_FIRST into their own functions.
+   - On every restart calls ask_boot and try_floppy_first.  Allowing you
+     to change your mind on how you want to boot after network booting
+starts.
+
+8) In cleanup calls both eth_disable (to disable the interface) &
+eth_reset to make certain the interface can be initialized from linux.
+(If nothing else this should cause more hidden bugs to show up).
+
+9) Restart etherboot when downloading a bootfile fails, instead of just
+looping trying to get that file.  Allowing typos in dhcpd.conf to be
+corrected without having to reboot the client machine running etherboot.
+
+Released as Etherboot 5.1.0 (development)
+
++ All the changes from 5.1.0 carried over except calling eth_reset()
+from cleanup().
+
++ Marty Connor, funded by Sicom System (http://www.sicompos.com/), wrote
+a driver for NICs based on the National Semiconductor DP83815, e.g.
+Netgear FA311/FA312. Also independently created by Jason McMullan just
+at the time Marty released his driver. Thanks for the effort Jason;
+great minds think alike. Both are based on Donald Becker's Linux driver,
+of course.
+
++ Doug Ambrisko contributed a patch to take environment bindings for
+FreeBSD kernels from a BOOTP/DHCP option or config variable.
+
++ Dax Kelson contributed an example of an ISC DHCP config file that uses
+Vendor Class Identifier to tailor the response to Etherboot clients.
+Also discovered that the Etherboot VCI should also be sent in the
+DHCPREQUEST message, in addition to the DHCPDISCOVER message.  Note that
+the DHCP server must be set to non authorititative if you have an
+authoritative server running already or it will interfere with that
+one's operation.
+
++ Peter Lister and Vasil Vasilev contributed changes to generate .pxe
+images bootable via PXE.
+
++ Eric Biederman added code to 3c90x.c to enable the NIC: set up
+busmastering and set the latency timer in case the NIC is not already
+set correctly, and fixed a couple of related bugs in eepro100.c.
+Verified that the 3c90x driver works for the 3c980.
+
++ Moved strncmp from osdep.h to linux-asm-string.h. Use the general
+version using string ops, not the deprecated 486 version (what was I
+thinking).  Also added strlen, needed for FreeBSD patch above.
+
++ Thanks to gcc 3.0, found and corrected a couple of C constructs of
+undefined semantics in rtl8139.c and lance.c of the form: i = ++i &
+MASK;
+
++ In Config/CFLAGS32: changed -m386 to prefered form, -mcpu=i386,
+changed -O2 to -Os, and added -ffreestanding. These changes allow
+warning-free compilation under gcc 3.0. Only mimimal testing has been
+done with gcc 3.0 compiled binaries, we hope there are no problems but
+don't throw away your gcc 2.9.5 yet.
+
++ Added an .org 0 to loader.S just before _start. May or may not fix
+alleged assembly problem with gas 2.11.
+
++ Cosmetic change: in boot1a.s replaced "loaded" with "done\r\n" so that
+Etherboot messages start at beginning of line.
+
++ More improvements to contrib/mkffwnb.
+
+Released as Etherboot 5.0.2 (production)
+
++ Added missing rules in genrules.pl for .pxe and .lzpxe images.
+
++ Peter Lister unified pxeloader.S into loader.S. pxeloader.S not
+required now. Also fixed .lzpxe.
+
++ Added missing int i; declaration in try_floppy_first().
+
++ Load %edx with dev just before calling xstart in floppy.c:bootdisk()
+so that %dl will have device number, just like entry from BIOS.
+
++ Merged in Eric Biederman's patches to build .ebi images that run under
+LinuxBIOS. To make an image, edit Config to enable the EBI options (and
+disable TAGGED_IMAGE), then make bin32/driver.ebi, where driver is the
+name of a supported PCI NIC.
+
+Released as Etherboot 5.1.1 (development)
+
++ The rotating bar progress display has been replaced by a sequence of
+dots, one for each transmitted packet. This is kinder to dumb displays,
+e.g. serial terminals, and gives a better feel for how the loading is
+going. If you want the rotating bar, use -DBAR_PROGRESS.
+
++ In loader.S change .fill 0x18-(.-_start) to .org 0x18. Might help
+people having errors assembling it.
+
++ Do Jong Gwan found a 3Com 980 with PCI ID 0x9805. Added to config.c
+and NIC. Added for good measure 0x7646 which is listed as 3CSOHO100-TX
+in Linux kernel 3c59x.c.
+
++ Add a rule to the Makefile to check for gcc 2.96, which is buggy, and
+tell the user to use kgcc instead if found.
+
++ Till Straumann added long-needed code to warn when fragmented packets
+seen (encountered on a wireless link) and to do UDP packet checksumming.
+
++ A trio of patches from Klaus Espenlaub, to fix a lance ring pointer
+error in lance.c, to fix a format error in the multiboot call in
+osloader.c and a patch to enable powersaving while waiting (good for
+compute clusters and VMware), this one requiring the new option
+-DPOWERSAVE in compiles.
+
++ While we are adding compile options, -DFLOPPY has been renamed to
+-DCAN_BOOT_DISK as FLOPPY has been a misnomer ever since the ability to
+boot /dev/hdX and /dev/sdX was added.
+
++ Spurred by correspondence from Till Straumann and Klaus Espenlaub,
+hacked printf to not require a buffer. Now printf output can be
+arbitrarily long as it no longer needs a buffer to assemble the
+characters before sending to putchar; it outputs on the spot for
+non-format chars and %s items, and at the end of the item for non-%s
+items.
+
++ DRIVER AND EXTENSION WRITERS NOTE! (s)printf formats have been changed
+to be a subset of those in glibc to reduce confusion. The changes are %x
+-> %hX, %b -> %hhX, and %I -> %@. Lower case x formats are also
+available now. The only variances from glibc are %@ for dotted quad IP
+addresses (formerly %I; %I is now used), %! for 6 byte Ethernet
+addresses, and that printf returns void. Thanks to Klaus Espenlaub for
+assistance on this, after adding the %! format, he cleaned up all of the
+Ethernet address display code in the drivers.
+
++ More cleanup patches from Klaus Espenlaub (he's better than lint;
+people who have used Bell Labs Unix will know what lint is). Changes
+noted here for posterity.
+
+3c509.c: consistent non-use of # modifier for debugging output
+3c595.c: consistent non-use of # modifier for debugging output
+3c90x.c: use optimal %x variant, PCI bus/function numbers are always small
+Config: Replace a TAB by two spaces inside the descriptions
+eepro100.c: 6->ETH_ALEN, PCI bus/function numbers are always small
+floppy.c: optimal %x variant
+genrules.pl: consistent use of TAB characters
+i82586.c: the ENET address printing patch for the EXOS205 got lost somehow....
+main.c: cleanup of the UDP_CHECKSUM comment some editor messed up, make the
+    assembly fragment use the normal formatting, fix the register assignment
+    specification for the %bx register to use the "b" constraint instead of
+    "bx" - the x makes no sense...
+natsemi.c: %X case fix...
+ns8390.c: optimal %x variant
+pci.c: fix bad Linux port (most messages truncated the hex values)
+sis900.c: a value read with inl() should probably(!) be printed with %X
+start32.S: move around the #endifs a little
+timer.c: fix space/tab characters
+via-rhine.c: all values "printed" inside the comments are 32 bit integers
+wd89c840.c: PCI bus/function numbers are always small
+
+Released as Etherboot 5.0.3 (production)
+
++ New version of contrib/Diskless-From-NT/furtmayer.html. I mangled the
+previous version by forgetting to extract with metamail so it was still
+quotable-printable encoded.
+
++ Renamed do_printf to vsprintf because that's the standard function it
+has the same signature as.
+
++ More patches from Klaus Espenlaub. In his own words:
+
+The patch to add UDP checksums for transmitted packets is attached.
+Just don't be surprised if some packet sniffer tells you that the
+checksum for the NFS_LOOKUP packets are wrong and that the filename is
+truncated.  It's a bug in the sniffer, not in Etherboot.
+
+Oh, and the small change in udpchksum() almost makes up for the
+increased code size.
+
+I also rewrote the NFS code to use pointers instead of array accesses.
+This reduced the code size by 124 bytes.  Patch attached.
+
+The last patch in this mail fixes misc things: a typo in misc.c
+(DOT_PROGRESS instead of BAR_PROGRESS), and twiddle() is only called if
+the packet type is IP.  This makes the output nicer - the dots are also
+printed in some non-approriate places for ARP reply packets.  The
+important packets are IP anyway.
+
++ The option BOOTP_DATA_AT_0x93C00 is deprecated, in preparation for
+expanding the parameter area and the first32.c area.
+
++ Marty Connor found a typo in index.html, should be: Etherboot can work
+with..., not Ethernet can work with... Ooops.
+
++ Eric Biederman tried a patch of Preston Wilson's and discovered that
+DI should be prefixed by ES in the test for a PnP BIOS in loader.S to be
+sure.  Furthermore some BIOSes are not fully compliant and we need an
+#ifndef PNP_BUT_NOT_BBS_COMPLIANT to work around that.
+
++ Oops, there's no entry in config.c for the DFE530TX+ even though
+there's one in NIC.
+
+Released as Etherboot 5.0.4 (production)
+
++ Fixed a struct alignment (8-byte constraint) problem in lance.c caused
+by the introduction of the rx_idx field by moving rx_idx to the end of
+the struct. Found by Rizsanyi Zsolt. Klaus Espenlaub also suggested
+increasing all the Rx buffers by 4 bytes because of the checksum stored
+at the end.
+
++ Fred Gray contributed changes in tulip.c to check for a duplex
+connection and to modify the controller register if so. Marty fixed an
+unassigned to "negotiated" variable.
+
++ Mark G of Inprimis Technologies contributed another FA311 (National
+Semiconductor DP83815) driver, also based on the Donald Becker Linux
+driver.
+
++ Armin Schindler contributed a patch to allow booting LynxOS KDI
+images.
+
++ Moved code to set PCI busmastering and reasonable latency to a routine
+in pci.c and added calls to this routine from all PCI drivers.
+
++ New files for contrib/mkffwnb for version 1.9.11 and 1.9.16.
+
++ Removed BOOTP_DATA_AT_0x93Cxx option.
+
++ Convert epic100 driver to use hardware timer for transmit timeout and
+remove polling loop from receive routine.
+
++ Steve Tilden pointed out that BOOT_INT18H is a LCONFIG option, not a
+CFLAGS32 option. Put note under option documentation and also added a
+commented-out example in Config. Steve also contributed a patch¸ in
+contrib/auto-default, which autoboots from the next device if a disk is
+detected.
+
++ PNP_BUT_NOT_BBS_COMPLIANT option renamed to BBS_BUT_NOT_PNP_COMPLIANT.
+
++ Merged in Vasil Vasilev's changes to loader.S to release memory taken
+by PXE properly.
+
++ E820 memory detection routines added by Eric Biederman. May increase
+size of bss segment and push large drivers, e.g. Tulip, nearer to limit,
+please report.
+
++ Default to -DCONGESTED in Config, may help on busy networks.
+
++ Add Holtek HT80232 to list of NE2000 PCI clones.
+
++ Remove prohibition on loading < 0x10000 in ELF images since by default
+drivers don't use memory < 0x10000 any more, with 48kB to run in.
+
++ Put define of ETH_MAX_MTU in etherboot.h inside #ifndef so that it can
+be overriden from Makefile.
+
++ Gustavo Junior Alves added .cvsignore files for src/bin and src/bin32.
+
++ Short note on how to make tomsrtbt netbootable in contrib/tomsrtbt.
+
+This release is dedicated to the memory of my mother (July 1917 -
+November 2001) [Ken Yap].
+
+Released as Etherboot 5.0.5 (production)
+
++ Changes to enable fa311too driver which were overlooked in 5.0.5.
+
++ Chien-Yu Chen sent in patches to support the SiS630ET. Independently,
+Doug Ambrisko made the same changes. Marty Connor tidied the patches.
+
++ In misc.c, when enabling/disabling Gate A20, call int 0x15 with
+ax=0x240x to do handling first, and if that is not supported, fall back
+to using the keyboard controller. Hopefully this will solve Gate A20
+problems for recent BIOSes.
+
++ Add missing entry to config.c for the Macronix 98713 (device ID
+0x512). But latest report is that it doesn't transmit. Anybody wanna
+debug?
+
++ Omit test for pointer to $PnP string for ISA NIC images, it may
+trigger false recognition of a PnP ROM. Just use legacy mode.
+
++ Merged in Christopher Li's Intel E1000 gigabit Ethernet driver.
+
++ RISKO Gergely found that the ADMTek Comet 983 works with the tulip
+driver if you provide the right PCI IDs.
+
++ Rohit Jalan contributed patches to support FreeBSD booting via PXE.
+(genrules.pl needed hacking to make it ignore the system includes in
+osdep.h.)  Anybody want to see if it can be made to support pxelinux?
+[Glanced at it and I think general PXE support may be hard, you may need
+an Etherboot specific secondary loader. - Ken]
+
++ Merged in Eric Biederman's patches to allow trying all PCI devices.
+
++ From Eric Biederman: A small patch to allow the serial port parameters
+to be unchanged at activation.  Major changes to start32.S to merge
+LinuxBIOS support.  New files for LinuxBIOS support.  PCBIOS specific
+functions split out into pcbios.S. Massive clean up of PCI subsystem
+logic.
+
++ Jean-Jacques Michel sent in a fix for via-rhine.c to make sure the
+transmit is finished before returning from the _transmit routine.
+Also found a bug in gcc 3.0.3 that affected rtl8139.c. Moving the
+assignment to nstype in _transmit two lines up avoids it.
+
++ Based on the experience of Yedidyah Bar-David, in eepro100.c,
+increased udelay around line 533 after getting MAC address to
+udelay(10000).
+
++ Added PCI IDs for RTL8129, which can use the rtl8139 driver.
+
++ Added PCI IDs for 3Com905 with device ID 0x9058. Confirmed working by
+Fabio Papa.
+
++ Added PCI IDs for D-Link 528, which is a PCI NE2000 clone.
+
++ Philip R. Auld found a block number rollover bug due to promotion to
+signed in main.c.
+
++ Luigi Rizzo sent in a patch to nfs.c to implement an adaptive timeout.
+
++ New config files for floppyfw-1.9.19 in contrib/mkffwnb/.
+
++ Glenn McKechnie contributed a Perl script for making a netbootable
+image from the Dachstein LRP firewall distribution floppy. It's in
+contrib/mklrpnb/
+
++ At the request of Greg Beeley, who got irate mail from kernel NIC
+developers, put in a warning in the Makefile about the 3c90x XCVR
+options which may affect later operation with the Linux driver. For you
+tinkerers out there, if you don't know what you're doing, please read
+3c90x.txt over and over again until you understand what those options
+do. If you don't understand, please ask on the Etherboot mailing list.
+And don't complain to the kernel developers, it's nothing to do with
+them. If you must change the XCVR options on a board, please document it
+prominently on the board so that those who come after you won't
+encounter strange behaviour and complain to the kernel developers.
+Greg also supplied a patch to 3c90x.c to print a warning message.
+
+Released as Etherboot 5.0.6 (production)
+
++ Andrew Bettison sent in a patch and the explanation: Here's a patch
+for some changes I made to Etherboot-5.0.6 because it didn't work with a
+SMC EtherEZ in an old PCI/ISA bybrid bus system.  The ISA shared memory
+isn't accessible on many such systems, so the only way to do I/O to the
+card is in Programmed I/O mode.  I studied the Linux 2.2.19 driver
+(drivers/net/smc-ultra.c) and hacked what I figured was equivalent code
+into src/ns8390.c, and it eventually worked.  All my new code is enabled
+with -DWD-790_PIO.
+
++ Small error in the ADMTEK Comet 983 IDs fixed.
+
++ Michael Rendell sent in patches for 3c90x.c to get the MAC address
+from location 10 of the EEPROM onwards, like the Linux driver does. Some
+905s have the MAC address at both 0 and 10 which is why it worked for
+some boards.
+
++ Michael Brown sent in drivers for 3 wireless NICs based in the prism2
+chipset, and a small patch to rtl8139.c to abort detection on no link.
+
++ Rewrote makerom.c in Perl to give makerom.pl.
+
++ Rewrite genrules.pl to parse a new NIC format.
+
++ Timothy Legge contributed a 3c515 driver. Requires a ISA PnP BIOS.
+
++ Modified call to int15h/e801 in pcbios.S to check for return values in
+CX, DX in case BIOS doesn't return them in AX, BX.
+
++ Richard Chan sent in PCI IDs for another Intel EEPRO100 product.
+Omigawd will they ever run out of EEPRO100 model numbers. :-)
+
++ Changed location of setup header from 0x97e000 to 0x93e000 in
+mkQNXnbi.c for recent Etherboot versions.
+
++ Renamed membase to addr1 to reflect its lack of predefined meaning in
+PCI config space. Should do similar to ioaddr, but too much work.
+
++ Samuel Clememts found another Intel EEPRO100 device ID, 0x1039.
+
++ Updated instructions in contrib/tomsrtbt for latest 2.0.103 release.
+
++ Folded in changes by Michael Brown to send PCI and ISA IDs to the
+server and to encapsulate Etherboot specific options. Changed scheme to
+send fixed binary structure instead of variable length string.
+
++ Bug in sis900.c, wrongly classifies revisions 0x81 and 0x82 because
+first test catches too many revisions. Changed to match the Linux
+driver.
+
++ Fotis Andritsopoulos found a small bug in cs89x0.h, TX_AFTER_ALL
+should be 0x0C0.
+
++ Great idea by Eric Biederman. Ignore DHCP offers with zero server
+IP, or null filename unless DEFAULT_BOOTFILE is defined. This will
+ignore most Windows DHCP servers.
+
++ Patrik Weiskircher sent in a patch for rtl8139.c to bring it up to
+date with the Linux driver.
+
+Released as Etherboot 5.0.7 (production)
+
++ Multicast support and LOTS of other changes by Eric Biederman.
+
++ Builtin menuing has been removed.
+
++ Patches for FreeBSD by Doug Ambrisko.
+
+Released as Etherboot 5.1.2 (development)
+
++ Fix syntax errors in nfs.c.
+
++ Patch for tagged image loading by Miles Nordin.
+
++ Patches for new eepr100 variant by Georg Baum.
+
++ Fixes for typos by Adam Sulmicki.
+
++ Fixes by Eric.
+
+Released as Etherboot 5.1.3 (development)
+
++ Eric rearranged files for multiple platforms, including Itanium.
+
+Released as Etherboot 5.1.4 (development)
+
++ Lots of fixes to drivers, see CVS for details.
+
+Released as Etherboot 5.1.5 (development)
+
++ Eric added support for the AMD Hammer.
+
++ Geert Stappers found a VIA6105 (via-rhine.c) with id 0x3106.
+
+Released as Etherboot 5.1.6 (development)
+
++ Broadcomm TG3 support by Eric Biederman.
+
++ Georg Baum found that the start16.S prefix was missing from the LILO
+and PXE images, those formats were broken. He also migrated the PCI IDs
+into the driver files. Those formats should work again.
+
++ Reworked genrules.pl. Family declarations now in here document inside
+genrules.pl. NIC is now an output file, for use by rom-o-matic.
+
+Released as Etherboot 5.1.7 (development)
+
++ Fixed various syntax errors that made the source not compile with some
+configurations.
+
++ Hacked boot1a.s to take count of number of blocks to boot from book
+block itself in new scheme.
+
++ Dave Airlie found a patch for an old bug in eepro100 driver on Linux
+that applies to Etherboot driver too.
+
++ Add use bytes; pragma to Perl scripts to avoid problems with UTF-8
+handling of input data.
+
++ Replace boot1a.s with floppyload.S which has no problems loading large
+binaries. Lose the ability to boot from disk partition. Use LILO or
+something similar.
+
++ Morten Kristiansen sent in a patch to handle another variant of the
+SiS 900.
+
++ Fix for eepro100 timing problem by Georg Baum.
+
++ Add use bytes; to Eric's Perl scripts too.
+
++ Additional fix to mask interrupts after PortPartialReset by Georg
+Baum that might help with booting DOS.
+
++ Sundance driver contributed by Timothy Legge.
+
+Released as Etherboot 5.1.8 (development)
+
++ Fix for correct SMC8416 detection.
+
++ Alignment bug fix for the 3c90x driver contributed by Neil Newell.
+
++ Robb Main found a bug in appending the MACHINE_INFO to the DHCP request.
+
++ SONE Takeshi fixed the Multiboot structure.
+
++ Patch from Axel Dittrich to allow timeout to be changed to a fixed
+value for peer-to-peer setups where the exponential backoff is not
+suitable.
+
++ Tlan driver contributed by Timothy Legge.
+
++ Support for symlinks on NFS mounts by Anselm Martin Hoffmeister.
+
++ Experimental safe booting code by Anselm Martin Hoffmeister.
+
++ Run Etherboot in an even megabyte so that unsetting A20 won't kill it.
+Experimental UNDI driver by Michael Brown.
+
+Released as Etherboot 5.1.9 (5.2 release candidate 1)
+
++ 82562EZ ID provided by Samuel Clements.
+
++ Rename Local option as Quit, because that's what it really is.
+
++ Should prepend start16.bin to .com images, they didn't work and nobody
+noticed.
+
++ PM stack was getting clobbered by zeroing of BSS, move to own segment
+in etherboot.lds. Move %ss out of the way of Etherboot in comprefix.S.
+Now Q works from .zrom and sort of from .com (DOS is odd after return).
+
++ Make ASK_PROMPT reflect the device options available.
+
++ Removed many outdated comments and updated others.
+
+Released as Etherboot 5.1.10 (5.2 release candidate 2)
+
++ Make floppyload.S and liloprefix.S call instead of jmp to the image so
+that the return calls int 0x19, which is somewhat better than
+hyperspace.
+
++ Put http://etherboot.org in prompt and ID string.
+
+Released as Etherboot 5.2.0 (production)
+
++ Print F? if no filename in DHCP offer.
+
++ Make lance.c throw a compile error if -DRELOCATE is used.
+
++ pcnet32 driver ported by Timothy Legge.
+
++ Reinstate boot1a.s in arch/i386/prefix. The binary may have some uses;
+it boots with vmware although the image fails later in the emulation.
+
+Released as Etherboot 5.2.1 (production)
+
+CVSed as Etherboot 5.3 (development)
+
++ Break out etherboot.h into multiple files along protocol lines.
+
++ Georg Baum's conversion of a more recent version of the Linux e1000
+driver.
+
++ Add mini-slamd to contrib/, it was missed during 5.2 release.
+
++ Timothy Legge enabled multicast for a bunch of drivers. Tested with
+mini-slamd.
+
+Released as Etherboot 5.3.0 (development)
+
++ Timothy Legge rewrite proto_tftm.c, got multicast working with atftp
+and enabled multicast for the Tulip.
+
+Released as Etherboot 5.3.1 (development)
+
++ Günter Knauf sent in a new version of romid that handles the new
+and old IDENT format.
+
++ Cai Qiang fixed the WINCE loader. It needs to handle > 512 byte packets
+and also the buffer has to be static. Also submitted a driver for VGA
+which can be activated by CONSOLE_DIRECT_VGA.
+
++ Improved tg3 driver by Eric Biederman. New define in etherboot.h:
+VALID_LINK_TIMEOUT.
+
++ Timothy Legge and I fixed up various ISA drivers to be less noisy
+when probing, from information provided by Paolo Salvan, so that the
+super etherboot image is more useful.
+
++ Proof of concept of a TFTP to HTTP proxy in contrib/t2hproxy/.
+
+Released as Etherboot 5.3.2 (development)
+
++ Multicast support for the ns8390 (NE, WD, etc) added by Timothy Legge.
+
++ Provide config access to alternate DHCP/BOOTP ports. The macro
+ALTERNATE_DHCP_PORTS_1067_1068 switches to ports 1067 and 1068.
+
++ UNDI driver by Michael Brown.
+
+Released as Etherboot 5.3.3 (development)
+
++ More UNDI improvements by Michael Brown.
+
++ Michael Brown pointed out error in ASK_BOOT behaviour. Make it match
+documentation. < 0 or undefined means no prompt,  = 0 means wait
+forever, > 0 means wait that many seconds.
+
++ Start of PCMCIA subsystem by Anselm Martin Hoffmeister.
+
++ Port to Hyperstone architecture (big-endian) by Yannis Mitsos and
+George Thanos at NTUA, Greece.
+
++ Timothy Legge got the epic100 driver working again, was not working
+when 5.2 released. Also implemented multicasting. Also tentatively
+fixed the tg3 driver.
+
++ Use Perl script to make .z?lilo images.
+
++ Added an .iso Makefile rule. This requires newer BIOSes as it
+uses no floppy emulation mode.
+
++ Guard Kuo sent in a patch for the via-rhine driver not being
+reset properly, Timothy Legge improved it based in the Linux driver.
+
+Released as Etherboot 5.3.4 (development)
+
++ David D. Smith, with help from Georg Baum, sent in a patch for the
+eepro100 driver which might help unjam the NIC when the receiver has
+suspended reception.
+
++ Timothy Legge and Eric Biederman fixed a bug in the tg3 driver which
+caused some models to not receive DHCP replies.
+
+Released as Etherboot 5.3.5 (development)
+
++ Timothy Legge ported the Linux Realtek 8169 driver.
+
++ Michael Brown removed irritating A20 status change messages.
+
++ Sis900, w89c840 and tg3 drivers fixed by Timothy Legge. R8169 driver
+needs family entry in genrules.pl.
+
++ Revert to normal way of assigning string to DEFAULT_BOOTFILE as
+tricky stringify macro falls foul of C++ // comments in gcc 3.x.
+
+Released as Etherboot 5.3.6 (development)
+
++ Don't include ISA .o files for etherboot-pci.
+
++ Doug Ambrisko fixed bugs in the FreeBSD loader.
+
++ Anders Nystrom provided a tiny via-rhine patch
+
++ Introduce new define DEFAULT_PROTO_NFS for those who were used to
+using DOWNLOAD_PROTO_NFS in 5.0 for NFS booting.
+
++ Reverse sort PCI drivers so that 3c90x is tried ahead of 3c595.
+
++ Updated e1000 driver by Georg Baum.
+
++ New PCI IDs for 3c90x and tulip drivers. Typos in 3c90x and tg3
+drivers corrected.
+
++ Georg Baum fixed the 3c503 
+
++ Fixed Typos which caused compiling with RARP_NOT_BOOTP to fail
+
++ Fixed IMAGE_FREEBSD bugs
+
++ Cleanup of driver output (pcnet32, r8169, sundance, tlan)
+
++ Minor updates to the Config file comments
+
++ arch/i386/prefix/boot1a.S is no longer maintained
+
++ Added make rule for a floppy emulation ISO boot image
+
++ Timothy Legge updated proto_tftm to make it easier to maintain and
+  fix some issues
+
++ Timothy Legge contributed a forcedeth driver for the NVidia Force
+  NIC.
+
++ Timothy Legge contributed a ns83820 driver for National
+  Semiconductor 83820 based NICS
+
++ Ken Yap added support for creating .liso output type which is an iso
+  image with legacy floppy support
+
++ Michael Brown improved memory allocation, 16/32 mode swapping, and
+  did various code cleanups
+
++ Michael Brown added High-Level PXE API support (pxelinux) to Etherboot
+
+Released as Etherboot 5.3.7 (development)
+
++ Timothy Legge Fixed an issue in the e1000 driver with 82544 and
+  newer devices that support port I/O.  Enabled port io for the reset.
+  Without the patch the e1000 could not reliably boot Linux on some
+  cards.  Thanks to James Pearson, Georg Baum and Marty Connor for
+  help resolving this issue.
+
++ Michael Brown added lots of PXE code to complete implementation. He
+  also did a warnings purge of the core.
+
++ Marty Connor did warnings purge of the network drivers.
+
++ Anselm Martin Hoffmeister contributed DNS resolution code.
+
++ Lots of driver PXEifications and cleanups from Timothy Legge and
+  Marty Connor
+
++ Makefile and genrules fixes from Michael Brown and Marty Connor
+
++ BPBATCH workaround from Timothy Legge and Michael Brown
+
++ Timothy Legge improved image format detection logic.
+
+Released as Etherboot 5.3.8 (development)
+
++ Update to lance.c chip_table from Helge Wagner
+
++ Fixes to attributes to prevent gcc from optimising away seemingly
+unused functions and variables that are actually referenced from asm
+or in the linking stage. (Ken Yap)
+
++ Removed non-relocation support, relocation is now always active.
+Removed lance.c driver as this will not work with relocation. 32-bit
+Lance NIC users should use pcnet32. (Ken Yap)
+
++ Migrated SAFEBOOT to a patch set. This proof-of-concept code is
+incomplete and needs more work before becoming mainstream. (Ken Yap)
+
+Released as Etherboot 5.3.9 (development)
+
++ Patch from Tim Fletcher for another eepro100 model.
+
++ Patch from Jeremy Jackson to make DNS query recursive and fix sign and
+casting issues in dns_resover.c.
+
++ Paolo Salvan experimented with using isolinux for non-emulation
+images and contributed the first cut at the code for geniso.
+
++ Fix for relocation issue with prism2_pci driver
+
++ Small patch to support 3Com tulip version from Jacek Kalinski
+
++ Dag Lem provided a new pci_id for the eepro100 Intel "82801EB/ER 
+(ICH5/ICH5R)"
+
++ Small patch to support 3Com tulip version from Jacek Kalinski
+
++ Yinghai Lu contributed a large patch to add filo, bText and usb 
+support:
+       btext console: In LinuxBIOS, for the VGA, we only can 
+       enable display chipframe buffer and write char to framebuffer 
+       to get output in CRT.
+       
+       FILO: originally it is standalone boot program and 
+       author is TakeshiSone.
+
+       Boot from SATA disk.
+
+       Boot from USB disk (OHCI and UHCI).  USB boot is from Steven 
+       James 's baremetal in LinuxBIOS, moved to FILO and added the 
+       OHCI support to it 
+
++ armnommu arch support by Tobias Lorenz.
+
++ Driver updates/cleanup: rtl8139, sis900, tlan 
+
++ Updates to via-rhine based on input from Guard Kuo from Via Networking 
+Technologies, Inc
+
++ Update p910nd (port 9100+n printer daemon) to latest version
+
++ Fixed some bugs to enable compilation for gcc 3.4.x.
+
+Released as Etherboot 5.3.10 aka 5.4RC1 (development)
+
++ Changes to segment scheme to make large compressed images work.
+
++ .zelf images can be built now but still don't run properly. .zrom
+images may be broken.
+
++ Start of a .exe prefix which should allow payloads > 64kB.
+
+Released as Etherboot 5.3.11 aka 5.4RC2 (development)
+
++ Left out in last release's LOG: accepted patch from Jan Kiszka
+fixing default TFTP blocksize.
+
++ Fixed .z?rom image generation, they work now.
+
++ Patch from Jan Kiszka for for multiple receive buffers in eepro100
+driver.
+
++ Fixed 961507 Not so nice 'F?' message when no file name received
+
++ Small fixes to e1000 and via-rhine drivers.
+
++ New mtd80x.c driver contributed by Erdem Guven
+
++ New dmfe.c driver for Davicom based cards contributed by Timothy Legge
+
++ Added new definitions of site DHCP options in preparation for 5.4.
+
++ Removed etherboot(-pci)?.* rule because there are too many drivers and
+the image will no longer fit in memory. I don't want to choose a subset
+of drivers as everybody will have different preferences. So I'm going to
+piss off everybody equally by deleting the rule. Use the multiple driver
+rule (driver1--driver2--...) and select your own subset of drivers.
+
+Released as Etherboot 5.3.12 aka 5.4RC3 (development)
+
++ Changes to Makefile.main and Config to collect FILO objects in
+filolib.a.  This allows FILO to be excluded from compilation and linking
+with one Makefile define.
+
++ Reverse site DHCP option changes, should apply for official
+assignment.
+
++ RIS filename patch which seems to work for many people.
+
++ Thanks to the help of Daniel Nilsson, tracked down and fixed a bug
+where the tftp code did not fall back to 512 byte blocks when an OACK
+was NOT received.
+
++ Removed dead code related to CAN_BOOT_DISK.
+
++ Clarified that BOOT_DISK and BOOT_FLOPPY options only work with
+LinuxBIOS and are not replacements for PCBIOS functions.
+
++ Renamed EMERGENCYDISKBOOT to EXIT_IF_NO_OFFER.
+
++ Builtin menuing DHCP options are gone.
+
++ Paolo Salvan submitted changes to arch/i386/Makefile to make .com
+images compressed.
+
++ Eric Biedermann made .*elf images work again and cleaned up the build
+procedure in the process. The hardwired virtual RELOCADDR is no more,
+the virtual base is 0. He also added code to display which protocols are
+compiled into the image.
+
+Released as Etherboot 5.3.13 aka 5.4RC4 (development)
+
++ Lots of fixes by Eric Biederman.  Symbols for protected mode segment
+and prefix segments separated.  Multiple ASM statements combined to
+ensure compiler keeps them intact.  Allocate real mode stack if none in
+use.  Protect low memory interrupt vectors. Makefile rules for various
+prefixes factored. Dynamic relocatable image support.
+
++ Fixes by Michael Brown. Cleanup of PXE and UNDI code.
+
++ Patch to Tulip driver for missing PCI ID.
+
++ Fixes to genrules.pl by Kenneth Sumrall.
+
+Released as Etherboot 5.3.14 aka 5.4RC5 (development)
+
++ Small ARMNOMMU architecture fixes by Toby Lorenz.
+
++ Patch to Tulip driver for additional PCI ID by Ramesh Chander.
+
++ Proxy DHCP support, catrom.pl script, flat real mode support, and
+e1000 fixes by Michael Brown.
+
++ New PHY support for tg3.c by Timothy Legge.
+
++ FS Protocol support by Radim Kolar.
+
++ FILO config changes by YHLu.
+
++ Support for compilation on AMD64 for i386. makerom.pl fixed not to
+change product string pointer if one already exists.
+
+Released as Etherboot 5.3.15 aka 5.4RC6 (development)
+
++ Minor additions and amendments to acknowledgements.
+
++ Added Doug Ambrisko's FreeBSD patch to freebsd_loader.c. Doesn't
+hurt FreeBSD 4 and seems to help FreeBSD 5 get further in booting.
+Should not affect other image types since it modifies only one file.
+The part of the patch relating to osloader.c was already present.
+
+Released as Etherboot 5.4.0 (production)
+
++ Added PCI ID for Fujistu Siemens Futro C200 by Martin Vogt
+
++ Liu Tao contributed a driver for the AMD8111 based on the Linux 
+driver
+
++ Till Straumann patch for Sporadic eepro(10)  RX problems after reboot
+
++ Hermann Gausterer sent a patch to support additional Broadcom PHYs
+
diff --git a/RELNOTES b/RELNOTES
new file mode 100644 (file)
index 0000000..ffd0145
--- /dev/null
+++ b/RELNOTES
@@ -0,0 +1,43 @@
+Etherboot 5.4.0
+
+PXE is now supported.  You will also need to configure your server to
+provide a pxelinux.0 loader file, kernel and initrd images, and a
+pxelinux.cfg directory with a appropriate configuration spec files.
+
+See the PXELINUX home page at:
+
+    http://syslinux.zytor.com/pxe.php
+
+for more information. 
+
+There is no longer a default target for make.  You must specify an
+argument to make. Help text is now provided to indicate possible make
+targets.
+
+It should be possible to compile Etherboot with gcc >= 3.3.3, including
+gcc 3.4.x now that a couple of bugs have been tracked down. Please mail
+reports of success or failure to the etherboot-users list, together with
+the versions of gcc and binutils used.
+
+gcc 2.x is not supported anymore. You need at least gcc 3.x to compile
+etherboot due to C99 constructs.
+
+Removed etherboot(-pci)?.* rule because there are too many drivers and
+the image will no longer fit in memory. I don't want to choose a subset
+of drivers as everybody will have different preferences. So I'm going to
+piss off everybody equally by deleting the rule. Use the multiple driver
+rule (driver1--driver2--...) and select your own subset of drivers.
+
+In order to create .iso and .liso images you will need to have the
+packages mtools-3.9.9 or later, and syslinux-2.08 or later installed on
+your system.  These packages are available in various locations and
+formats.  .liso images are like .iso but use floppy emulation.  If you
+have a very old BIOS and .liso images don't work you may wish to try
+adding the -s option of syslinux as a last resort.
+
+EMERGENCYDISKBOOT has been renamed EXIT_IF_NO_OFFER, which describes it
+better.
+
+Menuing using DHCP options (mknbi/menu.c) has been removed.
+
+.exe format can be generated by doesn't work so not publicised.
diff --git a/VERSION b/VERSION
new file mode 100644 (file)
index 0000000..85570a8
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+5.4.0 2005-04-01
diff --git a/contrib/3c90xutil/Makefile b/contrib/3c90xutil/Makefile
new file mode 100644 (file)
index 0000000..1dd1723
--- /dev/null
@@ -0,0 +1,9 @@
+FILES = cromutil bromutil
+
+INCLUDEDIR = /usr/include
+CFLAGS = -O2 -fomit-frame-pointer -Wall -I$(INCLUDEDIR)
+
+all: $(FILES)
+
+clean:
+       rm -f $(FILES) *~ core
diff --git a/contrib/3c90xutil/README b/contrib/3c90xutil/README
new file mode 100644 (file)
index 0000000..235530f
--- /dev/null
@@ -0,0 +1,31 @@
+This utility was apparently writen by John Finlay and came to me
+via Richard Schroeder who got it from Greg Beeley. John, if you want
+to be credited with your full address or whatever in the Etherboot
+documentation, please contact me (Etherboot maintainer).
+
+1/18/2000 Marty Connor (mdc@thinguin.org) added code for the 3C905C
+with AT49BV512 Flash memory, and created cromutil and bromutil to
+differentiate the versions.  cromutil is for 3C905C and bromutil is
+for 3C905B.
+
+Be careful. You can easily erase your Flash memory using these
+utilities.  Make *sure* to back them up first using the "read"
+command. You must "erase" before using "prog" to program the chip with
+Etherboot code.  This code comes with NO WARRANTY, and you take sole
+responsibility and liability for whatever it does.  Read the
+"romutil.txt" file for more information on commands.
+
+That being said, if you are programming a 3C905C-TXM (for example)
+you would do something like this:
+
+    $ cd etherboot-x.x.x/contrib
+    $ tar -zxvf n3c905xutil.tar.gz
+    $ cd n3c905xutil
+    $ make
+    # replace 0x6600 with whatever the IO Addr for your card is!!!!
+    $ ./cromutil 0x6600 read > 905cbackup.bin
+    $ ./cromutil 0x6600 erase
+    $ ./cromutil 0x6600 prog < 3c90x.lzrom
+
+You should now have an Etherboot-enabled 3c905C-TXM.
+
diff --git a/contrib/3c90xutil/bromutil.c b/contrib/3c90xutil/bromutil.c
new file mode 100644 (file)
index 0000000..a736e5a
--- /dev/null
@@ -0,0 +1,169 @@
+/* 
+ * readutil.c - perform various control ops on the 3c509b bios rom
+ *
+ */
+
+#ifndef __i386__
+#  error "This program can't compile or run on non-intel computers"
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __FreeBSD__
+
+#include <fcntl.h>
+#include <machine/cpufunc.h>
+
+#define OUTB(data, port)       outb(port, data)
+#define OUTW(data, port)       outw(port, data)
+#define OUTL(data, port)       outl(port, data)
+
+#else
+
+#include <sys/io.h>
+
+#define OUTB(data, port)       outb(data, port)
+#define OUTW(data, port)       outw(data, port)
+#define OUTL(data, port)       outl(data, port)
+
+#endif
+
+int main(int argc, char **argv)
+{
+    unsigned int i, j, n;
+    unsigned int ioaddr;
+    unsigned long recvrstat;
+    unsigned char buf[128];
+    unsigned char b;
+
+    if (argc != 3) {
+      printf("Usage: romid ioaddr [erase|protect|unprotect|id|read >file|prog <file]\n");
+      exit(-1);
+    }
+
+#ifdef __FreeBSD__
+    /* get permissions for in/out{blw} */
+    open("/dev/io",O_RDONLY,0);
+#else
+    setuid(0); /* if we're setuid, do it really */
+    if (iopl(3)) {
+      perror("iopl()");
+      exit(1);
+    }
+#endif
+
+    sscanf(argv[1],"%x",&ioaddr);
+    /* Set the register window to 3 for the 3c905b */
+    OUTW(0x803, ioaddr+0xe);
+    recvrstat = inl(ioaddr);   /* save the receiver status */
+    /* set the receiver type to MII so the full bios rom address space
+       can be accessed */
+    OUTL((recvrstat & 0xf00fffff)|0x00600000, ioaddr);
+
+    /* Set the register window to 0 for the 3c905b */
+    OUTW(0x800, ioaddr+0xe);
+
+    if (strcmp(argv[2], "erase") == 0) {
+      /* do the funky chicken to erase the rom contents */
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0x80, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0x10, ioaddr+0x8);
+      printf("Bios ROM at %04x has been erased\n", ioaddr);
+    } else if (strcmp(argv[2], "protect") == 0) {
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xa0, ioaddr+0x8);
+      printf("Software Data Protection for Bios ROM at %04x has been enabled\n",
+            ioaddr);
+    } else if (strcmp(argv[2], "unprotect") == 0) {
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0x80, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0x20, ioaddr+0x8);
+      printf("Software Data Protection for Bios ROM at %04x has been disabled\n",
+            ioaddr);
+    } else if (strcmp(argv[2], "id") == 0) {
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0x90, ioaddr+0x8);
+      /* 10ms delay needed */
+      printf("Manufacturer ID - ");
+      /* manuf. id */
+      OUTL(0x0000, ioaddr+0x4);
+      printf("%02x\n", inb(ioaddr+0x8));
+      /* device id */
+      OUTL(0x0001, ioaddr+0x4);
+      printf("Device ID - %02x\n", inb(ioaddr+0x8));
+      /* undo the funky chicken */
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xaa, ioaddr+0x8);
+      OUTL(0x2aaa, ioaddr+0x4);
+      OUTB(0x55, ioaddr+0x8);
+      OUTL(0x5555, ioaddr+0x4);
+      OUTB(0xf0, ioaddr+0x8);
+    } else if (strcmp(argv[2], "read") == 0) {
+      for (i = 0; i < 65536; i++) {
+       OUTL(i, ioaddr+0x4);
+       b = inb(ioaddr+0x8);
+       write(1, &b, 1);
+      }
+    } else if (strcmp(argv[2], "prog") == 0) {
+      /* program the rom in 128 bute chunks */
+      for (i = 0, n = 0; i < 65536; i += n) {
+       n = read(0, buf, 128);
+       if (n == 0)
+         break;
+       if (n < 0) {
+         perror("File Error");
+         exit(-3);
+       }
+       /* disable SDP temporarily for programming a sector */
+       OUTL(0x5555, ioaddr+0x4);
+       OUTB(0xaa, ioaddr+0x8);
+       OUTL(0x2aaa, ioaddr+0x4);
+       OUTB(0x55, ioaddr+0x8);
+       OUTL(0x5555, ioaddr+0x4);
+       OUTB(0xa0, ioaddr+0x8);
+       for (j = 0; j < n; j++) {
+         OUTL(i+j, ioaddr+0x4);
+         OUTB(buf[j], ioaddr+0x8);
+       }
+       /* wait for the programming of this sector to coomplete */
+       while (inb(ioaddr+0x8) != buf[j-1])
+         ;
+      }
+    }
+
+    /* Set the register window to 3 for the 3c905b */
+    OUTW(0x803, ioaddr+0xe);
+    /* restore the receiver status */
+    OUTL(recvrstat, ioaddr);
+    return 0;
+}
+
+#endif /* __i386__ */
diff --git a/contrib/3c90xutil/cromutil.c b/contrib/3c90xutil/cromutil.c
new file mode 100644 (file)
index 0000000..d4751fb
--- /dev/null
@@ -0,0 +1,103 @@
+/* 
+ * 3c905cutil.c - perform various control ops on the 3C905C bios rom
+ *             which we assume to be an AT49BV512
+ *
+ */
+
+#ifndef __i386__
+#  error "This program can't compile or run on non-intel computers"
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/io.h>
+
+int main(int argc, char **argv)
+{
+  unsigned int ioaddr, i, n;
+  unsigned char b;
+
+  setuid(0); /* if we're setuid, do it really */
+  if (argc != 3) {
+    printf("Usage: romid ioaddr [erase|id|read >file|prog <file]\n");
+    exit(-1);
+  }
+  if (iopl(3)) {
+    perror("iopl()");
+    exit(1);
+  }
+  sscanf(argv[1],"%x",&ioaddr);
+
+  /* Set the register window to 0 for the 3C905C */
+  outw(0x800, ioaddr+0xe);
+
+  if (strcmp(argv[2], "erase") == 0) {
+    /* do the funky chicken to erase the rom contents */
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0x80, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0x10, ioaddr+0x8);
+    sleep (1);
+    printf("Bios ROM at %04x has been erased\n", ioaddr);
+  } else if (strcmp(argv[2], "id") == 0) {
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0x90, ioaddr+0x8);
+    /* 10ms delay needed */
+    printf("Manufacturer ID - ");
+    /* manuf. id */
+    outl(0x0000, ioaddr+0x4);
+    printf("%02x\n", inb(ioaddr+0x8));
+    /* device id */
+    outl(0x0001, ioaddr+0x4);
+    printf("Device ID - %02x\n", inb(ioaddr+0x8));
+    /* undo the funky chicken */
+    outl(0x5555, ioaddr+0x4);
+    outb(0xaa, ioaddr+0x8);
+    outl(0x2aaa, ioaddr+0x4);
+    outb(0x55, ioaddr+0x8);
+    outl(0x5555, ioaddr+0x4);
+    outb(0xf0, ioaddr+0x8);
+  } else if (strcmp(argv[2], "read") == 0) {
+    for (i = 0; i < 65536; i++) {
+      outl(i, ioaddr+0x4);
+      b = inb(ioaddr+0x8);
+      write(1, &b, 1);
+    }
+  } else if (strcmp(argv[2], "prog") == 0) {
+    for (i = 0; i < 65536; i++) {
+      n = read(0, &b, 1);
+      if (n == 0)
+       break;
+      if (n < 0) {
+       perror("File Error");
+       exit(-3);
+      }
+      outl(0x5555, ioaddr+0x4);
+      outb(0xaa, ioaddr+0x8);
+      outl(0x2aaa, ioaddr+0x4);
+      outb(0x55, ioaddr+0x8);
+      outl(0x5555, ioaddr+0x4);
+      outb(0xA0, ioaddr+0x8);
+      outl(i, ioaddr+0x4);
+      outb(b, ioaddr+0x8);
+      while (inb(ioaddr+0x8) != b)
+       ;
+    }
+  }
+  return 0;
+}
+
+#endif /* __i386__ */
diff --git a/contrib/3c90xutil/romutil.txt b/contrib/3c90xutil/romutil.txt
new file mode 100644 (file)
index 0000000..58074b9
--- /dev/null
@@ -0,0 +1,36 @@
+I wrote the attached little util program to try out the basic approach
+and thought that you might find it useful as well as providing some
+simple testing. It isn't a final solution so the interface is rough. The
+program must be run as root on an Intel based machine.
+
+The key point is that the IO address needs to be entered - I grab it
+from the dmesg output:
+
+eth0: 3Com 3c905B Cyclone 100baseTx at 0xe400,  00:10:4b:d2:5e:0d, IRQ
+11
+
+or "cat /proc/pci" to find the "I/O at XXXXXX" for your 3Com Card.
+
+Some example commands are:
+
+romutil 0xe400 erase            - erases the ROM contents
+romutil 0xe400 protect            - enables the Software Data Protection
+on the ROM [3c905B only]
+romutil 0xe400 unprotect       - disables the Software Data Protection
+on the ROM [3c905B only]
+romutil 0xe400 id                    - displays the manufacturer and
+device IDs
+romutil 0xe400 read >file    - writes the contents of the ROM to stdout
+romutil 0xe400 prog <file    - writes the contents of the stdin into the
+ROM (<64k)
+
+I tried reading and writing the ROM while doing large ftp transfers and
+experienced no problems. I didn't spend much time worrying about the
+possible race conditions. My system has lots of resources (450MHx P2,
+128MB RAM) so it might not provide the best test candidate.
+
+Let me know what results you get if you try it out.
+
+Thanks
+
+John
diff --git a/contrib/Diskless-From-NT/Config.txt b/contrib/Diskless-From-NT/Config.txt
new file mode 100644 (file)
index 0000000..60385fb
--- /dev/null
@@ -0,0 +1,537 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_X86=y
+CONFIG_ISA=y
+# CONFIG_SBUS is not set
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Processor type and features
+#
+CONFIG_M386=y
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_M686FXSR is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_X86_CMPXCHG is not set
+CONFIG_X86_L1_CACHE_SHIFT=4
+# CONFIG_TOSHIBA is not set
+# CONFIG_MICROCODE is not set
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_CPUID is not set
+CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_MTRR=y
+# CONFIG_SMP is not set
+# CONFIG_X86_UP_IOAPIC is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+# CONFIG_VISWS is not set
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_EISA=y
+# CONFIG_MCA is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PM=y
+# CONFIG_ACPI is not set
+# CONFIG_APM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=y
+# CONFIG_SK_G16 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+
+#
+# Game port support
+#
+
+#
+# Gameport joysticks
+#
+
+#
+# Serial port support
+#
+
+#
+# Serial port joysticks
+#
+
+#
+# Parallel port joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=m
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_I810=y
+CONFIG_AGP_VIA=y
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VIDEO_SELECT is not set
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+CONFIG_SOUND_ES1371=m
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_VIA82CXXX=m
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_PSS is not set
+CONFIG_SOUND_SB=m
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+CONFIG_SOUND_YM3812=m
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMPCI is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
diff --git a/contrib/Diskless-From-NT/Diskless-From-NT.txt b/contrib/Diskless-From-NT/Diskless-From-NT.txt
new file mode 100644 (file)
index 0000000..54c2b74
--- /dev/null
@@ -0,0 +1,565 @@
+
+
+The Diskless Terminal running from NT server Mini-HOWTO
+Pavel Tkatchouk, ptkatcho@portal.ca
+v0.1, June 19th 1999
+
+Table of Contents
+
+1. Introduction.
+
+   1.1 What is it for?
+   1.2 Do we need this HOWTO?
+   1.3 A bit of History.
+
+2. Project description.
+
+   2.1 Packaging.
+   2.2 Image.
+      2.2.1 Kernel.
+      2.2.2 MRFS.
+      2.2.3 Building MRFS.
+   2.3 Remotefs.
+   2.4 Booting sequence.
+      2.4.1 BOOTP, TFTP.
+   2.5 Bootprom.
+
+3. Resources.
+
+4. Copyright.
+
+5. Feedback and credits.
+
+
+1. Introduction.
+
+
+1.1. What is it for?
+
+This document describes how to build software distribution to run Java client on diskless 
+terminal booted from Microsoft Windows 95/98/NT workstation. Package can also be easily 
+modified to be used as Linux terminal or X Windows terminal's software. I found it also 
+convenient for setup over the Ethernet of floppyless PS's, hard disk of which for some 
+reason can not be accessed (sealed case under warranty, etc.).
+
+
+1.2. Do we need this HOWTO?
+
+To be honest, I'm not sure. There are few excellent HOWTO's (see 3. Recources) that up until 
+recently I considered quite sufficient to build what I've done two years ago. But since my 
+project uses MS Windows as a file server vs. traditional NFS there were some know-how's 
+involved which number of people wanted to see in some formal document.
+
+
+1.3. A bit of history.
+
+My project at that time (1996) was to find OS/JVM that will allow to run Java application 
+on hardware we manufacture. Hardware is practically generic x86 PC except it has no keyboard, 
+hard drive, floppy drive, mouse, but touchscreen over LCD, plus some POS specific peripherals 
+(badge reader, credit card reader, etc.). Due to cost consideration it had no any significant 
+storage, so OS and Java client along with support binaries, libraries etc. had to be loaded 
+remotely. Because our clients are exclusively Windows shops, Server had to be Windows as well. 
+During evaluation of different commercial OS'es along with JVM's available it become apparent 
+to my surprise that most promising solution was GPL one - Linux.
+
+
+2. Project description.
+
+2.1. Packaging.
+
+The whole distribution consists of remote file system (RemoteFS) residing on MS Windows
+server (NT Workstation, NT Server or Windows9x) and tagged bootable image. 
+
+
+2.2. Image.
+
+Image (~1.5MB) is generated by mknbi utility that comes with Etherboot package
+<http://etherboot.sourceforge.net>. It can include minimal root file system (MRFS) 
+like in my case (since I had to boot client from MS Windows server and Linux kernel doesn't 
+support SMBFS-Root, only NFS-Root. So I had to keep rootfs in the ramdisk). To generate 
+image the following script can be used.
+
+#!/bin/sh
+# mkrootnet: makes tagged netbootable image
+# This image includes kernel and minimal root filesystem
+# to do initial boot.
+#
+# Copyright (c) Pavel Tkatchouk 1996. All rights reserved.
+# Permission is granted for this material to be freely
+# used and distributed, provided the source is acknowledged.
+# No warranty of any kind is provided. You use this material
+# at your own risk.
+#
+DEVICEFILENAME="/tmp/file"             # temporary file to be used as device
+FSBLOCKS=4096                                  # uncompressed filesystem size in K
+BOOTDISKDIR="/usr/BOOT/ROOTFS" # root filesystem model
+MOUNT="/mnt2"                          # temporary mount point
+ROOTFS="/tmp/rootfs"                   # root filesystem image
+ROOTFSGZ="/tmp/rootfs.gz"              # compressed root filesystem image
+KERNEL="/usr/KERNELS/vmlinuz-nt"       # kernel image
+KERNELTMP="/tmp/vmlinuz"               # temporary copy of kernel image
+BOOTIMAGE="/tmp/img"                   # tagged image to be booted by client
+# if you want ramisk more than default 4096 set CMDLINE, don't forget to
+# adjust $FSBLOCKS 
+# CMDLINE="ramdisk_size=8192"          # parameters to pass to the kernel
+# 
+echo "check:"
+echo "- if tftp server's download dir mounted to /mnt"
+echo "- loopback device is built-in or loaded"
+echo "\n press Enter when done"
+read tmp 
+UPLOAD="/mnt/tmp"                              # tftp server's dir to upload bootimage
+echo -e "\nZeroing $DEVICEFILENAME of $FSBLOCKS k"
+echo "to be used as device for root filesystem model"
+dd if=/dev/zero of=$DEVICEFILENAME bs=1k count=$FSBLOCKS
+echo -e "\nMaking file system on $DEVICEFILENAME"
+mke2fs -m 0 $DEVICEFILENAME
+echo "Mounting $DEVICEFILENAME as a loopback device"
+mount -o loop -t ext2 $DEVICEFILENAME $MOUNT
+curdir=`pwd`
+cd $BOOTDISKDIR
+echo -e "Copying files from $BOOTDISKDIR to $DEVICEFILENAME, please wait"
+find . -print|cpio -pmd $MOUNT
+echo "Unmounting $MOUNT"
+umount $MOUNT
+cd $curdir
+echo "Copying $DEVICEFILENAME to $ROOTFS"
+dd if=$DEVICEFILENAME of=$ROOTFS bs=1k
+echo "Compressing $ROOTFS, it may take a while"
+echo "Please wait..."
+if [ -f $ROOTFSGZ ];then
+       rm -f $ROOTFSGZ
+fi
+gzip -c $ROOTFS>$ROOTFSGZ
+rm -f $ROOTFS
+echo -e "\nCreating netbootable image"
+cp $KERNEL $KERNELTMP
+mknbi -d ram -i rom -r $ROOTFSGZ -k $KERNELTMP -a $CMDLINE -o $BOOTIMAGE
+echo "Uploading $BOOTIMAGE to $UPLOAD"
+cp $BOOTIMAGE $UPLOAD
+echo "Cleaning after ourselves"
+rm -f $KERNELTMP $DEVICEFILENAME $BOOTIMAGE
+echo "All done"
+
+
+In the above script actual image is generated by the following comand
+
+#mknbi -d ram -i rom -r rootfs.gz -k vmlinuz-nt -o img
+
+where:
+       rootfs.gz - minimal root file system (MRFS);
+       vmlinuz-nt   - kernel;
+       img       - resulting image.
+
+
+Note:
+Default ramdisk size is 4096. It was enough for RedHat4.1 based minimal file system, but 
+apparently not enough for 5.2 based. When this happens "end request:I/O error, dev 01:00 ..." 
+error shows up. To fix that either use "mknbi -a ramdisk_size=8192" to pass parameter to the 
+kernel (doesn't require kernel recompilation), or change /usr/src/linux/drivers/block/rd.c: 
+int rd_size= from 4096 to 8192 or whatever and rebuild the kernel.                                                    
+
+
+2.2.1. Kernel.
+
+Kernels 2.0.30 and 2.0.36 have been used by author, although nothing is preventing you from
+experimenting with others. Kernel should include ramdisk support. The following 
+<link to .config> configuration has been used to build <link to binary (kernel 2.0.30)>. 
+You may find some components unnecessary, just exclude them and rebuild. 
+
+Don't forget to change root device after you built the kernel (rdev vmlinuz /dev/rd).
+
+Gotcha's: apparently smbfs is broken in 2.2.x kernels. Symptoms: remote share is mounted
+just fine but after a while fails with "smb_request: result = -32" errmsg. I've heard
+SuSe has fix for that.
+
+2.2.2. MRFS.
+
+Minimal root file system is required to get Linux up and running along with networking until 
+it can mount remote file system to run X/Java from there. After image gets loaded from the 
+server MRFS is decompressed into ramdisk. If you can afford a lot of ram on your terminal the 
+entire remote file system can be moved to rootfs.gz. That will make your terminal more 
+responsive.
+
+
+2.2.3. Building MRFS.  
+
+Some folks found it easier to start from scratch, others use known "minimal" Linux distributions
+(Linux Router, tomsrtbt, etc.), yet others prefer to start from "big" Linuces like I did. Every
+path has it's pro and contras.
+
+Pruning standard distribution (RedHat, Debian, etc.) to your needs might be very time consuming.
+To ease that painful process I have used remotely booted diskless client with NFS-Root (see 
+Etherboot's Readme, NFS-Root and NFS-Root-Client mini-HOWTO's, Diskless-HOWTO):
+
+- setup minimal RedHat4.1 install (networked workstation, X, no development, mail, etc., ~117MB);
+- find . -print|cpio -pmd /usr/NFS/ROOTFS - copy entire fs tree to NFS exported dir;
+- mknod /usr/NFS/ROOTFS/dev/nfsroot b 0 255;
+- build vmlinuz-nfs kernel according to NFS-Howto (built-in bootp,rarp,NFS,NFS root,NIC 
+  driver,RAM disk);
+- rdev vmlinuz-nfs /dev/nfsroot - to set NFS root device; 
+- build image for NFS-Root fs:
+  #mknbi -d rom -i rom -k vmlinuz-nfs -o nfsImage;
+- boot client while monitoring NFS file requests (by Solaris snoop);
+- copy files from /usr/NFS/ROOTFS to /usr/BOOT/ROOTFS (MRFS model) according to snoop's
+  filelist;
+- generate image by mkrootnet script (don't forget to point to the right kernel vmlinuz-nt).
+
+The above trick not only allows to determine the sought files set but also debug boot process 
+analyzing NFS messages. I found it convenient to put "read tmp" statements into init scripts
+for debugging. Tracking files up until issuing login gives you <link to rootfs.gz> MRFS (~1MB) 
+that can be used to boot Linux from ROM (flash, eprom, DiskOnChip, SanDisk, etc.) as well. All 
+the other files requested by client (during starting X, Java, Java client) were put into (link 
+to remotefs.zip, ~9MB).
+
+
+To restore MRFS model on your PC from the above rootfs.gz:
+- #cd /tmp
+- #gunzip rootfs.gz
+- #mount -o loop -t ext2 /tmp/rootfs /mnt
+- #cd /mnt
+- #find . -print|cpio -pmd /usr/BOOT/ROOTFS
+- #umount /mnt
+
+Note: 
+
+You will have to change attributes of some dirs, files (/etc/mtab, /etc/mtab~, /var/lock/subsys/*, 
+/var/run/*, /dev/tty*, etc.) against standard. This is because with standard attribs diskless 
+client refused to work. For example I had to change /dev/tty* ownerships to 99:99 from original 
+0:0 or 0:5, to get rid of errmsg "INIT: Id "1" respawning too fast: disabled for 5 minutes". 
+Being admin illiterate I just chmod them to 777 and chown to 99:99 to make life easier. 
+THIS IS SERIOUS SECURITY VIOLATION!!! Using keyboardless terminal with no daemons running in 
+my case reduces the risk, yet I would appreciate very much those more experienced who will help 
+to restore the right attribs while keeping the distribution working.
+
+Some "gotcha's" to watch for during MRFS building:
+- standard attributes/ownership of some files don't work;
+- rdev must be set (non-tagged image didn't work, so couldn't use config file to pass parrs 
+  to the kernel);
+- diskless client writes 99:99 ownership on generated files;
+- "password incorrect" for root, but any other OK and su OK too.
+
+
+2.3. RemoteFS.
+
+Remotefs.zip file includes everything required by the system that can be located on
+remote file system, i.e after booting has been complete and remote file system mounted.
+In my case it is X Windows System and Java binaries, libraries etc. To use that file on
+MS Windows NT:
+- unzip remotefs.zip to some directory;
+- share this directory read-only as "usr" (or share as some other name and pass this name to
+  the client through bootptab configuration file for BOOTP server;
+- create an account username=root, password=linux on NT (can be set in bootptab).
+
+Note:
+There's no symbolic links on NTFS, so UNIX links must be replaced by copies on NTFS. 
+To determine potential troublmakers one could use the following:
+- first copy required subset (according to snoop's intercept) from /usr/NFS/ROOTFS to 
+  /usr/BOOT/REMOTEFS;
+- mount some share from NTFS to /mnt;
+- /usr/BOOT/REMOTEFS#find . -print|cpio -pmd /mnt 2>links;
+In the links file you will find names to work with.
+
+
+2.4. Booting sequence.
+
+Boot occurs in the following sequence:
+- bootprom sends bootp request,
+- bootp server responds with subnet mask, client's name, client's IP, TFTP server's IP, 
+  bootfile name and some optional parameters (like NT's username/password to use it's share,
+  you could pass some other share name here as say T104="somedir");
+- bootprom downloads image from TFTP server;
+- kernel starts;
+- kernel decompresses MRFS in RAM;
+- system starts init using ramdisk root,
+- mounts remote file system from NT via SMBFS;
+- automatically logins;
+- starts xstart script located on remotefs (/usr/sbin) where you can start any of your
+  programs, change parameters, etc. without rebuilding the image.
+
+Below are some config/init sample files from <rootfs.gz>, <remotefs.zip>:
+
+<bootptab, change to link>
+t1:sm=255.255.255.0:sa=192.168.33.150:bf=img:T100="pavelnt4":T101="root":T102="linux"
+touch1:hn=touch1:tc=t1:ha=00A0F00035CD:ip=192.168.33.127
+
+</etc/fstab, change to link>:
+/dev/ram  /      ext2    defaults    1 1
+/proc     /proc  proc    defaults    0 0
+
+</etc/rc.d/rc.bootp, change to link later>:
+#!/bin/sh
+# Written to simply set the IP stuff up from the
+# bootpc data.
+# Last updated : Mon Mar 10 15:17:01 1997
+#
+# Variables
+
+BOOTPC=/sbin/bootpc
+IFCONFIG=/sbin/ifconfig
+ROUTE=/sbin/route
+BINHOST=/bin/hostname
+DEV=eth0
+ASKSERVER="255.255.255.255"
+TW="--timeoutwait 320"
+RIF="--returniffail"
+RIFMESSAGE="Bootp failed -- disabling network."
+RCONF=/etc/resolv.conf
+EHOSTS=/etc/hosts
+LHOSTS=/etc/hosts.local
+TMPFILE=/tmp/bootp
+# Functions
+# Remove the networking by taking down the interface
+netdown() {
+  ${ROUTE} del default
+  ${IFCONFIG} ${DEV} down
+}
+## End of the functions
+
+## Start of the actual work
+# Bring up minimal networking use 0.0.0.0 as our address as we don't
+# know it yet (Means "Me but I don't know my address or network")
+${IFCONFIG} ${DEV} up 0.0.0.0
+${ROUTE} add default dev ${DEV}
+
+# Perform the bootp  --  doesn't return unless it gets an answer
+if ${BOOTPC} --dev ${DEV} --server ${ASKSERVER} ${RIF} ${TW} > ${TMPFILE}
+then
+# Take down networking (use the 0.0.0.0 for as short a time as possible)
+  netdown
+# Read in the values   
+  . ${TMPFILE}
+
+# To use in mountsmb script later
+SMBSERVER=${T100}
+# And delete the temporary file
+#  rm ${TMPFILE}
+else
+# Take down networking (use the 0.0.0.0 for as short a time as possible)
+  netdown
+# give message and quit
+  echo ${RIFMESSAGE}
+  exit 1
+fi
+
+# Start the loopback interface and add a route to it
+# It's already set by standard init?
+${IFCONFIG} lo 127.0.0.1
+${ROUTE} add -net 127.0.0.0
+
+# Setup of IP stuff needs doing first
+#
+if [ -z "${NETMASK}" ] ; then
+# No netmask info, all this is guessed from the IP number
+# If this is wrong for your network FIX the bootpd to know
+# what it should send in the RFC1497 cookie!  11/02/94 JSP
+#
+  ${IFCONFIG} ${DEV} up ${IPADDR} broadcast ${BROADCAST} 
+  ${ROUTE} -n add -net ${NETWORK} dev ${DEV}
+else
+# We will have NETMASK, BROADCAST, and NETWORK defined 
+  ${IFCONFIG} ${DEV} up ${IPADDR} broadcast ${BROADCAST} netmask ${NETMASK} 
+  ${ROUTE} -n add -net ${NETWORK} dev ${DEV}
+fi
+
+# Set the hostname from what we got via bootp or reverse lookup
+
+echo "127.0.0.1        loopback localhost">${EHOSTS}
+${BINHOST} "${HOSTNAME}"
+echo "${IPADDR}        ${HOSTNAME}" >>${EHOSTS}
+echo "${SERVER} ${SMBSERVER}" >>${EHOSTS}
+
+
+</etc/rc.d/rc.local, change to link>:
+#!/bin/sh
+# This script will be executed *after* all the other init scripts.
+# You can put your own initialization stuff in here if you don't
+# want to do the full Sys V style init stuff.
+#
+# 07/02/97 Pavel Tkatchouk
+#
+echo "Start networking"
+insmod /lib/8390.o
+insmod /lib/ne.o io=0x300 irq=9
+echo "Install serial"
+insmod /lib/serial.o
+echo "Install touch"
+insmod /lib/touch.o
+echo "Install smbfs"
+insmod /lib/smbfs.o
+echo "Getting TCP/IP parameters from bootp server"
+echo "and start networking"
+/etc/rc.d/rc.bootp
+if [ -f /etc/squirrel-release ]; then
+       R=$(cat /etc/squirrel-release)
+else
+       R="release 0.02"
+fi
+echo "Mounting remote fs"
+/sbin/mountsmb
+echo "XYZ Inc. Diskless Linux $R"
+echo "Starting X and Java client without login"
+su -c /sbin/xstart root
+
+
+</usr/sbin/xstart, change to link>:
+#!/bin/bash
+#
+# Script to start X and Java client
+# 08/07/97 Pavel Tkatchouk
+#
+# Read bootps response first
+. /tmp/bootp
+# -s 0 to disable screen-saver
+/usr/X11R6/bin/X -s 0 &
+export DISPLAY=:0.0
+# /usr is share mounted from Windows workstation
+cd /usr/program/
+java SomeJavaApp 
+
+
+</sbin/mountsmb, change to link>:
+#!/bin/bash
+# mountsmb: mounts remote filesystems from NT workstation 
+# using Microsoft's SMB protocol 
+# 
+# Copyright (c) Pavel Tkatchouk 1997. All rights reserved.
+# Permission is granted for this material to be freely
+# used and distributed, provided the source is acknowledged.
+# No warranty of any kind is provided. You use this material
+# at your own risk.
+#
+# Last edit June 29 8:30 1997
+#
+MOUNTDIR="usr"
+SHRDIR="usr"
+BOOTPRES="/tmp/bootp"
+# Read botpc response
+. ${BOOTPRES}
+# Sharename from NT server, uncomment if you want to use 
+# non-hardcoded "usr" but from bootptab
+#SHRDIR=${T104} 
+SMBSRV="//${T100}"
+CLIENT="${HOSTNAME}"
+USER="${T101}"
+PASSWORD="${T102}"
+echo -e "\nMounting $SMBSRV/$SHRDIR to /$MOUNTDIR"
+smbmount $SMBSRV/$SHRDIR $MOUNTDIR -c $CLIENT -U $USER -P $PASSWORD
+echo -e "\nDone"
+
+Gotcha's:
+Looks like smbmount client from smbfs package used to mount remote Windows shares to local 
+Linux dirs in pre 2.2.x era isn't maintained anymore so you should use one coming with 
+Samba package. Also binary smbmount won't work with 2.2.x, so you have to recompile with 
+2.2.x headers following Samba's readme. Yet even that won't guarantee reliable work until
+somebody fixes kernel's smbfs module.
+
+2.4.1. BOOTP, TFTP.
+
+There are number of BOOTP, TFTP servers for Windows on the market. You could find them
+here:
+
+- www.walusoft.co.uk (Walusoft's tftp);
+- ftp.coast.net/simtel/nt/internet/tftpds12.zip (Millwood AB's tftp);
+- ftp.cabletron.com/pub/snmp/bootftp/boottft2.zip (Cabletron's bootp/tftp combo);
+- www.tellurian.au.com (Tellurian's bootp, tftp, dhcp servers).
+- www.metainfo.com (Metainfo's DHCP server)
+- www.nts.com (Network Telesystems's DHCP server in IPserver package)
+
+My choice was Tellurian's products - very reliable, simple to install, attractively priced
+(fully capable evaluation versions are available).
+
+2.5. Bootprom.
+
+Ken Yap's Etherboot <etherboot.sourceforge.net> will tell you everything about bootprom. 
+Here I just want to mention that normally you would have to put bootprom's code into network
+adapter's PROM. But if your hardware like mine has BIOS programmed in flash you could 
+re-program it to add bootprom (some BIOS requires special programmer to do that, others don't)
+as BIOS extension.
+
+This is what I did to add ne.rom (bootprom generated by Etherboot's makerom for NE2000 clone) 
+to AMI BIOS on my flash:
+
+- read flash content by programmer into bios.bin binary file;
+- use one of available binary editors (say www.simtel.net/Win95/editors/hxp3005.zip to add
+  ne.rom to bios.bin (and to edit ne.rom if necessary);
+- write new bios.bin back to flash.
+
+Notes:
+- makerom generates bootprom for standard EPROM sizes (8k, 16k, 32k, etc.), so if you tight on 
+  space use -s flag to adjust size (or cut it manually to multiple of 512 bytes blocks, just
+  don't forget to adjust extension's length which is coded in Byte 2 and checksum to 8 bits 
+  of zero;
+- valid absolute addresses for BIOS extensions are from 0xC8000 to 0xF4000 (check with 
+  motherboard's manufacturer how flash is mapped onto system memory space);
+- Byte 0 must be 0x55, Byte 1 must be 0xAA, Byte 2 must be extension's length in 512 bytes 
+  blocks;
+- extension BIOS has to start at a 2k boundary;
+
+
+3. Resources.
+
+FAQ's:
+- tomsrtbt.FAQ (www.toms.net);
+
+HOWTO's:
+- Paul Moody's miniHOWTO (www.linuxembedded.com/pmhowto.html)
+- Diskless;
+- Diskless-HOWTO;
+- NFS-Root;
+- NFS-Root-Client;
+- Bootdisk-HOWTO;
+- BootPrompt-HOWTO;
+- NCD-X-Terminal;
+- Remote-Boot;
+- Remote-X-Apps;
+
+Web:
+- etherboot.sourceforge.net/
+- www.waste.org/~zanshin
+- www.tellurian.com.au.
+- www.toms.net
+- www.trinux.org
+- www.linux.org.uk/ELKS-Home
+- www.embedded.com
+- www.linuxembedded.com
+- www.thinlinux.org
+- www.linuxrouter.org
+- linux-mandrake.com
+- www.disklessworkstations.com
+
+Newsgroups:
+- comp.arch.embedded
+
+Lists:
+- netboot-owner@baghira.han.de
+- linux-embedded@waste.org
+
+Magazines:
+- Circuit Cellar #100 - 105
+
+
+4. Copyright.
+
+Copyright (c) Pavel Tkatchouk 1999.
+Permission is granted for this material to be freely used and distributed, provided the source 
+is acknowledged. Copyright policy is GPL as published by the Free Software Foundation.
+
+No warranty of any kind is provided. You use this material at your own risk.
+
+
+5. Feedback and credits.
+
+Since I am neither have a lot of Linux experience nor native English speaker, there would be 
+errors in this document. I would accept any help with gratitude whether in form of proof-reading, 
+techical corrections or otherwise. Please send your comments, suggestions and questions to Pavel 
+Tkatchouk (ptkatcho@portal.ca)
+
+I wish to thank Pierre Mondie who convinced me to start this document. I'm also very much in 
+debt to all those who's work made this project possible:
+
+Ken Yap                <ken_yap@users.sourceforge.net> (Etherboot)
+David Newall   <www.tellurian.com.au>  (Bootpdnt/Ftpdnt)
+(to be continued)
+
diff --git a/contrib/Diskless-From-NT/furtmayr.html b/contrib/Diskless-From-NT/furtmayr.html
new file mode 100644 (file)
index 0000000..224632d
--- /dev/null
@@ -0,0 +1,82 @@
+<html>
+
+<head>
+<title>Free TFTP / Syslog / NFS Servers for Windows</title>
+</head>
+
+<body>
+
+<h3 align="center">Free TFTP / Syslog / NFS Servers for Windows</h3>
+<div align="center"><center>
+
+<address>
+  Stefan Furtmayr (<a href="mailto:sf@paf.net">sf@paf.net</a>) 
+</address>
+</center></div>
+
+<p>Feel free to send me your comments about these programs or some additions.</p>
+
+<p>Also have a look at the <a
+href="http://www.ltsp.org/contrib/diskless-windows-howto.htm">&quot;Diskless Windows
+Cookbook &quot;</a> in the <a href="http://www.ltsp.org/contrib/">LTSP Contrib Area</a>.</p>
+
+<p><small>From this list I have only used the W2K-TFTP once for a customer with the <a
+href="http://support.3com.com/infodeli/tools/nic/mba.htm">3Com MBA Utility Disk</a>, while
+it can be used as well with <a href="http://etherboot.sourceforge.net">Etherboot</a>
+tagged images for other NIC brands.</small><br>
+<small>The solution used a netbooted DOS with MS Client 3.0 to easily restore disk images
+with <a href="http://www.ghost.com/">Symantec Ghost</a> (see <a
+href="http://appdeploy.com/tools/imaging.shtml">appdeploy.com</a> for similar tools).</small><br>
+<small>Sure there are several possibilities to do this with Linux but for cloning NT4/W2K
+the NTFS support is rather experimental and automatically changing the SID is another
+issue.</small></p>
+
+<h4>TFTP Servers:</h4>
+
+<p>In Autumn 2000 i tested some different TFTP servers and found out that most of them do
+not install/run as a service, especially under W2K. 
+
+<ul>
+  <li>TFTP server included with Windows 2000 (remote installation services need to be
+    installed)<br>
+    The path for the images has to be specified via registry:<br>
+    Q232115 - Changing the Drive or Volume on Which Remote Installation Images Reside:<br>
+    <a href="http://support.microsoft.com/support/kb/articles/Q232/1/15.ASP">http://support.microsoft.com/support/kb/articles/Q232/1/15.ASP</a></li>
+  <li>3CDaemon version 2.0 revision 10. Freeware. Integrated TFTP/FTP/Syslog Daemon for
+    Windows 95/98/NT<br>
+    <a href="ftp://ftp.3com.com/pub/utilbin/win32/3cdv2r10.zip">ftp://ftp.3com.com/pub/utilbin/win32/3cdv2r10.zip</a><br>
+    - Windows 2000 Server: does not run as service!<br>
+    - Windows NT Server 4.0: not tested</li>
+  <li>The TFTP Server portion of 3CServer, altered to run as a system Service under Windows NT<br>
+    <a href="ftp://ftp.3com.com/pub/utilbin/win32/3CTftpSvc.zip">ftp://ftp.3com.com/pub/utilbin/win32/3CTftpSvc.zip</a><br>
+    - Windows 2000 Server: only working in debug mode, does not run as service!<br>
+    - Windows NT Server 4.0: not tested</li>
+  <li>Cisco TFTP Server v.1.1<br>
+    <a href="http://www.cisco.com/pcgi-bin/tablebuild.pl/tftp">http://www.cisco.com/pcgi-bin/tablebuild.pl/tftp</a><br>
+    Does not provide an option itself to install as service.</li>
+  <li><a href="http://solarwinds.net/Tools/Free_Tools/TFTP_Server/">http://solarwinds.net/Tools/Free_Tools/TFTP_Server/</a><br>
+    Does not provide an option itself to install as service.</li>
+</ul>
+
+<p><em>Untested:</em></p>
+
+<p>found on <a href="http://www.nonags.com/nonags/servd32.html">http://www.nonags.com/nonags/servd32.html</a><br>
+- <a href="http://www.klever.net/kin/pumpkin.html">http://www.klever.net/kin/pumpkin.html</a><br>
+- <a href="http://membres.tripod.fr/phjounin//P_tftpd32.htm">http://membres.tripod.fr/phjounin//P_tftpd32.htm</a></p>
+
+<h4>Syslog Servers:</h4>
+
+<ul>
+  <li>3Com Software Library - Utilities for 32 bit Windows<br>
+    <a href="http://support.3com.com/software/utilities_for_windows_32_bit.htm">http://support.3com.com/software/utilities_for_windows_32_bit.htm</a></li>
+  <li><a href="http://www.netal.com/download.htm#SL4NT03">http://www.netal.com/download.htm#SL4NT03</a>
+    (works as service) </li>
+</ul>
+
+<h4>NFS Servers:</h4>
+
+<ul>
+  <li>War NFS Daemon: <a href="http://www.jgaa.com">http://www.jgaa.com</a> (untested)</li>
+</ul>
+</body>
+</html>
diff --git a/contrib/auto-default/mail b/contrib/auto-default/mail
new file mode 100644 (file)
index 0000000..015c789
--- /dev/null
@@ -0,0 +1,40 @@
+Date:        11/9/2001 3:56 PM
+Received:    11/9/2001 4:05 PM
+From:        Steve Tilden, stilden@sicom-sys.com
+
+...
+
+2)  I have added conditional code to main.c from Etherboot 5.0.4 to add
+a new default boot option and I have included the modified main.c as an
+attachment to this message.
+
+As I received Etherboot 5.0.4, in the Config file, if you select
+ASK_BOOT with a non zero time-out option, then you also get to set
+ANS_DEFAULT = ANS_NETWORK or ANS_DEFAULT = ANS_LOCAL to determine what
+will happen if the operator does not respond to the prompt.   I have now
+added conditional code in main.c such that if you set ANS_DEFAULT =
+ANS_AUTO, the default answer will be set according to whether or not
+there is a hard disk in the system (as detected by the BIOS).  If a hard
+disk is present, then if the operator does nothing, the system will boot
+from it.  If a hard disk does not exist, then again if the operator does
+nothing, the system will boot via the network.  Either way, for our
+particular environment, the operator has to do nothing to get it to boot
+correctly.  Yet the operator can still override the default selection
+to, for example, allow a unit without a hard disk, to boot directly from
+a floppy rather than the network, or to allow a unit with a hard disk,
+to boot from the network.
+
+I don't know it the code I have added might be correct for a future
+production version of Etherboot, but I thought I'd send it to you and
+let you get it into the system if you feel it might be appropriate.
+
+Thanks,
+
+Steve Tilden
+Sicom Systems Inc.
+stilden@sicom-sys.com
+
+[Ed: On a compliant BIOS, it will actually boot the next device in the
+BIOS list if local is selected, either explicitly or by timeout, which
+may or may not be the hard disk, which is why it's less than general and
+not included in the distribution by default.]
diff --git a/contrib/auto-default/main.c.patch b/contrib/auto-default/main.c.patch
new file mode 100644 (file)
index 0000000..e707b63
--- /dev/null
@@ -0,0 +1,55 @@
+--- main.c     Mon Nov  5 18:58:30 2001
++++ main.c.new Thu Nov 15 01:45:12 2001
+@@ -149,21 +151,49 @@
+ static unsigned short ipchksum(unsigned short *ip, int len);
+ static unsigned short udpchksum(struct iphdr *packet);
++
++#if defined(ASK_BOOT) && ASK_BOOT > 0 && (ANS_DEFAULT == ANS_AUTO)
++/*
++ * Read Installed Hard Disk Count from BIOS memory at 0:0475
++ */
++static int hdsk_cnt(void)
++{
++      int retv;
++      __asm__ __volatile__(
++       "xorw %%ax,%%ax\n\t"
++       "movb 0x475,%%al\n"
++       : "=a" (retv)
++       : /* no inputs */
++       : "ax", "cc", "memory"
++      );
++      return(retv);
++}
++#endif /* ASK_BOOT && ANS_AUTO */
++
++
+ static inline void ask_boot(void)
+ {
+ #if defined(ASK_BOOT) && ASK_BOOT > 0
+       while(1) {
+-              int c;
++              int c, deflt;
+               unsigned long time;
++#if defined(ASK_BOOT) && ASK_BOOT > 0 && (ANS_DEFAULT == ANS_AUTO)
++              if (hdsk_cnt() != 0)
++                      deflt = ANS_LOCAL;
++              else
++                      deflt = ANS_NETWORK;
++#else
++              deflt = ANS_DEFAULT;
++#endif
+               printf(ASK_PROMPT);
+               for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); )
+                       if (currticks() > time) {
+-                              c = ANS_DEFAULT;
++                              c = deflt;
+                               goto done;
+                       }
+               c = getchar();
+               if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
+-              if (c == '\n') c = ANS_DEFAULT;
++              if (c == '\n') c = deflt;
+ done:
+               if ((c >= ' ') && (c <= '~')) putchar(c);
+               putchar('\n');
diff --git a/contrib/award_plugin_roms/README b/contrib/award_plugin_roms/README
new file mode 100644 (file)
index 0000000..5f657cf
--- /dev/null
@@ -0,0 +1,2 @@
+An Award BIOS ROM lister in Perl contributed by Eric W. Biederman
+<ebiederman@lnxi.com>.
diff --git a/contrib/award_plugin_roms/award_plugin_roms.pl b/contrib/award_plugin_roms/award_plugin_roms.pl
new file mode 100755 (executable)
index 0000000..2b95eed
--- /dev/null
@@ -0,0 +1,341 @@
+#!/usr/bin/perl -w
+use strict;
+use FileHandle;
+use integer;
+
+sub unsigned_little_endian_to_value
+{
+       # Assumes the data is initially little endian
+       my ($buffer) = @_;
+       my $bytes = length($buffer);
+       my $value = 0;
+       my $i;
+       for($i = $bytes -1; $i >= 0; $i--) {
+               my $byte = unpack('C', substr($buffer, $i, 1));
+               $value = ($value * 256) + $byte;
+       }
+       return $value;
+}
+
+sub decode_fixed_string
+{
+       my ($data, $bytes) = @_;
+       return $data;
+}
+
+sub decode_pstring
+{
+       my ($buf_ref, $offset_ref) = @_;
+       # Decode a pascal string
+       my $offset = ${$offset_ref};
+       my $len = unpack('C',substr(${$buf_ref}, $offset, 1));
+       my $data = substr(${$buf_ref}, $offset +1,  $len);
+       ${$offset_ref} = $offset + $len +1;
+       return $data;
+}
+
+sub decode_cstring
+{
+       # Decode a c string
+       my ($buf_ref, $offset_ref) = @_;
+       my ($data, $byte);
+       my $index = ${$offset_ref};
+       while(1) {
+               $byte = substr(${$buf_ref}, $index, 1);
+               if (!defined($byte) || ($byte eq "\0")) {
+                       last;
+               }
+               $data .= $byte;
+               $index++;
+       }
+       ${$offset_ref} = $index;
+       return $data;
+}
+
+sub type_size
+{
+       my ($entry) = @_;
+       my %type_length = (
+               byte => 1,
+               half => 2,
+               word => 4,
+               xword => 8,
+               'fixed-string' => $entry->[2],
+               pstring => 0,
+               cstring => 0,
+       );
+       my $type = $entry->[0];
+       if (!exists($type_length{$type})) {
+                die "unknown type $type";
+        }
+       my $length = $type_length{$type};
+       return $length;
+}
+
+sub decode_fixed_type
+{
+       my ($type, $data, $bytes) = @_;
+       my %decoders = (
+               'byte' => \&unsigned_little_endian_to_value,
+               'half' => \&unsigned_little_endian_to_value,
+               'word' => \&unsigned_little_endian_to_value,
+               'xword' => \&unsigned_little_endian_to_value,
+               'fixed-string' => \&decode_fixed_string,
+       );
+       my $decoder = $decoders{$type} or die "unknow fixed type $type";
+       return $decoder->($data, $bytes);
+}
+
+sub decode_variable_type
+{
+       my ($type, $buf_ref, $offset_ref) = @_;
+       my %decoders = (
+               'pstring' => \&decode_pstring,
+               'cstring' => \&decode_cstring,
+       );
+       my $decoder = $decoders{$type} or die "unknow variable type $type";
+       return $decoder->($buf_ref, $offset_ref);
+}
+
+sub decode_struct
+{
+       my ($buf_ref, $offset, $layout) = @_;
+       my $initial_offset = $offset;
+       my ($entry, %results);
+       foreach $entry (@$layout) {
+               my ($type, $name) = @$entry;
+               my $bytes = type_size($entry);
+               if ($bytes > 0) {
+                       my $data = substr(${$buf_ref}, $offset, $bytes);
+                       $results{$name} = decode_fixed_type($type, $data, $bytes);
+                       $offset += $bytes;
+               } else {
+                       $results{$name} = decode_variable_type($type, $buf_ref, \$offset);
+               }
+       }
+       return (\%results, $offset - $initial_offset);
+}
+
+sub print_big_hex
+{
+       my ($min_digits, $value) = @_;
+       my @digits;
+       while($min_digits > 0 || ($value > 0)) {
+               my $digit = $value%16;
+               $value /= 16;
+               unshift(@digits, $digit);
+               $min_digits--;
+       }
+       my $digit;
+       foreach $digit (@digits) {
+               printf("%01x", $digit);
+       }
+}
+
+
+
+my %lha_signatures = (
+       '-com-' => 1,   
+       '-lhd-' => 1,
+       '-lh0-' => 1,
+       '-lh1-' => 1,
+       '-lh2-' => 1,
+       '-lh3-' => 1,
+       '-lh4-' => 1,
+       '-lh5-' => 1,
+       '-lzs-' => 1,
+       '-lz4-' => 1,
+       '-lz5-' => 1,
+       '-afx-' => 1,
+       '-lzf-' => 1,
+);
+
+my %lha_os = (
+       'M' => 'MS-DOS',
+       '2' => 'OS/2',
+       '9' => 'OS9',
+       'K' => 'OS/68K',
+       '3' => 'OS/386',
+       'H' => 'HUMAN',
+       'U' => 'UNIX',
+       'C' => 'CP/M',
+       'F' => 'FLEX',
+       'm' => 'Mac',
+       'R' => 'Runser',
+       'T' => 'TownOS',
+       'X' => 'XOSK',
+       'A' => 'Amiga',
+       'a' => 'atari',
+       ' ' => 'Award ROM',
+);
+
+
+my @lha_level_1_header = (
+       [ 'byte',         'header_size' ],    # 1
+       [ 'byte',         'header_sum', ],    # 2
+       [ 'fixed-string', 'method_id', 5 ],   # 7
+       [ 'word',         'skip_size', ],     # 11
+       [ 'word',         'original_size' ],  # 15
+       [ 'half',         'dos_time' ],       # 17
+       [ 'half',         'dos_date' ],       # 19
+       [ 'byte',         'fixed'   ],        # 20
+       [ 'byte',         'level'   ],        # 21
+       [ 'pstring',      'filename' ],       # 22
+       [ 'half',         'crc' ],
+       [ 'fixed-string', 'os_id', 1 ],
+       [ 'half',         'ext_size' ],           
+);
+
+# General lha_header
+my @lha_header = (
+       [ 'byte',         'header_size' ],
+       [ 'byte',         'header_sum', ],
+       [ 'fixed-string', 'method_id', 5 ],
+       [ 'word',         'skip_size', ],
+       [ 'word',         'original_size' ],
+       [ 'half',         'dos_time' ],
+       [ 'half',         'dos_date' ],
+       [ 'half',         'rom_addr' ],
+       [ 'half',         'rom_flags' ],
+       [ 'byte',         'fixed'   ],
+       [ 'byte',         'level'   ],
+       [ 'pstring',      'filename' ],
+       [ 'half',         'crc' ],
+       [ 'lha_os',       'os_id', 1 ],
+       [ 'half',         'ext_size' ],
+       [ 'byte',         'zero' ],
+       [ 'byte',         'total_checksum' ],
+       [ 'half',         'total_size' ],
+);
+
+sub print_struct
+{
+       my ($layout, $self) = @_;
+       my $entry;
+       my $width = 0;
+       foreach $entry(@$layout) {
+               my ($type, $name) = @$entry;
+               if (length($name) > $width) {
+                       $width = length($name);
+               }
+       }
+       foreach $entry (@$layout) {
+               my ($type, $name) = @$entry;
+               printf("%*s = ", $width, $name);
+               my $value = $self->{$name};
+               if (!defined($value)) {
+                       print "undefined";
+               }
+               elsif ($type eq "lha_os") {
+                       print "$lha_os{$value}";
+               }
+               elsif ($type =~ m/string/) {
+                       print "$value";
+               } 
+               else {
+                       my $len = type_size($entry);
+                       print "0x";
+                       print_big_hex($len *2, $value);
+               }
+               print "\n";
+       }
+}
+
+sub checksum
+{
+       my ($buf_ref, $offset, $length) = @_;
+       my ($i, $sum);
+       $sum = 0;
+       for($i = 0; $i < $length; $i++) {
+               my $byte = unpack('C', substr($$buf_ref, $offset + $i, 1));
+               $sum = ($sum + $byte) %256;
+       }
+       return $sum;
+}
+
+sub decode_lha_header
+{
+       my ($buf_ref, $offset) = @_;
+       my $level = unpack('C',substr(${$buf_ref}, $offset + 20, 1));
+
+       my %self;
+       my ($struct, $bytes);
+       if ($level == 1) {
+               ($struct, $bytes) 
+                       = decode_struct($buf_ref, $offset, \@lha_level_1_header);
+               %self = %$struct;
+               if ($self{fixed} != 0x20) {
+                        die "bad fixed value";
+               }
+               $self{total_size} = $self{header_size} + 2 + $self{skip_size};
+               if ($bytes != $self{header_size} +2) {
+                       die "$bytes != $self{header_size} +2";
+               }
+               my $checksum = checksum($buf_ref, $offset +2, $self{header_size});
+               if ($checksum != $self{header_sum}) {
+                       printf("WARN: Header bytes checksum to %02lx\n", 
+                                    $checksum);
+               }
+               # If we are an award rom...
+               if ($self{os_id} eq ' ') {
+                       @self{qw(zero total_checksum)} = 
+                           unpack('CC', substr($$buf_ref, 
+                               $offset + $self{total_size}, 2));
+                       if ($self{zero} != 0) {
+                               warn "Award ROM without trailing zero";
+                       }
+                       else {
+                               $self{total_size}++;
+                       }
+                       my $checksum = 
+                               checksum($buf_ref, $offset, $self{total_size});
+                       if ($self{total_checksum} != $checksum) {
+                               printf("WARN: Image bytes checksum to %02lx\n", 
+                                       $checksum);
+                       }
+                       else {
+                               $self{total_size}++;
+                       }
+                       $self{rom_addr} = $self{dos_time};
+                       $self{rom_flags} = $self{dos_date};
+                       delete @self{qw(dos_time dos_date)};
+               }
+       }
+       else {
+               die "Unknown header type";
+       }
+       return \%self;
+}
+
+sub main
+{
+       my ($filename, $rom_length) = @_;
+       my $fd = new FileHandle;
+       if (!defined($rom_length)) {
+               my ($dev, $ino, $mode, $nlink, $uid, $gid,$rdev,$size,
+                       $atime, $mtime, $ctime, $blksize, $blocks)
+                       = stat($filename);
+               $rom_length = $size;
+       }
+       $fd->open("<$filename") or die "Cannot ope $filename";
+       my $data;
+       $fd->read($data, $rom_length);
+       $fd->close();
+       
+       my $i;
+       for($i = 0; $i < $rom_length; $i++) {
+               my $sig = substr($data, $i, 5);
+               if (exists($lha_signatures{$sig})) {
+                       my $start = $i -2;
+                       my $header = decode_lha_header(\$data, $start);
+                       
+                       my $length = $header->{total_size};
+                       print "AT:  $start - @{[$start + $length -1]},  $length bytes\n";
+                       print_struct(\@lha_header, $header);
+                       print "\n";
+
+               }
+       }
+}
+
+main(@ARGV);
diff --git a/contrib/baremetal/Makefile b/contrib/baremetal/Makefile
new file mode 100644 (file)
index 0000000..df4de76
--- /dev/null
@@ -0,0 +1,475 @@
+#
+# Makefile for Etherboot
+#
+# Most of the time you should edit Config
+#
+# Common options:
+#      VERSION=v       - Set the version string
+#
+# NS8390 options:
+#      -DINCLUDE_NE    - Include NE1000/NE2000 support
+#      -DNE_SCAN=list  - Probe for NE base address using list of
+#                        comma separated hex addresses
+#      -DINCLUDE_3C503 - Include 3c503 support
+#        -DT503_SHMEM  - Use 3c503 shared memory mode (off by default)
+#      -DINCLUDE_WD    - Include Western Digital/SMC support
+#      -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards
+#      -DCOMPEX_RL2000_FIX
+#
+#      If you have a Compex RL2000 PCI 32-bit (11F6:1401),
+#      and the bootrom hangs in "Probing...[NE*000/PCI]",
+#      try enabling this fix... it worked for me :).
+#      In the first packet write somehow it somehow doesn't
+#      get back the expected data so it is stuck in a loop.
+#      I didn't bother to investigate what or why because it works
+#      when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES.
+#      The code will notify if it does a abort.
+#      SomniOne - somnione@gmx.net
+#
+# 3C509 option:
+#      -DINCLUDE_3C509 - Include 3c509 support
+#
+# 3C90X options:
+#      -DINCLUDE_3C90X - Include 3c90x support
+#      -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it
+#                        had initially just before the loaded code is started.
+#      -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses.
+#      -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM
+#                        interface, setting this option might "fix" it.  Use
+#                        with caution and read the docs in 3c90x.txt!
+#
+#      See the documentation file 3c90x.txt for more details.
+#
+# CS89X0 (optional) options:
+#      -DINCLUDE_CS89X0- Include CS89x0 support
+#      -DCS_SCAN=list  - Probe for CS89x0 base address using list of
+#                        comma separated hex addresses; increasing the
+#                        address by one (0x300 -> 0x301) will force a
+#                        more aggressive probing algorithm. This might
+#                        be neccessary after a soft-reset of the NIC.
+#
+# LANCE options:
+#      -DINCLUDE_NE2100- Include NE2100 support
+#      -DINCLUDE_NI6510- Include NI6510 support
+#
+# SK_G16 options:
+#      -DINCLUDE_SK_G16- Include SK_G16 support
+#
+# I82586 options:
+#      -DINCLUDE_3C507 - Include 3c507 support
+#      -DINCLUDE_NI5210- Include NI5210 support
+#      -DINCLUDE_EXOS205-Include EXOS205 support
+#
+# SMC9000 options:
+#       -DINCLUDE_SMC9000   - Include SMC9000 driver
+#       -DSMC9000_SCAN=list - List of I/O addresses to probe
+#
+# TIARA (Fujitsu Etherstar) options:
+#      -DINCLUDE_TIARA - Include Tiara support
+#
+# NI5010 options:
+#      -DINCLUDE_NI5010 - Include NI5010 support
+#
+# TULIP options:
+#      -DINCLUDE_TULIP - Include Tulip support
+#      -DUSE_INTERNAL_BUFFER - receuve and transmit buffers within program
+#              space, not below 0x10000, in case that region is used
+#
+# RTL8139 options:
+#      -DINCLUDE_RTL8139 - Include RTL8139 support
+#      -DUSE_INTERNAL_BUFFER - 8 kB receive buffer within program space,
+#              not at 0x10000 - 8kB, in case that region is used
+#
+
+include Config
+
+GCC=           gcc
+CPP=           gcc -E
+VERSION=       4.6.12
+CFLAGS16+=     -DVERSION=\"$(VERSION)\" -DRELOC=$(RELOCADDR)
+CFLAGS32+=     -DVERSION=\"$(VERSION)\" -DRELOC=$(RELOCADDR) $(OLDGAS)
+LCONFIG+=      -DRELOC=$(RELOCADDR)
+
+IDENT16=               'Etherboot/16 $(VERSION) (GPL) $(@F)'
+IDENT32=               'Etherboot/32 $(VERSION) (GPL) $(@F)'
+
+# Find out if we're using binutils 2.9.1 which uses a different syntax in some
+# places (most prominently in the opcode prefix area).
+OLDGAS:=       $(shell $(AS) --version | grep -q '2\.9\.1' && echo -DGAS291)
+
+# Check the requested type of build (32, 16 or both families)
+ifeq ($(ETHERBOOT),16)
+BUILD_LIBS=    $(BLIB16)
+BUILD_BINS=    $(BINS16)
+endif
+ifeq ($(ETHERBOOT),32)
+BUILD_LIBS=    $(BLIB32)
+BUILD_BINS=    $(BINS32)
+endif
+ifeq ($(ETHERBOOT),both)
+BUILD_LIBS=    $(BLIB16) $(BLIB32)
+BUILD_BINS=    $(BINS16) $(BINS32)
+endif
+
+3C503FLAGS=    -DINCLUDE_3C503 # -DT503_SHMEM
+# Note that the suffix to MAKEROM_ is the (mixed case) basename of the ROM file
+MAKEROM_3c503= -3
+3C507FLAGS=    -DINCLUDE_3C507
+3C509FLAGS=    -DINCLUDE_3C509
+3C529FLAGS=    -DINCLUDE_3C529
+3C595FLAGS=    -DINCLUDE_3C595
+3C90XFLAGS=    -DINCLUDE_3C90X
+CS89X0FLAGS=   -DINCLUDE_CS89X0
+EEPROFLAGS=    -DINCLUDE_EEPRO
+EEPRO100FLAGS= -DINCLUDE_EEPRO100
+EPIC100FLAGS=  -DINCLUDE_EPIC100
+EXOS205FLAGS=  -DINCLUDE_EXOS205
+LANCEFLAGS=    -DINCLUDE_LANCE         # Lance/PCI!
+NE2100FLAGS=   -DINCLUDE_NE2100
+NEFLAGS=       -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380
+NS8390FLAGS=   -DINCLUDE_NS8390        # NE2000/PCI!
+NI5010FLAGS=   -DINCLUDE_NI5010
+NI5210FLAGS=   -DINCLUDE_NI5210
+NI6510FLAGS=   -DINCLUDE_NI6510
+RTL8139FLAGS=  -DINCLUDE_RTL8139
+SK_G16FLAGS=   -DINCLUDE_SK_G16
+SMC9000FLAGS=   -DINCLUDE_SMC9000
+TIARAFLAGS=    -DINCLUDE_TIARA
+DEPCAFLAGS=    -DINCLUDE_DEPCA # -DDEPCA_MODEL=DEPCA -DDEPCA_RAM_BASE=0xd0000
+TULIPFLAGS=    -DINCLUDE_TULIP
+OTULIPFLAGS=   -DINCLUDE_OTULIP
+VIA_RHINEFLAGS=        -DINCLUDE_VIA_RHINE
+WDFLAGS=       -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000
+W89C840FLAGS=  -DINCLUDE_W89C840
+
+# If you have not made any changes to the *.S files, AS86 need not be set.
+# (most people)
+# If you have made changes to the *.S files and you want to rebuild *loader.bin
+# and {floppy,com}load.bin and you have as86 from the ELKS Dev86 package (not
+# the one that normally comes with Linux) (not most people)
+#AS86=         as86
+# If you have made changes to the *.S files and you want to rebuild *loader.bin
+# and {floppy,com}load.bin and you have nasm (not most people)
+#AS86=         nasm
+
+# if your as has trouble with the data32 directive, uncomment this
+# but note that the premade start*.o will be larger than necessary because it
+# contains some routines which may not be used
+#AS_PSEUDOS=   n
+
+SRCS=  floppyload.S comload.S liloprefix.S loader.S start16.S start32.S serial.S startmpcc.S
+SRCS+= main.c pci.c osloader.c nfs.c misc.c ansiesc.c bootmenu.c config.c
+SRCS+= md5.c floppy.c
+
+# ROM loaders: LZ version (prefix Z), PCI header version (prefix P)
+ifndef AS86
+RLOADER=       rloader.bin.pre
+PRLOADER=      prloader.bin.pre
+RZLOADER=      rzloader.bin.pre
+PRZLOADER=     przloader.bin.pre
+FLOPPYLOAD=    floppyload.bin.pre
+COMLOAD=       comload.bin.pre
+LILOPREFIX=    liloprefix.bin.pre
+else
+RLOADER=       bin/rloader.bin
+PRLOADER=      bin/prloader.bin
+RZLOADER=      bin/rzloader.bin
+PRZLOADER=     bin/przloader.bin
+FLOPPYLOAD=    bin/floppyload.bin
+COMLOAD=       bin/comload.bin
+LILOPREFIX=    bin/liloprefix.bin
+endif
+
+ifeq ($(AS86),as86)
+LCPPFLAGS+=    -DUSE_AS86
+LASFLAGS+=     $(AS86FLAGS) -0
+LASBINARY:=    -b
+endif
+ifeq ($(AS86),nasm)
+LCPPFLAGS+=    -DUSE_NASM
+LASFLAGS+=     $(NASMFLAGS) -fbin
+LASBINARY:=    -o
+endif
+
+ifeq ($(AS_PSEUDOS),n)
+START16=       start16.o.pre
+START32=       start32.o.pre
+else
+START16=       bin16/start16.o
+START32=       bin32/startmpcc.o
+endif
+
+BOBJS16=       bin16/main.o bin16/osloader.o bin16/misc.o bin16/bootmenu.o
+BOBJS16+=      bin16/floppy.o bin16/timer.o
+BOBJS32=       bin32/main.o bin32/osloader.o bin32/nfs.o bin32/misc.o
+BOBJS32+=      bin32/ansiesc.o bin32/bootmenu.o bin32/md5.o bin32/floppy.o
+BOBJS32+=      bin32/serial.o bin32/timer.o
+BLIB16=        bin16/bootlib.a
+BLIB32=        bin32/bootlib.a
+LIBS16=        $(BLIB16) $(LIBC16)
+LIBS32=        $(BLIB32) $(LIBC32) /usr/lib/gcc-lib/i386-redhat-linux/2.96/libgcc.a
+UTIL_LZHUF:= $(shell if [ -d ../contrib/compressor ]; then echo bin/lzhuf; fi)
+UTILS+=        bin/makerom $(UTIL_LZHUF) bin/organon
+STDDEPS16=     $(START16) $(BLIB16) $(UTILS)
+STDDEPS32=     $(START32) $(BLIB32) $(UTILS)
+MAKEDEPS=      Makefile Config Roms
+
+CHECKSIZE=     { read d1; read d1 d2 d3 size d4; [ $$size -gt $(ROMLIMIT) ] &&\
+       { $(RM) $@; echo "ERROR: code size exceeds limit!"; exit 1; }; exit 0; }
+
+# Make sure that the relocation address is acceptable for all ROM sizes.
+# Setting it to 0x98000 leaves about 29kB of space for the Etherboot program.
+# The check is done based running 'size' on the binary, not ROM size, but
+# roughly this means a ROM of 16kB or a partially used ROM of 32kB,
+# remembering to compressed ROM images into account.
+# You may also set RELOCADDR to 0x88000 to avoid using 0x98000
+# because of other drivers (e.g. Disk On Chip). In that case, you may
+# only load 512kB of OS, or load in memory above 1MB.
+# Don't forget to choose an assembler because the loaders have to be rebuilt.
+ifndef RELOCADDR
+RELOCADDR=0x98000
+#RELOCADDR=0xe0000
+endif
+
+# Evaluate ROMLIMIT only once - it is constant during the make run.
+# Note that the 3K safety margin below is for the 1K extended BIOS data area
+# and for the Etherboot runtime stack.  Under normal situations, 2K of stack
+# are rarely needed.  If you experience strange behaviour in functions that use
+# many local variables or that call functions that do, check for stack overrun!
+# Make sure that the normal case needs no perl interpreter - if someone uses a
+# different RELOCADDR, then he has perl installed anyways (the shell cannot
+# deal with hex numbers, as test/eval don't support non-decimal integers).
+ifeq ($(RELOCADDR),0x98000)
+ROMLIMIT=29696
+else
+ROMLIMIT:=$(shell perl -e 'print 0x10000 - 3072 - ($(RELOCADDR) & 0xFFFF), "\n";')
+endif
+
+# Start of targets
+
+all:   $(UTILS) $(BUILD_LIBS) allbins
+
+include Roms
+
+# We need allbins because $(BINS16) and $(BINS32) are not defined until
+# the Makefile fragment "Roms" is read.
+
+allbins:       $(BUILD_BINS)
+
+# Common files
+
+$(BLIB16):     $(BOBJS16)
+       $(AR16) rv $@ $(BOBJS16)
+       $(RANLIB16) $@
+
+$(BLIB32):     $(BOBJS32)
+       $(AR32) rv $@ $(BOBJS32)
+       $(RANLIB32) $@
+
+bin16/main.o:          main.c etherboot.h osdep.h nic.h
+bin32/main.o:          main.c etherboot.h osdep.h nic.h
+
+bin16/osloader.o:      osloader.c etherboot.h osdep.h
+bin32/osloader.o:      osloader.c etherboot.h osdep.h
+
+# NFS currently makes no sense for Etherboot/16
+bin32/nfs.o:           nfs.c etherboot.h osdep.h nic.h
+
+bin16/misc.o:          misc.c etherboot.h osdep.h
+bin32/misc.o:          misc.c etherboot.h osdep.h
+
+# ANSIESC is not supported for Etherboot/16
+bin32/ansiesc.o:       ansiesc.c etherboot.h osdep.h
+
+bin16/bootmenu.o:      bootmenu.c etherboot.h osdep.h
+bin32/bootmenu.o:      bootmenu.c etherboot.h osdep.h
+
+# Password support is not available for Etherboot/16
+bin32/md5.o:           md5.c etherboot.h osdep.h
+
+bin16/floppy.o:                floppy.c etherboot.h osdep.h
+bin32/floppy.o:                floppy.c etherboot.h osdep.h
+
+bin16/timer.o:         timer.c timer.h etherboot.h osdep.h
+bin32/timer.o:         timer.c timer.h etherboot.h osdep.h
+
+bin32/inthw.o:         inthw.c
+
+# PCI support code (common to all PCI drivers)
+
+bin32/pci.o:   pci.c pci.h
+
+# Do not add driver specific dependencies here unless it's something the
+# genrules.pl script *can't* deal with, i.e. if it is not C code.
+
+# Prepended loaders
+
+#ifndef AS86
+#$(RLOADER) $(RZLOADER) $(PRLOADER) $(PRZLOADER):      $(MAKEDEPS)
+#      @if [ $(RELOCADDR) != 0x98000 ]; then echo Non-standard RELOCADDR, must assemble $@; exit 1; fi
+#      $(TOUCH) $@
+#else
+#bin/rloader.s:        loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -o $@ $<
+#
+#bin/rzloader.s:       loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -DZLOADER -o $@ $<
+#
+#bin/prloader.s:       loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -DPCI_PNP_HEADER -o $@ $<
+#
+#bin/przloader.s:      loader.S $(MAKEDEPS)
+#      $(CPP) $(LCPPFLAGS) $(LCONFIG) -DPCI_PNP_HEADER -DZLOADER -o $@ $<
+#endif
+
+# Floppy loader
+
+ifdef AS86
+bin/floppyload.s:      floppyload.S $(MAKEDEPS)
+       $(CPP) $(LCPPFLAGS) -o $@ $<
+endif
+
+# COM loader
+
+ifdef AS86
+bin/comload.s: comload.S $(MAKEDEPS)
+       $(CPP) $(LCPPFLAGS) -o $@ $<
+endif
+
+# LILO prefix:
+
+ifdef AS86
+bin/liloprefix.s:      liloprefix.S $(MAKEDEPS)
+       $(CPP) $(LCPPFLAGS) -o $@ $<
+endif
+
+# Utilities
+
+bin/makerom: makerom.c
+       $(GCC) -O2 -o $@ makerom.c
+
+bin/organon: organon.c
+       $(GCC) -o $@ organon.c
+
+bin/lzhuf:     ../contrib/compressor/lzhuf.c
+       $(GCC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -o $@ $<
+
+# Roms file
+
+Roms:  NIC genrules.pl
+       @chmod +x genrules.pl
+       ./genrules.pl NIC > $@
+
+# Pattern Rules
+
+# general rules for compiling/assembling source files
+bin16/%.o:     %.c $(MAKEDEPS)
+       $(CC16) $(CFLAGS16) -o $@ -c $<
+
+bin32/%.o:     %.c $(MAKEDEPS)
+       $(CC32) $(CFLAGS32) -o $@ -c $<
+
+bin16/%.o:     %.S $(MAKEDEPS)
+       $(CC16) $(CFLAGS16) $(ASFLAGS16) -c -o $@ $<
+
+bin32/%.o:     %.S $(MAKEDEPS)
+       $(CPP) $(CFLAGS32) $< | $(AS) $(ASFLAGS32) -o $@
+
+# general rule for .bin (plain binary loader code), may be overridden
+ifdef AS86
+bin/%.bin:     bin/%.s
+       $(AS86) $(LASFLAGS) $(LASBINARY) $@ $<
+endif
+
+# general rule for .huf (compressed binary code), may be overridden
+%.huf: %.img
+       bin/lzhuf e $< $@
+
+# general rules for normal/compressed ROM images, may be overridden
+bin16/%.rom:   bin16/%.img $(RLOADER)
+       cat $(RLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT16) $@
+
+bin32/%.rom:   bin32/%.img $(RLOADER)
+       cat $(RLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT32) $@
+
+bin16/%.lzrom: bin16/%.huf $(RZLOADER)
+       cat $(RZLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT16) $@
+
+bin32/%.lzrom: bin32/%.huf $(RZLOADER)
+       cat $(RZLOADER) $< > $@
+       bin/makerom $(MAKEROM_$*) -i$(IDENT32) $@
+
+# rules to write the .rom/.lzrom image onto a blank floppy
+# You must give the directory name, e.g. use bin32/rtl8139.lzfd0 as the target.
+%.fd0: %.rom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > /dev/fd0
+
+%.lzfd0:       %.lzrom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > /dev/fd0
+
+# rules to generate a .com executable
+# You must give the directory name, e.g. use bin32/rtl8139.com as the target.
+%.com: %.lzrom $(COMLOAD)
+       cat $(COMLOAD) $< > $@
+
+# rules to make a floppy image (padding to fill an even number of cylinders).
+# VMware reports floppy image read errors if it cannot read ahead 36 sectors,
+# probably because the floppyload.S code reads up to that number of sectors in
+# a single request.  Not that 18k matters much these days...
+# You must give the directory name, e.g. use bin32/rtl8139.fdimg as the target.
+%.fdimg:       %.rom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > $@.x
+       dd if=$@.x of=$@ bs=36k conv=sync 2> /dev/null
+       $(RM) $@.x
+
+%.lzfdimg:     %.lzrom $(FLOPPYLOAD)
+       cat $(FLOPPYLOAD) $< > $@.x
+       dd if=$@.x of=$@ bs=36k conv=sync 2> /dev/null
+       $(RM) $@.x
+
+# rules to make a LILO-bootable image
+%.lilo:                %.rom $(LILOPREFIX)
+       cat $(LILOPREFIX) $< /dev/zero | head -c 64k > $@
+
+%.lzlilo:      %.lzrom $(LILOPREFIX)
+       cat $(LILOPREFIX) $< /dev/zero | head -c 64k > $@
+
+# Housekeeping
+
+# To make sure that this actually builds a start32.o.pre with all options set,
+# you have to make sure that -DFLOPPY -DANSIESC -DCONSOLE_DUAL are in CFLAGS32.
+precompiled:   bin/rloader.bin bin/rzloader.bin bin/prloader.bin bin/przloader.bin bin/floppyload.bin bin/comload.bin bin16/start16.o bin32/start32.o bin/liloprefix.bin
+       cp -p bin/rloader.bin rloader.bin.pre
+       cp -p bin/rzloader.bin rzloader.bin.pre
+       cp -p bin/prloader.bin prloader.bin.pre
+       cp -p bin/przloader.bin przloader.bin.pre
+       cp -p bin/floppyload.bin floppyload.bin.pre
+       cp -p bin/comload.bin comload.bin.pre
+       cp -p bin16/start16.o start16.o.pre
+       cp -p bin32/start32.o start32.o.pre
+       cp -p bin/liloprefix.bin liloprefix.bin.pre
+
+clean:
+       $(RM) $(UTILS) bin/*.s bin/*.bin
+       $(RM) $(BLIB16) $(BLIB32)
+       $(RM) bin16/*.o bin32/*.o bin16/*.tmp bin32/*.tmp
+       $(RM) bin16/*.img bin32/*.img bin16/*.huf bin32/*.huf
+       $(RM) bin16/*.rom bin32/*.rom bin16/*.lzrom bin32/*.lzrom
+       $(RM) bin16/*.com bin32/*.com
+       $(RM) bin16/*.fdimg bin32/*.fdimg bin16/*.lzfdimg bin32/*.lzfdimg
+       $(RM) bin16/*.lilo bin32/*.lilo bin16/*.lzlilo bin32/*.lzlilo
+       $(RM) bin32/*.hex
+       $(RM) bin32/*.asm
+       $(RM) bin32/*.map
+
+tarball:
+       (echo -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION
+       (cd ..; tar cf /tmp/mpccboot-$(VERSION).tar --exclude CVS mpccboot)
+       bzip2 -9 < /tmp/mpccboot-$(VERSION).tar > /tmp/mpccboot-$(VERSION).tar.bz2
+       gzip -9 < /tmp/mpccboot-$(VERSION).tar > /tmp/mpccboot-$(VERSION).tar.gz
+
+version:
+       @echo $(VERSION)
diff --git a/contrib/baremetal/main.c b/contrib/baremetal/main.c
new file mode 100644 (file)
index 0000000..7b0de44
--- /dev/null
@@ -0,0 +1,1119 @@
+/**************************************************************************
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+  Date: Dec/93
+
+Literature dealing with the network protocols:
+       ARP - RFC826
+       RARP - RFC903
+       UDP - RFC768
+       BOOTP - RFC951, RFC2132 (vendor extensions)
+       DHCP - RFC2131, RFC2132 (options)
+       TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
+       RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
+       NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
+
+**************************************************************************/
+
+/* #define MDEBUG */
+
+#include "etherboot.h"
+#include "nic.h"
+
+int    jmp_bootmenu[10];
+
+struct arptable_t arptable[MAX_ARP];
+
+const char *kernel;
+char kernel_buf[128];
+struct rom_info rom;
+
+#ifdef IMAGE_MENU
+static char *imagelist[RFC1533_VENDOR_NUMOFIMG];
+static int useimagemenu;
+int    menutmo,menudefault;
+unsigned char *defparams = NULL;
+int defparams_max = 0;
+#endif
+#ifdef MOTD
+char   *motd[RFC1533_VENDOR_NUMOFMOTD];
+#endif
+#ifdef IMAGE_FREEBSD
+int freebsd_howto = 0;
+#endif
+int     vendorext_isvalid;
+char   config_buffer[TFTP_MAX_PACKET+1];       /* +1 for null byte */
+unsigned long  netmask;
+char *hostname = "";
+int hostnamelen = 0;
+#if    defined(ETHERBOOT16) || defined(INTERNAL_BOOTP_DATA)
+struct bootpd_t bootp_data;
+#endif
+unsigned long xid;
+unsigned char   *end_of_rfc1533 = NULL;
+#ifndef        NO_DHCP_SUPPORT
+int dhcp_reply;
+in_addr dhcp_server = { 0L };
+in_addr dhcp_addr = { 0L };
+#endif /* NO_DHCP_SUPPORT */
+
+unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* Ã¤Eth */
+#ifdef NO_DHCP_SUPPORT
+char    rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END };
+#else
+char    rfc1533_cookie[] = { RFC1533_COOKIE};
+char    rfc1533_end[]={RFC1533_END };
+static const char dhcpdiscover[]={
+               RFC2132_MSG_TYPE,1,DHCPDISCOVER,
+               RFC2132_MAX_SIZE,2,     /* request as much as we can */
+               sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256,
+               RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY,
+               RFC1533_HOSTNAME
+       };
+static const char dhcprequest []={
+               RFC2132_MSG_TYPE,1,DHCPREQUEST,
+               RFC2132_SRV_ID,4,0,0,0,0,
+               RFC2132_REQ_ADDR,4,0,0,0,0,
+               RFC2132_MAX_SIZE,2,     /* request as much as we can */
+               sizeof(struct bootpd_t) / 256, sizeof(struct bootpd_t) % 256,
+               /* request parameters */
+               RFC2132_PARAM_LIST,
+#ifdef IMAGE_FREEBSD
+               /* 4 standard + 6 vendortags + 8 motd + 16 menu items */
+               4 + 6 + 8 + 16,
+#else
+               /* 4 standard + 5 vendortags + 8 motd + 16 menu items */
+               4 + 5 + 8 + 16,
+#endif
+               /* Standard parameters */
+               RFC1533_NETMASK, RFC1533_GATEWAY,
+               RFC1533_HOSTNAME,
+               RFC1533_ROOTPATH,       /* only passed to the booted image */
+               /* Etherboot vendortags */
+               RFC1533_VENDOR_MAGIC,
+                RFC1533_VENDOR_ADDPARM,
+                RFC1533_VENDOR_ETHDEV,
+#ifdef IMAGE_FREEBSD
+               RFC1533_VENDOR_HOWTO,
+#endif
+               RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION,
+               /* 8 MOTD entries */
+               RFC1533_VENDOR_MOTD,
+               RFC1533_VENDOR_MOTD+1,
+               RFC1533_VENDOR_MOTD+2,
+               RFC1533_VENDOR_MOTD+3,
+               RFC1533_VENDOR_MOTD+4,
+               RFC1533_VENDOR_MOTD+5,
+               RFC1533_VENDOR_MOTD+6,
+               RFC1533_VENDOR_MOTD+7,
+               /* 16 image entries */
+               RFC1533_VENDOR_IMG,
+               RFC1533_VENDOR_IMG+1,
+               RFC1533_VENDOR_IMG+2,
+               RFC1533_VENDOR_IMG+3,
+               RFC1533_VENDOR_IMG+4,
+               RFC1533_VENDOR_IMG+5,
+               RFC1533_VENDOR_IMG+6,
+               RFC1533_VENDOR_IMG+7,
+               RFC1533_VENDOR_IMG+8,
+               RFC1533_VENDOR_IMG+9,
+               RFC1533_VENDOR_IMG+10,
+               RFC1533_VENDOR_IMG+11,
+               RFC1533_VENDOR_IMG+12,
+               RFC1533_VENDOR_IMG+13,
+               RFC1533_VENDOR_IMG+14,
+               RFC1533_VENDOR_IMG+15,
+       };
+
+#endif /* NO_DHCP_SUPPORT */
+static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/**************************************************************************
+MAIN - Kick off routine
+**************************************************************************/
+int main(void)
+{
+       char *p;
+       static int card_retries = 0;
+       int i;
+
+       for (p=_edata; p<_end; p++)
+               *p = 0; /* Zero BSS */
+
+#ifdef CONSOLE_SERIAL
+       (void)serial_init();
+#endif
+
+#ifdef DELIMITERLINES
+       for (i=0; i<80; i++) putchar('=');
+#endif
+
+#ifdef ETHERBOOT32
+       rom = *(struct rom_info *)ROM_INFO_LOCATION;
+       printf("ROM segment %#x length %#x reloc %#x\n", rom.rom_segment,
+               rom.rom_length << 1, ((unsigned long)_start) >> 4);
+#endif
+#ifdef ETHERBOOT16
+       fmemcpy(&rom, (Address)ROM_INFO_LOCATION, sizeof(rom));
+       printf("ROM segment %#x length %#x\n", rom.rom_segment,
+               rom.rom_length << 1);
+#endif
+#ifdef ASK_BOOT
+       while (1) {
+               int c;
+               unsigned long time;
+               printf(ASK_PROMPT);
+#if    ASK_BOOT > 0
+               for (time = currticks() + ASK_BOOT*TICKS_PER_SEC; !iskey(); )
+                       if (currticks() > time) {
+                               c = ANS_DEFAULT;
+                               goto done;
+                       }
+#endif
+               c = getchar();
+               if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
+               if (c == '\n') c = ANS_DEFAULT;
+done:
+               if ((c >= ' ') && (c <= '~')) putchar(c);
+               putchar('\n');
+               if (c == ANS_LOCAL)
+                       exit(0);
+               if (c == ANS_NETWORK)
+                       break;
+       }
+#endif
+#if    (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY)
+       disk_init();
+       printf("Trying floppy");
+       for (i = TRY_FLOPPY_FIRST; i-- > 0; ) {
+               putchar('.');
+               if (disk_read(0, 0, 0, 0, ((char *) FLOPPY_BOOT_LOCATION)) != 0x8000) {
+                       printf("using floppy\n");
+                       exit(0);
+               }
+       }
+       printf("no floppy\n");
+#endif /* TRY_FLOPPY_FIRST && FLOPPY */
+       print_config();
+       gateA20_set();
+#ifdef EMERGENCYDISKBOOT
+       if (!eth_probe()) {
+               printf("No adapter found\n");
+               exit(0);
+       }
+#else
+       while (!eth_probe()) {
+               printf("No adapter found");
+               if (!setjmp(jmp_bootmenu))
+                       rfc951_sleep(++card_retries);
+       }
+#endif
+       kernel = DEFAULT_BOOTFILE;
+       while (1) {
+               if ((i = setjmp(jmp_bootmenu)) != 0) {
+#if    defined(ANSIESC) && defined(CONSOLE_CRT)
+                       ansi_reset();
+#endif
+                       bootmenu(--i);
+               } else {
+                       load();
+               }
+#if    defined(ANSIESC) && defined(CONSOLE_CRT)
+               ansi_reset();
+#endif
+       }
+}
+
+/**************************************************************************
+LOADKERNEL - Try to load kernel image
+**************************************************************************/
+#ifndef        FLOPPY
+#define loadkernel(s) download((s),downloadkernel)
+#else
+static int loadkernel(const char *fname)
+{
+       if (!memcmp(fname,"/dev/",5) && fname[6] == 'd') {
+               int dev, part = 0;
+               if (fname[5] == 'f') {
+                       if ((dev = fname[7] - '0') < 0 || dev > 3)
+                               goto nodisk; }
+               else if (fname[5] == 'h' || fname[5] == 's') {
+                       if ((dev = 0x80 + fname[7] - 'a') < 0x80 || dev > 0x83)
+                               goto nodisk;
+                       if (fname[8]) {
+                               part = fname[8] - '0';
+                               if (fname[9])
+                                       part = 10*part + fname[9] - '0'; }
+                       /* bootdisk cannot cope with more than eight partitions */
+                       if (part < 0 || part > 8)
+                               goto nodisk; }
+               else
+                       goto nodisk;
+               return(bootdisk(dev,part)); }
+nodisk:
+       return download(fname, downloadkernel);
+}
+#endif
+
+/**************************************************************************
+LOAD - Try to get booted
+**************************************************************************/
+void load()
+{
+       static int bootp_completed = 0;
+
+       /* Find a server to get BOOTP reply from */
+       if (!bootp_completed ||
+           !arptable[ARP_CLIENT].ipaddr.s_addr || !arptable[ARP_SERVER].ipaddr.s_addr) {
+retry:
+               bootp_completed = 0;
+#ifdef RARP_NOT_BOOTP
+               printf("Searching for server (RARP)...\n");
+#else
+#ifndef        NO_DHCP_SUPPORT
+               printf("Searching for server (DHCP)...\n");
+#else
+               printf("Searching for server (BOOTP)...\n");
+#endif
+#endif
+
+#ifdef RARP_NOT_BOOTP
+               if (!rarp()) {
+#else
+               if (!bootp()) {
+#endif
+                       printf("No Server found\n");
+#ifdef EMERGENCYDISKBOOT
+                       exit(0);
+#else
+                       goto retry;
+#endif
+               }
+               bootp_completed++;
+       }
+       printf("Me: %I, Server: %I",
+               arptable[ARP_CLIENT].ipaddr.s_addr,
+               arptable[ARP_SERVER].ipaddr.s_addr);
+       if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr)
+               printf(", Relay: %I",
+                       BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr);
+       if (arptable[ARP_GATEWAY].ipaddr.s_addr)
+               printf(", Gateway %I", arptable[ARP_GATEWAY].ipaddr.s_addr);
+       putchar('\n');
+
+#ifdef MDEBUG
+       printf("\n=>>"); getchar();
+#endif
+
+#ifdef MOTD
+       if (vendorext_isvalid)
+               show_motd();
+#endif
+       /* Now use TFTP to load file */
+#ifdef IMAGE_MENU
+       if (vendorext_isvalid && useimagemenu) {
+               selectImage(imagelist);
+               bootp_completed = 0;
+       }
+#endif
+#ifdef DOWNLOAD_PROTO_NFS
+       rpc_init();
+#endif
+       for (;;) {
+               printf("Loading %s ",kernel);
+               while (!loadkernel(kernel)) {
+                       printf("Unable to load file.\n");
+                       sleep(2);       /* lay off server for a while */
+               }
+       }
+}
+
+/**************************************************************************
+DEFAULT_NETMASK - Return default netmask for IP address
+**************************************************************************/
+static inline unsigned long default_netmask(void)
+{
+       int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
+       if (net <= 127)
+               return(htonl(0xff000000));
+       else if (net < 192)
+               return(htonl(0xffff0000));
+       else
+               return(htonl(0xffffff00));
+}
+
+/**************************************************************************
+UDP_TRANSMIT - Send a UDP datagram
+**************************************************************************/
+int udp_transmit(unsigned long destip, unsigned int srcsock,
+       unsigned int destsock, int len, const void *buf)
+{
+       struct iphdr *ip;
+       struct udphdr *udp;
+       struct arprequest arpreq;
+       int arpentry, i;
+       int retry;
+
+       ip = (struct iphdr *)buf;
+       udp = (struct udphdr *)((long)buf + sizeof(struct iphdr));
+       ip->verhdrlen = 0x45;
+       ip->service = 0;
+       ip->len = htons(len);
+       ip->ident = 0;
+       ip->frags = 0;
+       ip->ttl = 60;
+       ip->protocol = IP_UDP;
+       ip->chksum = 0;
+       ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
+       ip->dest.s_addr = destip;
+       ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr));
+       udp->src = htons(srcsock);
+       udp->dest = htons(destsock);
+       udp->len = htons(len - sizeof(struct iphdr));
+       udp->chksum = 0;
+       if (destip == IP_BROADCAST) {
+               eth_transmit(broadcast, IP, len, buf);
+       } else {
+               if (((destip & netmask) !=
+                       (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
+                       arptable[ARP_GATEWAY].ipaddr.s_addr)
+                               destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
+               for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
+                       if (arptable[arpentry].ipaddr.s_addr == destip) break;
+               if (arpentry == MAX_ARP) {
+                       printf("%I is not in my arp table!\n", destip);
+                       return(0);
+               }
+               for (i = 0; i<ETHER_ADDR_SIZE; i++)
+                       if (arptable[arpentry].node[i]) break;
+               if (i == ETHER_ADDR_SIZE) {     /* Need to do arp request */
+                       arpreq.hwtype = htons(1);
+                       arpreq.protocol = htons(IP);
+                       arpreq.hwlen = ETHER_ADDR_SIZE;
+                       arpreq.protolen = 4;
+                       arpreq.opcode = htons(ARP_REQUEST);
+                       memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+                       memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
+                       memset(arpreq.thwaddr, 0, ETHER_ADDR_SIZE);
+                       memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
+                       for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
+                               eth_transmit(broadcast, ARP, sizeof(arpreq),
+                                       &arpreq);
+                               if (await_reply(AWAIT_ARP, arpentry,
+                                       arpreq.tipaddr, TIMEOUT)) goto xmit;
+                               rfc951_sleep(retry);
+                               /* We have slept for a while - the packet may
+                                * have arrived by now.  If not, we have at
+                                * least some room in the Rx buffer for the
+                                * next reply.  */
+                               if (await_reply(AWAIT_ARP, arpentry,
+                                       arpreq.tipaddr, 0)) goto xmit;
+                       }
+                       return(0);
+               }
+xmit:
+               eth_transmit(arptable[arpentry].node, IP, len, buf);
+       }
+       return(1);
+}
+
+/**************************************************************************
+DOWNLOADKERNEL - Try to load file
+**************************************************************************/
+int downloadkernel(data, block, len, eof)
+       unsigned char   *data;
+       int             block, len, eof;
+{
+#ifdef SIZEINDICATOR
+       static int rlen = 0;
+
+       if (!(block % 4) || eof) {
+               int size;
+               size = ((block-1) * rlen + len) / 1024;
+
+               putchar('\b');
+               putchar('\b');
+               putchar('\b');
+               putchar('\b');
+
+               putchar('0' + (size/1000)%10);
+               putchar('0' + (size/100)%10);
+               putchar('0' + (size/10)%10);
+               putchar('0' + (size/1)%10);
+       }
+#endif
+       if (block == 1)
+       {
+#ifdef SIZEINDICATOR
+               rlen=len;
+#endif
+               if (!eof && (
+#ifdef TAGGED_IMAGE
+                   *((unsigned long *)data) == 0x1B031336L ||
+#endif
+#ifdef ELF_IMAGE
+                   *((unsigned long *)data) == 0x464C457FL ||
+#endif
+#ifdef AOUT_IMAGE
+                   *((unsigned short *)data) == 0x010BL ||
+#endif
+                   ((unsigned short *)data)[255] == 0xAA55))
+               {
+                       ;
+               }
+               else if (eof)
+               {
+                       memcpy(config_buffer, data, len);
+                       config_buffer[len] = 0;
+                       return (1); /* done */
+               }
+               else
+               {
+                       printf("error: not a tagged image\n");
+                       return(0); /* error */
+               }
+       }
+       if (len != 0) {
+               if (!os_download(block, data, len))
+                       return(0); /* error */
+       }
+       if (eof) {
+               os_download(block+1, data, 0); /* does not return */
+               return(0); /* error */
+       }
+       return(-1); /* there is more data */
+}
+
+#ifdef DOWNLOAD_PROTO_TFTP
+/**************************************************************************
+TFTP - Download extended BOOTP data, or kernel image
+**************************************************************************/
+int tftp(const char *name, int (*fnc)(unsigned char *, int, int, int))
+{
+       int             retry = 0;
+       static unsigned short iport = 2000;
+       unsigned short  oport;
+       unsigned short  len, block = 0, prevblock = 0;
+       int             bcounter = 0;
+       struct tftp_t  *tr;
+       struct tftp_t   tp;
+       int             rc;
+       int             packetsize = TFTP_DEFAULTSIZE_PACKET;
+
+       /* Clear out the Rx queue first.  It contains nothing of interest,
+        * except possibly ARP requests from the DHCP/TFTP server.  We use
+        * polling throughout Etherboot, so some time may have passed since we
+        * last polled the receive queue, which may now be filled with
+        * broadcast packets.  This will cause the reply to the packets we are
+        * about to send to be lost immediately.  Not very clever.  */
+       await_reply(AWAIT_QDRAIN, 0, NULL, 0);
+
+       tp.opcode = htons(TFTP_RRQ);
+       len = (sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
+                      name, 0, 0, 0, TFTP_MAX_PACKET) - ((char *)&tp)) + 1;
+       if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
+               TFTP_PORT, len, &tp))
+               return (0);
+       for (;;)
+       {
+#ifdef CONGESTED
+               if (!await_reply(AWAIT_TFTP, iport, NULL, (block ? TFTP_REXMT : TIMEOUT)))
+#else
+               if (!await_reply(AWAIT_TFTP, iport, NULL, TIMEOUT))
+#endif
+               {
+                       if (!block && retry++ < MAX_TFTP_RETRIES)
+                       {       /* maybe initial request was lost */
+                               rfc951_sleep(retry);
+                               if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
+                                       ++iport, TFTP_PORT, len, &tp))
+                                       return (0);
+                               continue;
+                       }
+#ifdef CONGESTED
+                       if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
+                       {       /* we resend our last ack */
+#ifdef MDEBUG
+                               printf("<REXMT>\n");
+#endif
+                               udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
+                                       iport, oport,
+                                       TFTP_MIN_PACKET, &tp);
+                               continue;
+                       }
+#endif
+                       break;  /* timeout */
+               }
+               tr = (struct tftp_t *)&nic.packet[ETHER_HDR_SIZE];
+               if (tr->opcode == ntohs(TFTP_ERROR))
+               {
+                       printf("TFTP error %d (%s)\n",
+                              ntohs(tr->u.err.errcode),
+                              tr->u.err.errmsg);
+                       break;
+               }
+
+               if (tr->opcode == ntohs(TFTP_OACK)) {
+                       char *p = tr->u.oack.data, *e;
+
+                       if (prevblock)          /* shouldn't happen */
+                               continue;       /* ignore it */
+                       len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
+                       if (len > TFTP_MAX_PACKET)
+                               goto noak;
+                       e = p + len;
+                       while (*p != '\000' && p < e) {
+                               if (!strcasecmp("blksize", p)) {
+                                       p += 8;
+                                       if ((packetsize = getdec(&p)) <
+                                           TFTP_DEFAULTSIZE_PACKET)
+                                               goto noak;
+                                       while (p < e && *p) p++;
+                                       if (p < e)
+                                               p++;
+                               }
+                               else {
+                               noak:
+                                       tp.opcode = htons(TFTP_ERROR);
+                                       tp.u.err.errcode = 8;
+                                       len = (sprintf((char *)tp.u.err.errmsg,
+                                                      "RFC1782 error")
+                                              - ((char *)&tp)) + 1;
+                                       udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
+                                                    iport, ntohs(tr->udp.src),
+                                                    len, &tp);
+                                       return (0);
+                               }
+                       }
+                       if (p > e)
+                               goto noak;
+                       block = tp.u.ack.block = 0; /* this ensures, that */
+                                               /* the packet does not get */
+                                               /* processed as data! */
+               }
+               else if (tr->opcode == ntohs(TFTP_DATA)) {
+                       len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
+                       if (len > packetsize)   /* shouldn't happen */
+                               continue;       /* ignore it */
+                       block = ntohs(tp.u.ack.block = tr->u.data.block); }
+               else /* neither TFTP_OACK nor TFTP_DATA */
+                       break;
+
+               if ((block || bcounter) && (block != prevblock+1)) {
+                       /* Block order should be continuous */
+                       tp.u.ack.block = htons(block = prevblock);
+               }
+               tp.opcode = htons(TFTP_ACK);
+               oport = ntohs(tr->udp.src);
+               udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
+                       oport, TFTP_MIN_PACKET, &tp);   /* ack */
+               if ((unsigned short)(block-prevblock) != 1) {
+                       /* Retransmission or OACK, don't process via callback
+                        * and don't change the value of prevblock.  */
+                       continue;
+               }
+               prevblock = block;
+               retry = 0;      /* It's the right place to zero the timer? */
+               if ((rc = fnc(tr->u.data.download,
+                             ++bcounter, len, len < packetsize)) >= 0)
+                       return(rc);
+               if (len < packetsize)           /* End of data */
+                       return (1);
+       }
+       return (0);
+}
+#endif /* DOWNLOAD_PROTO_TFTP */
+
+#ifdef RARP_NOT_BOOTP
+/**************************************************************************
+RARP - Get my IP address and load information
+**************************************************************************/
+int rarp()
+{
+       int retry;
+
+       /* arp and rarp requests share the same packet structure. */
+       struct arprequest rarpreq;
+
+       memset(&rarpreq, 0, sizeof(rarpreq));
+
+       rarpreq.hwtype = htons(1);
+       rarpreq.protocol = htons(IP);
+       rarpreq.hwlen = ETHER_ADDR_SIZE;
+       rarpreq.protolen = 4;
+       rarpreq.opcode = htons(RARP_REQUEST);
+       memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+       /* sipaddr is already zeroed out */
+       memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+       /* tipaddr is already zeroed out */
+
+       for (retry = 0; retry < MAX_ARP_RETRIES; rfc951_sleep(++retry)) {
+               eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
+
+               if (await_reply(AWAIT_RARP, 0, rarpreq.shwaddr, TIMEOUT))
+                       break;
+       }
+
+       if (retry < MAX_ARP_RETRIES) {
+               sprintf(kernel = kernel_buf, "/tftpboot/kernel.%I", arptable[ARP_CLIENT].ipaddr);
+
+               return (1);
+       }
+       return (0);
+}
+
+#else
+
+/**************************************************************************
+BOOTP - Get my IP address and load information
+**************************************************************************/
+int bootp()
+{
+       int retry;
+#ifndef        NO_DHCP_SUPPORT
+       int retry1;
+#endif /* NO_DHCP_SUPPORT */
+       struct bootp_t bp;
+       unsigned long  starttime;
+#ifdef T509HACK
+       int flag;
+
+       flag = 1;
+#endif
+       memset(&bp, 0, sizeof(struct bootp_t));
+       bp.bp_op = BOOTP_REQUEST;
+       bp.bp_htype = 1;
+       bp.bp_hlen = ETHER_ADDR_SIZE;
+       bp.bp_xid = xid = starttime = currticks();
+       memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+#ifdef NO_DHCP_SUPPORT
+       memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */
+#else
+       memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
+       memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover);
+       memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end);
+#endif /* NO_DHCP_SUPPORT */
+
+       for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
+
+               /* Clear out the Rx queue first.  It contains nothing of
+                * interest, except possibly ARP requests from the DHCP/TFTP
+                * server.  We use polling throughout Etherboot, so some time
+                * may have passed since we last polled the receive queue,
+                * which may now be filled with broadcast packets.  This will
+                * cause the reply to the packets we are about to send to be
+                * lost immediately.  Not very clever.  */
+               await_reply(AWAIT_QDRAIN, 0, NULL, 0);
+
+               udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
+                       sizeof(struct bootp_t), &bp);
+#ifdef T509HACK
+               if (flag) {
+                       flag--;
+               } else {
+                       if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+                               return(1);
+                       rfc951_sleep(++retry);
+
+               }
+#else
+#ifdef NO_DHCP_SUPPORT
+               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+#else
+               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){
+                       if (dhcp_reply==DHCPOFFER){
+               dhcp_reply=0;
+               memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
+               memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
+               memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end);
+               memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr));
+               memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr));
+                       for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) {
+                       udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
+                               sizeof(struct bootp_t), &bp);
+                               dhcp_reply=0;
+                               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+                                       if (dhcp_reply==DHCPACK)
+                                               return(1);
+                                       rfc951_sleep(++retry1);
+                               }
+                       } else
+#endif /* NO_DHCP_SUPPORT */
+                               return(1);
+#ifndef        NO_DHCP_SUPPORT
+               }
+               rfc951_sleep(++retry);
+
+#endif /* NO_DHCP_SUPPORT */
+#endif
+               bp.bp_secs = htons((currticks()-starttime)/20);
+       }
+       return(0);
+}
+#endif /* RARP_NOT_BOOTP */
+
+/**************************************************************************
+AWAIT_REPLY - Wait until we get a response for our request
+**************************************************************************/
+int await_reply(int type, int ival, void *ptr, int timeout)
+{
+       unsigned long time;
+       struct  iphdr *ip;
+       struct  udphdr *udp;
+       struct  arprequest *arpreply;
+       struct  bootp_t *bootpreply;
+       struct  rpc_t *rpc;
+       unsigned short ptype;
+
+       unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
+                               sizeof(struct udphdr);
+       time = timeout + currticks();
+       /* The timeout check is done below.  The timeout is only checked if
+        * there is no packet in the Rx queue.  This assumes that eth_poll()
+        * needs a negligible amount of time.  */
+       for (;;) {
+               if (eth_poll()) {       /* We have something! */
+                                       /* Check for ARP - No IP hdr */
+                       if (nic.packetlen >= ETHER_HDR_SIZE) {
+                               ptype = ((unsigned short) nic.packet[12]) << 8
+                                       | ((unsigned short) nic.packet[13]);
+                       } else continue; /* what else could we do with it? */
+                       if ((nic.packetlen >= ETHER_HDR_SIZE +
+                               sizeof(struct arprequest)) &&
+                          (ptype == ARP) ) {
+                               unsigned long tmp;
+
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
+                                  !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
+                                  (type == AWAIT_ARP)) {
+                                       memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       return(1);
+                               }
+                               memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                               if ((arpreply->opcode == ntohs(ARP_REQUEST)) &&
+                                       (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
+                                       arpreply->opcode = htons(ARP_REPLY);
+                                       memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+                                       eth_transmit(arpreply->thwaddr, ARP,
+                                               sizeof(struct  arprequest),
+                                               arpreply);
+#ifdef MDEBUG
+                                       memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                                       printf("Sent ARP reply to: %I\n",tmp);
+#endif MDEBUG
+                               }
+                               continue;
+                       }
+
+                       if (type == AWAIT_QDRAIN) {
+                               continue;
+                       }
+
+                                       /* Check for RARP - No IP hdr */
+                       if ((type == AWAIT_RARP) &&
+                          (nic.packetlen >= ETHER_HDR_SIZE +
+                               sizeof(struct arprequest)) &&
+                          (ptype == RARP)) {
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(RARP_REPLY)) &&
+                                  !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) {
+                                       memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
+                                       return(1);
+                               }
+                               continue;
+                       }
+
+                                       /* Anything else has IP header */
+                       if ((nic.packetlen < protohdrlen) ||
+                          (ptype != IP) ) continue;
+                       ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((ip->verhdrlen != 0x45) ||
+                               ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
+                               (ip->protocol != IP_UDP)) continue;
+                       udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE +
+                               sizeof(struct iphdr)];
+
+                                       /* BOOTP ? */
+                       bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((type == AWAIT_BOOTP) &&
+                          (nic.packetlen >= (ETHER_HDR_SIZE +
+#ifdef NO_DHCP_SUPPORT
+                            sizeof(struct bootp_t))) &&
+#else
+                            sizeof(struct bootp_t))-DHCP_OPT_LEN) &&
+#endif /* NO_DHCP_SUPPORT */
+                          (ntohs(udp->dest) == BOOTP_CLIENT) &&
+                          (bootpreply->bp_op == BOOTP_REPLY) &&
+                          (bootpreply->bp_xid == xid)) {
+                               arptable[ARP_CLIENT].ipaddr.s_addr =
+                                       bootpreply->bp_yiaddr.s_addr;
+#ifndef        NO_DHCP_SUPPORT
+                               dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
+#endif /* NO_DHCP_SUPPORT */
+                               netmask = default_netmask();
+                               arptable[ARP_SERVER].ipaddr.s_addr =
+                                       bootpreply->bp_siaddr.s_addr;
+                               memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+                               arptable[ARP_GATEWAY].ipaddr.s_addr =
+                                       bootpreply->bp_giaddr.s_addr;
+                               memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+                               if (bootpreply->bp_file[0]) {
+                                       memcpy(kernel_buf, bootpreply->bp_file, 128);
+                                       kernel = kernel_buf;
+                               }
+                               memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
+                               decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
+#ifdef NO_DHCP_SUPPORT
+                                              0, BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 1);
+#else
+                                              0, DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 1);
+#endif /* NO_DHCP_SUPPORT */
+                               return(1);
+                       }
+
+#ifdef DOWNLOAD_PROTO_TFTP
+                                       /* TFTP ? */
+                       if ((type == AWAIT_TFTP) &&
+                               (ntohs(udp->dest) == ival)) return(1);
+#endif /* DOWNLOAD_PROTO_TFTP */
+
+#ifdef DOWNLOAD_PROTO_NFS
+                                       /* RPC ? */
+                       rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((type == AWAIT_RPC) &&
+                           (ntohs(udp->dest) == ival) &&
+                           (*(unsigned long *)ptr == ntohl(rpc->u.reply.id)) &&
+                           (ntohl(rpc->u.reply.type) == MSG_REPLY)) {
+                               return (1);
+                       }
+#endif /* DOWNLOAD_PROTO_NFS */
+
+               } else {
+                       /* Check for abort key only if the Rx queue is empty -
+                        * as long as we have something to process, don't
+                        * assume that something failed.  It is unlikely that
+                        * we have no processing time left between packets.  */
+                       if (iskey() && (getchar() == ESC))
+#ifdef EMERGENCYDISKBOOT
+                               exit(0);
+#else
+                               longjmp(jmp_bootmenu,1);
+#endif
+                       /* Do the timeout after at least a full queue walk.  */
+                       if ((timeout == 0) || (currticks() > time)) {
+                               break;
+                       }
+               }
+       }
+       return(0);
+}
+
+/**************************************************************************
+DECODE_RFC1533 - Decodes RFC1533 header
+**************************************************************************/
+int decode_rfc1533(p, block, len, eof)
+       register unsigned char *p;
+       int block, len, eof;
+{
+       static unsigned char *extdata = NULL, *extend = NULL;
+       unsigned char        *extpath = NULL;
+       unsigned char        *endp;
+
+       if (block == 0) {
+#ifdef IMAGE_MENU
+               memset(imagelist, 0, sizeof(imagelist));
+               menudefault = useimagemenu = 0;
+               menutmo = -1;
+#endif
+#ifdef MOTD
+               memset(motd, 0, sizeof(motd));
+#endif
+               end_of_rfc1533 = NULL;
+               vendorext_isvalid = 0;
+               if (memcmp(p, rfc1533_cookie, 4))
+                       return(0); /* no RFC 1533 header found */
+               p += 4;
+               endp = p + len; }
+       else {
+               if (block == 1) {
+                       if (memcmp(p, rfc1533_cookie, 4))
+                               return(0); /* no RFC 1533 header found */
+                       p += 4;
+                       len -= 4; }
+               if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) {
+                       memcpy(extend, p, len);
+                       extend += len;
+               } else {
+                       printf("Overflow in vendor data buffer! Aborting...\n");
+                       *extdata = RFC1533_END;
+                       return(0);
+               }
+               p = extdata; endp = extend;
+       }
+       if (eof) {
+               while(p < endp) {
+                       unsigned char c = *p;
+                       if (c == RFC1533_PAD) {p++; continue;}
+                       else if (c == RFC1533_END) {
+                               end_of_rfc1533 = endp = p; continue; }
+                       else if (c == RFC1533_NETMASK) {memcpy(&netmask, p+2, sizeof(in_addr));}
+
+                       else if (c == RFC1533_GATEWAY) {
+                               /* This is a little simplistic, but it will
+                                  usually be sufficient.
+                                  Take only the first entry */
+                               if (TAG_LEN(p) >= sizeof(in_addr))
+                                       memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
+                       }
+                       else if (c == RFC1533_EXTENSIONPATH)
+                               extpath = p;
+#ifndef        NO_DHCP_SUPPORT
+                       else if (c == RFC2132_MSG_TYPE)
+                               { dhcp_reply=*(p+2);
+                               }
+                       else if (c == RFC2132_SRV_ID)
+                               {
+                               memcpy(&dhcp_server, p+2, sizeof(in_addr));
+                               }
+#endif /* NO_DHCP_SUPPORT */
+                       else if (c == RFC1533_HOSTNAME)
+                               {
+                               hostname = p + 2;
+                               hostnamelen = *(p + 1);
+                               }
+                       else if (c == RFC1533_VENDOR_MAGIC
+#ifndef        IMAGE_FREEBSD   /* since FreeBSD uses tag 128 for swap definition */
+                                && TAG_LEN(p) >= 6 &&
+                                 !memcmp(p+2,vendorext_magic,4) &&
+                                 p[6] == RFC1533_VENDOR_MAJOR
+#endif
+                               )
+                               vendorext_isvalid++;
+#ifdef IMAGE_FREEBSD
+                       else if (c == RFC1533_VENDOR_HOWTO) {
+                               freebsd_howto = ((p[2]*256+p[3])*256+p[4])*256+p[5];
+                       }
+#endif
+#ifdef IMAGE_MENU
+                       else if (c == RFC1533_VENDOR_MNUOPTS) {
+                               parse_menuopts(p+2, TAG_LEN(p));
+                       }
+                       else if (c >= RFC1533_VENDOR_IMG &&
+                                c<RFC1533_VENDOR_IMG+RFC1533_VENDOR_NUMOFIMG){
+                               imagelist[c - RFC1533_VENDOR_IMG] = p;
+                               useimagemenu++;
+                       }
+#endif
+#ifdef MOTD
+                       else if (c >= RFC1533_VENDOR_MOTD &&
+                                c < RFC1533_VENDOR_MOTD +
+                                RFC1533_VENDOR_NUMOFMOTD)
+                               motd[c - RFC1533_VENDOR_MOTD] = p;
+#endif
+                       else {
+#if    0
+                               unsigned char *q;
+                               printf("Unknown RFC1533-tag ");
+                               for(q=p;q<p+2+TAG_LEN(p);q++)
+                                       printf("%x ",*q);
+                               putchar('\n');
+#endif
+                       }
+                       p += TAG_LEN(p) + 2;
+               }
+               extdata = extend = endp;
+               if (block == 0 && extpath != NULL) {
+                       char fname[64];
+                       memcpy(fname, extpath+2, TAG_LEN(extpath));
+                       fname[(int)TAG_LEN(extpath)] = '\000';
+                       printf("Loading BOOTP-extension file: %s\n",fname);
+                       download(fname,decode_rfc1533);
+               }
+       }
+       return(-1); /* proceed with next block */
+}
+
+/**************************************************************************
+IPCHKSUM - Checksum IP Header
+**************************************************************************/
+unsigned short ipchksum(ip, len)
+       register unsigned short *ip;
+       register int len;
+{
+       unsigned long sum = 0;
+       len >>= 1;
+       while (len--) {
+               sum += *(ip++);
+               if (sum > 0xFFFF)
+                       sum -= 0xFFFF;
+       }
+       return((~sum) & 0x0000FFFF);
+}
+
+/**************************************************************************
+RFC951_SLEEP - sleep for expotentially longer times
+**************************************************************************/
+void rfc951_sleep(exp)
+       int exp;
+{
+       static long seed = 0;
+       long q;
+       unsigned long tmo;
+
+#ifdef BACKOFF_LIMIT
+       if (exp > BACKOFF_LIMIT)
+               exp = BACKOFF_LIMIT;
+#endif
+       if (!seed) /* Initialize linear congruential generator */
+               seed = currticks() + *(long *)&arptable[ARP_CLIENT].node
+                      + ((short *)arptable[ARP_CLIENT].node)[2];
+       /* simplified version of the LCG given in Bruce Scheier's
+          "Applied Cryptography" */
+       q = seed/53668;
+       if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l;
+       /* compute mask */
+       for (tmo = 63; tmo <= 60*TICKS_PER_SEC && --exp > 0; tmo = 2*tmo+1);
+       /* sleep */
+       printf("<sleep>\n");
+
+       for (tmo = (tmo&seed)+currticks(); currticks() < tmo; )
+               if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1);
+       return;
+}
+
+/**************************************************************************
+CLEANUP_NET - shut down networking
+**************************************************************************/
+void cleanup_net(void)
+{
+#ifdef DOWNLOAD_PROTO_NFS
+       nfs_umountall(ARP_SERVER);
+#endif
+       eth_disable();
+       eth_reset();
+}
+
+/**************************************************************************
+CLEANUP - shut down etherboot so that the OS may be called right away
+**************************************************************************/
+void cleanup(void)
+{
+#if    defined(ANSIESC) && defined(CONSOLE_CRT)
+       ansi_reset();
+#endif
+}
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff --git a/contrib/baremetal/marini.txt b/contrib/baremetal/marini.txt
new file mode 100644 (file)
index 0000000..464f148
--- /dev/null
@@ -0,0 +1,52 @@
+From: "Paolo Marini" <paolom@prisma-eng.it>
+Subject: Etherboot on bare metal
+Date: Tue, 10 Apr 2001 23:19:19 +0200
+Organization: Prisma Engineering srl
+
+Hi Ken,
+I have ported Etherboot on an embedded, biosless platform and would like
+to contribute the code.
+
+Essentially, the hardware I was running Etherboot is a Pentium based
+embedded system, with an Intel Chipset, *but* without serial, VGA,
+keyboard etc., only an 82559 Intel (custom) Ethernet controller (I debug
+it with the etheral Ethernet packet analyser and an emulator).
+
+What I did was:
+
+  a.. integrate the init.s file within the firmware, with GDT
+(re)initialisation (a simple and single entry point taking control of
+the boot process)
+  b.. provide some stupid BIOS stubs in order to let the OS boot and
+still belive that an INT10 call goes to the BIOS
+  c.. provide some basic functions to Etherboot, like timer (I used the
+Pentium TSC internal counter)
+  d.. hardwire in the code information about the RAM size
+The BIOS stubs are enough to boot Linux, pSOS and QNX with bootp. QNX is
+somewhat difficult to load, because the i82559 driver tries to find the
+component using the BIOS32 calls, so I had to patch it.
+
+what i I got from the original firmware is the PCI initialisation and
+resource (I/O, interrupts, memory) allocation.
+
+I send you what I changed, that is, the initialisation code and the
+misc.c file containing the timer, and the makefile (I don't remember
+exactly the options I used to compile all).
+
+Of course, it is only a good starting point for anyone wanting to
+implement a bootp client on a biosless platform; some integration work
+still needs to be done.
+
+Ciao
+Paolo
+
+And in a subsequent email:
+
+I worked with version 4.6.12, but the real modifications involve the
+init.S file, which I think is quite sstable between releases.  I forgot
+to say that my entry point (symbol _start in init.s) assumes the
+processor is already in protected mode.
+
+[The only difference between main.c and misc.c from those in Etherboot
+4.6.12 seems to be the deletion of eth_reset(). This may be of use to
+others trying to make these changes work on more recent releases. Ken]
diff --git a/contrib/baremetal/misc.c b/contrib/baremetal/misc.c
new file mode 100644 (file)
index 0000000..924ccd6
--- /dev/null
@@ -0,0 +1,351 @@
+/**************************************************************************
+MISC Support Routines
+**************************************************************************/
+
+#include "etherboot.h"
+
+/**************************************************************************
+SLEEP
+**************************************************************************/
+void sleep(int secs)
+{
+       unsigned long tmo;
+
+       for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; )
+               /* Nothing */;
+}
+
+/**************************************************************************
+TWIDDLE
+**************************************************************************/
+void twiddle()
+{
+       static unsigned long lastticks = 0;
+       static int count=0;
+       static const char tiddles[]="-\\|/";
+       unsigned long ticks;
+       if ((ticks = currticks()) == lastticks)
+               return;
+       lastticks = ticks;
+       putchar(tiddles[(count++)&3]);
+       putchar('\b');
+}
+
+/**************************************************************************
+STRCASECMP (not entirely correct, but this will do for our purposes)
+**************************************************************************/
+int strcasecmp(a,b)
+       char *a, *b;
+{
+       while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
+       return((*a & ~0x20) - (*b & ~0x20));
+}
+
+/**************************************************************************
+PRINTF and friends
+
+       Formats:
+               %[#]X   - 4 bytes long (8 hex digits)
+               %[#]x   - 2 bytes int (4 hex digits)
+                       - optional # prefixes 0x
+               %b      - 1 byte int (2 hex digits)
+               %d      - decimal int
+               %c      - char
+               %s      - string
+               %I      - Internet address in x.x.x.x notation
+       Note: width specification not supported
+**************************************************************************/
+static char *do_printf(char *buf, const char *fmt, const int *dp)
+{
+       register char *p;
+       int alt;
+       char tmp[16];
+       static const char hex[]="0123456789ABCDEF";
+
+       while (*fmt) {
+               if (*fmt == '%') {      /* switch() uses more space */
+                       alt = 0;
+                       fmt++;
+                       if (*fmt == '#') {
+                               alt = 1;
+                               fmt++;
+                       }
+                       if (*fmt == 'X') {
+                               const long *lp = (const long *)dp;
+                               register long h = *lp++;
+                               dp = (const int *)lp;
+                               if (alt) {
+                                       *buf++ = '0';
+                                       *buf++ = 'x';
+                               }
+                               *(buf++) = hex[(h>>28)& 0x0F];
+                               *(buf++) = hex[(h>>24)& 0x0F];
+                               *(buf++) = hex[(h>>20)& 0x0F];
+                               *(buf++) = hex[(h>>16)& 0x0F];
+                               *(buf++) = hex[(h>>12)& 0x0F];
+                               *(buf++) = hex[(h>>8)& 0x0F];
+                               *(buf++) = hex[(h>>4)& 0x0F];
+                               *(buf++) = hex[h& 0x0F];
+                       }
+                       if (*fmt == 'x') {
+                               register int h = *(dp++);
+                               if (alt) {
+                                       *buf++ = '0';
+                                       *buf++ = 'x';
+                               }
+                               *(buf++) = hex[(h>>12)& 0x0F];
+                               *(buf++) = hex[(h>>8)& 0x0F];
+                               *(buf++) = hex[(h>>4)& 0x0F];
+                               *(buf++) = hex[h& 0x0F];
+                       }
+                       if (*fmt == 'b') {
+                               register int h = *(dp++);
+                               *(buf++) = hex[(h>>4)& 0x0F];
+                               *(buf++) = hex[h& 0x0F];
+                       }
+                       if (*fmt == 'd') {
+                               register int dec = *(dp++);
+                               p = tmp;
+                               if (dec < 0) {
+                                       *(buf++) = '-';
+                                       dec = -dec;
+                               }
+                               do {
+                                       *(p++) = '0' + (dec%10);
+                                       dec = dec/10;
+                               } while(dec);
+                               while ((--p) >= tmp) *(buf++) = *p;
+                       }
+                       if (*fmt == 'I') {
+                               union {
+                                       long            l;
+                                       unsigned char   c[4];
+                               } u;
+                               const long *lp = (const long *)dp;
+                               u.l = *lp++;
+                               dp = (const int *)lp;
+                               buf = sprintf(buf,"%d.%d.%d.%d",
+                                       u.c[0], u.c[1], u.c[2], u.c[3]);
+                       }
+                       if (*fmt == 'c')
+                               *(buf++) = *(dp++);
+                       if (*fmt == 's') {
+                               p = (char *)*dp++;
+                               while (*p) *(buf++) = *p++;
+                       }
+               } else *(buf++) = *fmt;
+               fmt++;
+       }
+       *buf = '\0';
+       return(buf);
+}
+
+char *sprintf(char *buf, const char *fmt, ...)
+{
+       return do_printf(buf, fmt, ((const int *)&fmt)+1);
+}
+
+void printf(const char *fmt, ...)
+{
+       char buf[120], *p;
+
+       p = buf;
+       do_printf(buf, fmt, ((const int *)&fmt)+1);
+       while (*p) putchar(*p++);
+}
+
+#ifdef IMAGE_MENU
+/**************************************************************************
+INET_ATON - Convert an ascii x.x.x.x to binary form
+**************************************************************************/
+int inet_aton(char *p, in_addr *i)
+{
+       unsigned long ip = 0;
+       int val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       if (*p != '.') return(0);
+       p++;
+       ip = val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       if (*p != '.') return(0);
+       p++;
+       ip = (ip << 8) | val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       if (*p != '.') return(0);
+       p++;
+       ip = (ip << 8) | val;
+       if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+       i->s_addr = htonl((ip << 8) | val);
+       return(1);
+}
+
+#endif /* IMAGE_MENU */
+
+int getdec(char **ptr)
+{
+       char *p = *ptr;
+       int ret=0;
+       if ((*p < '0') || (*p > '9')) return(-1);
+       while ((*p >= '0') && (*p <= '9')) {
+               ret = ret*10 + (*p - '0');
+               p++;
+       }
+       *ptr = p;
+       return(ret);
+}
+
+#define K_RDWR         0x60            /* keyboard data & cmds (read/write) */
+#define K_STATUS       0x64            /* keyboard status */
+#define K_CMD          0x64            /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL     0x01            /* output buffer full */
+#define K_IBUF_FUL     0x02            /* input buffer full */
+
+#define KC_CMD_WIN     0xd0            /* read  output port */
+#define KC_CMD_WOUT    0xd1            /* write output port */
+#define KB_SET_A20     0xdf            /* enable A20,
+                                          enable output buffer full interrupt
+                                          enable data line
+                                          disable clock line */
+#define KB_UNSET_A20   0xdd            /* enable A20,
+                                          enable output buffer full interrupt
+                                          enable data line
+                                          disable clock line */
+#ifndef        IBM_L40
+static void empty_8042(void)
+{
+       unsigned long time;
+       char st;
+
+       time = currticks() + TICKS_PER_SEC;     /* max wait of 1 second */
+       while ((((st = inb(K_CMD)) & K_OBUF_FUL) ||
+              (st & K_IBUF_FUL)) &&
+              currticks() < time)
+               inb(K_RDWR);
+}
+#endif IBM_L40
+
+/*
+ * Gate A20 for high memory
+ */
+void gateA20_set(void)
+{
+#ifdef IBM_L40
+       outb(0x2, 0x92);
+#else  /* IBM_L40 */
+       empty_8042();
+       outb(KC_CMD_WOUT, K_CMD);
+       empty_8042();
+       outb(KB_SET_A20, K_RDWR);
+       empty_8042();
+#endif /* IBM_L40 */
+}
+
+#ifdef TAGGED_IMAGE
+/*
+ * Unset Gate A20 for high memory - some operating systems (mainly old 16 bit
+ * ones) don't expect it to be set by the boot loader.
+ */
+void gateA20_unset(void)
+{
+#ifdef IBM_L40
+       outb(0x0, 0x92);
+#else  /* IBM_L40 */
+       empty_8042();
+       outb(KC_CMD_WOUT, K_CMD);
+       empty_8042();
+       outb(KB_UNSET_A20, K_RDWR);
+       empty_8042();
+#endif /* IBM_L40 */
+}
+#endif
+
+#ifdef ETHERBOOT32
+/* Serial console is only implemented in ETHERBOOT32 for now */
+void
+putchar(int c)
+{
+#ifndef        ANSIESC
+       if (c == '\n')
+               putchar('\r');
+#endif
+
+#ifdef CONSOLE_CRT
+#ifdef ANSIESC
+       handleansi(c);
+#else
+       putc(c);
+#endif
+#endif
+#ifdef CONSOLE_SERIAL
+#ifdef ANSIESC
+       if (c == '\n')
+               serial_putc('\r');
+#endif
+       serial_putc(c);
+#endif
+}
+
+/**************************************************************************
+GETCHAR - Read the next character from the console WITHOUT ECHO
+**************************************************************************/
+int
+getchar(void)
+{
+       int c = 256;
+
+#if defined CONSOLE_CRT || defined CONSOLE_SERIAL
+       do {
+#ifdef CONSOLE_CRT
+               if (ischar())
+                       c = getc();
+#endif
+#ifdef CONSOLE_SERIAL
+               if (serial_ischar())
+                       c = serial_getc();
+#endif
+       } while (c==256);
+       if (c == '\r')
+               c = '\n';
+#endif         
+       return c;
+}
+
+int
+iskey(void)
+{
+#ifdef CONSOLE_CRT
+       if (ischar())
+               return 1;
+#endif
+#ifdef CONSOLE_SERIAL
+       if (serial_ischar())
+               return 1;
+#endif
+       return 0;
+}
+#endif /* ETHERBOOT32 */
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
+#include <asm/msr.h>
+
+#define CPUCLOCK 166
+
+unsigned long currticks(void)
+{
+    register unsigned long l, h;
+    long long unsigned p;
+    long long unsigned hh,ll;
+    
+    rdtsc(l, h);
+    ll = l, hh = h;
+
+    p = (ll + hh * 0x100000000LL) * 182 / (CPUCLOCK * 100000LL);
+    return (unsigned)p;
+}
+
diff --git a/contrib/baremetal/startmpcc.S b/contrib/baremetal/startmpcc.S
new file mode 100644 (file)
index 0000000..07486ce
--- /dev/null
@@ -0,0 +1,756 @@
+/* #defines because ljmp wants a number, probably gas bug */
+/*     .equ    KERN_CODE_SEG,_pmcs-_gdt        */
+#define        KERN_CODE_SEG   0x08
+       .equ    KERN_DATA_SEG,_pmds-_gdt
+/*     .equ    REAL_CODE_SEG,_rmcs-_gdt        */
+#define        REAL_CODE_SEG   0x18
+       .equ    REAL_DATA_SEG,_rmds-_gdt
+       .equ    CR0_PE,1
+
+#ifdef GAS291
+#define DATA32 data32;
+#define ADDR32 addr32;
+#define        LJMPI(x)        ljmp    x
+#else
+#define DATA32 data32
+#define ADDR32 addr32
+/* newer GAS295 require #define        LJMPI(x)        ljmp    *x */
+#define        LJMPI(x)        ljmp    x
+#endif
+
+#define PIC1_VBS  0x08      /* PIC1 interrupts start at vector 64  */
+#define PIC2_VBS  0x70      /* PIC1 interrupts start at vector 112  */
+
+/*
+ * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
+ * then you only have to take care of %ebx, %esi, %edi and %ebp.  These
+ * registers must not be altered under any circumstance.  All other registers
+ * may be clobbered without any negative side effects.  If you don't follow
+ * this rule then you'll run into strange effects that only occur on some
+ * gcc versions (because the register allocator may use different registers).
+ *
+ * All the data32 prefixes for the ljmp instructions are necessary, because
+ * the assembler emits code with a relocation address of 0.  This means that
+ * all destinations are initially negative, which the assembler doesn't grok,
+ * because for some reason negative numbers don't fit into 16 bits. The addr32
+ * prefixes are there for the same reasons, because otherwise the memory
+ * references are only 16 bit wide.  Theoretically they are all superfluous.
+ * One last note about prefixes: the data32 prefixes on all call _real_to_prot
+ * instructions could be removed if the _real_to_prot function is changed to
+ * deal correctly with 16 bit return addresses.  I tried it, but failed.
+ */
+
+/**************************************************************************
+START - Where all the fun begins....
+**************************************************************************/
+/* this must be the first thing in the file because we enter from the top */
+       .global _start
+       .code32
+_start:
+       cli
+       
+       /* load new IDT and GDT */
+       lgdt    gdtarg
+       lidt    Idt_Reg
+       /* flush prefetch queue, and reload %cs:%eip */
+       ljmp    $KERN_CODE_SEG,$1f
+1:
+       
+       /* reload other segment registers */
+       movl    $KERN_DATA_SEG,%eax
+       movl    %eax,%ds
+       movl    %eax,%es
+       movl    %eax,%ss
+        movl    $stktop,%esp
+
+       /* program the PITs in order to stop them */
+        mov    $0x30,%al
+       out     %al,$0x43
+       out     %al,$0x40
+        mov    $0x70,%al
+       out     %al,$0x43
+       out     %al,$0x41
+        mov    $0xf0,%al
+       out     %al,$0x43
+       out     %al,$0x42       
+
+       call    main
+       /* fall through */
+
+       .globl  exit
+exit:
+2:
+        ljmp $KERN_CODE_SEG,$2b
+
+/**************************************************************************
+MEMSIZE - Determine size of extended memory
+**************************************************************************/
+       .globl  memsize
+memsize:
+#if 0
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+       call    _prot_to_real
+       .code16
+       movw    $0xe801,%ax
+       stc
+       int     $0x15
+       jc      1f
+       andl    $0xffff,%eax
+       andl    $0xffff,%ebx
+       shll    $6,%ebx
+       addl    %ebx,%eax
+       jmp     2f
+1:
+       movw    $0x8800,%ax
+       int     $0x15
+       andl    $0xffff,%eax
+2:
+       movl    %eax,%esi
+       DATA32 call     _real_to_prot
+       .code32
+       movl    %esi,%eax
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+#else
+       mov     $32768,%eax
+#endif
+       ret
+
+/**************************************************************************
+XSTART - Transfer control to the kernel just loaded
+**************************************************************************/
+       .code16
+
+       .globl _int08_handler
+_int08_handler:
+       movb    $0x20, %al
+       outb    %al, $0x20
+       iret
+
+       .globl _int10_handler
+_int10_handler:
+       cmp     $0x3, %ah
+       jnz     _int10_04
+       mov     $0x0, %dx
+       mov     $0x0, %cx
+       iret
+_int10_04:
+       cmp     $0x4, %ah
+       jnz     _int10_05
+       mov     $0x0, %ah
+       iret
+_int10_05:
+       cmp     $0x5, %ah
+       jnz     _int10_08
+       mov     $0x0, %al
+       iret
+_int10_08:
+       cmp     $0x8, %ah
+       jnz     _int10_0D
+       mov     $0x20, %al
+       mov     $0x7,  %ah
+       iret
+_int10_0D:
+       cmp     $0xD, %ah
+       jnz     _int10_0F
+       mov     $0x0, %al
+       iret
+_int10_0F:
+       cmp     $0xF, %ah
+       jnz     _int10_XX
+       mov     $0xb, %al
+       mov     $80, %ah
+       mov     $0, %bh
+_int10_XX:
+       iret
+       
+       .globl _int11_handler
+_int11_handler:
+       mov     $0x22, %ax
+       iret
+       
+       .globl _int12_handler
+_int12_handler:
+       mov     $640, %ax
+       iret
+       
+       .globl _int13_handler
+_int13_handler:
+       clc
+       mov     $0, %ah
+       iret
+
+       .globl _int14_handler
+_int14_handler:
+       iret
+
+       .globl _int15_handler
+_int15_handler:
+       cmp     $0xe801,%ax
+       jz      _int15_008
+       cmp     $0x0, %ah
+       jz      _int15_000
+       cmp     $0x1, %ah
+       jz      _int15_000
+       cmp     $0x2, %ah
+       jz      _int15_000
+       cmp     $0x3, %ah
+       jz      _int15_000
+       cmp     $0xf, %ah
+       jz      _int15_000
+       cmp     $0x21, %ah
+       jz      _int15_000
+       cmp     $0x40, %ah
+       jz      _int15_000
+       cmp     $0x41, %ah
+       jz      _int15_000
+       cmp     $0x42, %ah
+       jz      _int15_000
+       cmp     $0x43, %ah
+       jz      _int15_000
+       cmp     $0x44, %ah
+       jz      _int15_000
+       cmp     $0x80, %ah
+       jz      _int15_001
+       cmp     $0x81, %ah
+       jz      _int15_001
+       cmp     $0x82, %ah
+       jz      _int15_002
+       cmp     $0x83, %ah
+       jz      _int15_003
+       cmp     $0x84, %ah
+       jz      _int15_000
+       cmp     $0x85, %ah
+       jz      _int15_004
+       cmp     $0x86, %ah
+       jz      _int15_003
+       cmp     $0x87, %ah
+       jz      _int15_005
+       cmp     $0x88, %ah
+       jz      _int15_006
+       cmp     $0x89, %ah
+       jz      _int15_005
+       cmp     $0x90, %ah
+       jz      _int15_007
+       cmp     $0xc0, %ah
+       jz      _int15_000
+       cmp     $0xc1, %ah
+       jz      _int15_000
+       cmp     $0xc2, %ah
+       jz      _int15_000
+       cmp     $0xc3, %ah
+       jz      _int15_000
+       cmp     $0xc4, %ah
+       jz      _int15_000
+       iret
+
+_int15_000:
+       mov     $0x86, %ah
+       stc
+       iret
+
+_int15_001:
+       mov     $0, %bx
+       mov     $0, %cx
+       iret
+
+_int15_002:
+       mov     $0, %bx
+       iret
+
+_int15_003:
+       clc
+       iret
+
+_int15_004:
+       mov     $0, %al
+       iret
+
+_int15_005:
+       mov     $0, %ah
+       clc
+       cmp     $0, %ah
+       iret
+
+_int15_006:
+       mov     $0xf000, %ax
+       iret
+
+_int15_007:
+       stc
+       iret
+
+_int15_008:
+       clc
+       mov     $1024, %dx      /* dx -> extended memory size (in 64K chuncks) */
+       mov     $640, %cx       /* cx -> conventional memory size (in 1 Kbytes chuncks) */
+       iret
+
+       .globl _int16_handler
+_int16_handler:
+       cmp     $0x0, %ah
+       jnz     _int16_01
+       mov     $0x20, %al
+       mov     $0x39, %ah
+       iret
+_int16_01:
+       cmp     $0x1, %ah
+       jnz     _int16_02
+       iret
+_int16_02:
+       cmp     $0x2, %ah
+       jnz     _int16_05
+       mov     $0, %al
+       iret
+_int16_05:
+       cmp     $0x5, %ah
+       jnz     _int16_10
+       mov     $0, %al
+       iret
+_int16_10:
+       cmp     $0x10, %ah
+       jnz     _int16_11
+       mov     $0x20, %al
+       mov     $0x39, %ah
+       iret
+_int16_11:
+       cmp     $0x11, %ah
+       jnz     _int16_12
+       iret
+_int16_12:
+       cmp     $0x12, %ah
+       jnz     _int16_XX
+       mov $0, %ax
+       iret
+_int16_XX:
+       iret
+
+       .globl _int17_handler
+_int17_handler:
+       mov $0xd0, %ah
+       iret
+
+       .globl _int19_handler
+_int19_handler:
+       hlt
+       iret
+
+       .globl _int1A_handler
+_int1A_handler:
+       stc
+       iret
+
+       .code32
+       .globl  xstart
+xstart:
+       /* reprogram the PICs so that interrupt are masked */
+        movb    $0x11,%al      /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
+       outb    %al,$0x20
+        movb    $PIC1_VBS, %al
+       outb    %al,$0x21
+        movb    $0x4,%al
+       outb    %al,$0x21
+        movb    $0x1,%al
+       outb    %al,$0x21
+        movb    $0xff,%al
+       outb    %al,$0x21
+       
+        movb    $0x11,%al      /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
+       outb    %al,$0xa0
+        movb    $PIC2_VBS, %al
+       outb    %al,$0xa1
+        movb    $0x2,%al
+       outb    %al,$0xa1
+        movb    $0x1,%al
+       outb    %al,$0xa1
+        movb    $0xff,%al
+       outb    %al,$0xa1
+
+       pushl   %ebp
+       movl    %esp,%ebp
+       pushl   %ebx
+       pushl   %esi
+       pushl   %edi
+       movl    8(%ebp),%eax
+       movl    %eax,_execaddr
+       movl    12(%ebp),%ebx
+       movl    16(%ebp),%ecx   /* bootp record (32bit pointer) */
+       addl    $28,%ecx        /* ip, udp header */
+       shll    $12,%ecx
+       shrw    $12,%cx
+       call    _prot_to_real
+       .code16
+/* MP: add int10 handler */
+       push    %eax
+       push    %ebx
+       push    %es
+       mov     $0,%ax
+       mov     %ax,%es
+       mov     %cs,%ax
+       shl     $16,%eax
+
+       ADDR32 mov      $(_int08_handler-_start),%ax
+       mov     $0x20,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int10_handler-_start),%ax
+       mov     $0x40,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int11_handler-_start),%ax
+       mov     $0x44,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int12_handler-_start),%ax
+       mov     $0x48,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int13_handler-_start),%ax
+       mov     $0x4c,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int14_handler-_start),%ax
+       mov     $0x50,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int15_handler-_start),%ax
+       mov     $0x54,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int16_handler-_start),%ax
+       mov     $0x58,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int17_handler-_start),%ax
+       mov     $0x5c,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int19_handler-_start),%ax
+       mov     $0x64,%ebx
+       mov     %eax,%es:(%bx)
+
+       ADDR32 mov      $(_int1A_handler-_start),%ax
+       mov     $0x68,%ebx
+       mov     %eax,%es:(%bx)
+
+       pop     %es
+       pop     %ebx
+       pop     %eax
+/* */
+       pushl   %ecx            /* bootp record */
+       pushl   %ebx            /* file header */
+       movl    $((RELOC<<12)+(1f-RELOC)),%eax
+       pushl   %eax
+       ADDR32  LJMPI(_execaddr-_start)
+1:
+       addw    $8,%sp          /* XXX or is this 10 in case of a 16bit "ret" */
+       DATA32 call     _real_to_prot
+       .code32
+       popl    %edi
+       popl    %esi
+       popl    %ebx
+       popl    %ebp
+       ret
+
+_execaddr:
+       .long   0
+
+#ifdef IMAGE_MULTIBOOT
+/**************************************************************************
+XEND - Restart Etherboot from the beginning (from protected mode)
+**************************************************************************/
+
+       .globl  xend
+xend:
+       cs
+       lidt    idtarg_realmode-_start+RELOC
+       cs
+       lgdt    gdtarg-_start+RELOC
+#ifdef GAS291
+       ljmp    $REAL_CODE_SEG,$1f-RELOC        /* jump to a 16 bit segment */
+#else
+       ljmp    $REAL_CODE_SEG,$1f-_start       /* jump to a 16 bit segment */
+#endif /* GAS291 */
+1:
+       .code16
+       movw    $REAL_DATA_SEG,%ax
+       movw    %ax,%ds
+       movw    %ax,%ss
+       movw    %ax,%es
+
+       /* clear the PE bit of CR0 */
+       movl    %cr0,%eax
+       andl    $0!CR0_PE,%eax
+       movl    %eax,%cr0
+
+       /* make intersegment jmp to flush the processor pipeline
+        * and reload %cs:%eip (to clear upper 16 bits of %eip).
+        */
+       DATA32 ljmp     $(RELOC)>>4,$2f-_start
+2:
+       /* we are in real mode now
+        * set up the real mode segment registers : %ds, %ss, %es
+        */
+       movw    %cs,%ax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+       xorl    %esp,%esp
+       ADDR32 movw     initsp-RELOC,%sp
+
+       movw    $0,%ax
+       movw    %ax,%fs
+       movw    %ax,%gs
+
+       sti
+       jmp     _start
+
+       .code32
+#endif /* IMAGE_MULTIBOOT */
+
+.global get_cs
+get_cs:
+       xorl    %eax,%eax
+       movw    %cs,%ax
+       ret
+
+.global get_ds
+get_ds:
+       xorl    %eax,%eax
+       movw    %ds,%ax
+       ret
+
+.global getsp
+getsp:
+       movl    %esp,%eax       /* GET STACK POINTER */
+       subl    $4, %eax        /* ACCOUNT FOR RETURN ADDRESS ON */
+       ret
+
+.global get_gdtbase
+get_gdtbase:
+       sub     $8,%esp                 /* ALLOCATE ROOM ON THE STACK */
+       sgdt    (%esp,1)                /*STORE IGDT REGISTER ON STACK */
+       mov     2(%esp),%eax            /* READ GDT BASE ADDRESS */
+       mov     $KERN_DATA_SEG,%dx      /* ASSUME UNIVERSAL DS. */
+       add     $8,%esp                 /* RESTORE STACK */
+       ret                             /* DONE */
+
+.global get_gdtsize
+get_gdtsize:
+       sub     $8,%esp /* ALLOCATE ROOM ON THE STACK */
+       sgdt    (%esp,1)        /*STORE IGDT REGISTER ON STACK */
+       xor     %eax,%eax
+       mov     2(%esp),%eax    /* READ GDT BASE ADDRESS */
+       mov     (%ESP),%ax
+       shr     $3,%ax
+       add     $8,%esp /* RESTORE STACK */
+       ret                     /* DONE */
+
+.global get_idtbase
+get_idtbase:
+       sub     $8,%esp
+       sidt   (%esp,1)         /* STORE IIDT REGISTER ON STACK */
+       mov     2(%esp),%eax
+       mov     $KERN_DATA_SEG,%dx
+       add     $8,%esp
+       ret
+
+.global get_lw
+get_lw:
+       xor     %edx,%edx
+       mov     8(%esp),%eax
+       mov     4(%esp),%dx
+       ret
+        
+/**************************************************************************
+SETJMP - Save stack context for non-local goto
+**************************************************************************/
+       .globl  setjmp
+setjmp:
+       mov     4(%esp),%ecx
+       mov     0(%esp),%edx
+       mov     %edx,0(%ecx)
+       mov     %ebx,4(%ecx)
+       mov     %esp,8(%ecx)
+       mov     %ebp,12(%ecx)
+       mov     %esi,16(%ecx)
+       mov     %edi,20(%ecx)
+       mov     %eax,24(%ecx)
+       mov     $0,%eax
+       ret
+
+/**************************************************************************
+LONGJMP - Non-local jump to a saved stack context
+**************************************************************************/
+       .globl  longjmp
+longjmp:
+       mov     4(%esp),%edx
+       mov     8(%esp),%eax
+       mov     0(%edx),%ecx
+       mov     4(%edx),%ebx
+       mov     8(%edx),%esp
+       mov     12(%edx),%ebp
+       mov     16(%edx),%esi
+       mov     20(%edx),%edi
+       cmp     $0,%eax
+       jne     1f
+       mov     $1,%eax
+1:     mov     %ecx,0(%esp)
+       ret
+
+/**************************************************************************
+_REAL_TO_PROT - Go from REAL mode to Protected Mode
+**************************************************************************/
+       .globl  _real_to_prot
+_real_to_prot:
+       .code16
+       cli
+       cs
+       ADDR32 lgdt     gdtarg-_start
+       movl    %cr0,%eax
+       orl     $CR0_PE,%eax
+       movl    %eax,%cr0               /* turn on protected mode */
+
+       /* flush prefetch queue, and reload %cs:%eip */
+       DATA32 ljmp     $KERN_CODE_SEG,$1f
+1:
+       .code32
+       /* reload other segment registers */
+       movl    $KERN_DATA_SEG,%eax
+       movl    %eax,%ds
+       movl    %eax,%es
+       movl    %eax,%ss
+       addl    $RELOC,%esp             /* Fix up stack pointer */
+       xorl    %eax,%eax
+       movl    %eax,%fs
+       movl    %eax,%gs
+       popl    %eax                    /* Fix up return address */
+       addl    $RELOC,%eax
+       pushl   %eax
+       ret
+
+/**************************************************************************
+_PROT_TO_REAL - Go from Protected Mode to REAL Mode
+**************************************************************************/
+       .globl  _prot_to_real
+_prot_to_real:
+       .code32
+       popl    %eax
+       subl    $RELOC,%eax             /* Adjust return address */
+       pushl   %eax
+       subl    $RELOC,%esp             /* Adjust stack pointer */
+#ifdef GAS291
+       ljmp    $REAL_CODE_SEG,$1f-RELOC        /* jump to a 16 bit segment */
+#else
+       ljmp    $REAL_CODE_SEG,$1f-_start       /* jump to a 16 bit segment */
+#endif /* GAS291 */
+1:
+       .code16
+       movw    $REAL_DATA_SEG,%ax
+       movw    %ax,%ds
+       movw    %ax,%ss
+       movw    %ax,%es
+       movw    %ax,%fs
+       movw    %ax,%gs
+       cli
+
+       /* clear the PE bit of CR0 */
+       movl    %cr0,%eax
+       andl    $0!CR0_PE,%eax
+       movl    %eax,%cr0
+
+       /* make intersegment jmp to flush the processor pipeline
+        * and reload %cs:%eip (to clear upper 16 bits of %eip).
+        */
+       DATA32 ljmp     $(RELOC)>>4,$2f-_start
+2:
+       /* we are in real mode now
+        * set up the real mode segment registers : %ds, $ss, %es
+        */
+       movw    %cs,%ax
+       movw    %ax,%ds
+       movw    %ax,%es
+       movw    %ax,%ss
+#if 0
+       sti
+#endif
+       DATA32 ret      /* There is a 32 bit return address on the stack */
+       .code32
+
+/**************************************************************************
+GLOBAL DESCRIPTOR TABLE
+**************************************************************************/
+       .align  4
+Idt_Reg:
+       .word 0x3ff
+       .long 0
+
+       .align  4
+_gdt:
+gdtarg:
+Gdt_Table:
+       .word   0x27                    /* limit */
+       .long   _gdt                    /* addr */
+       .word   0
+_pmcs:
+       /* 32 bit protected mode code segment */
+       .word   0xffff,0
+       .byte   0,0x9f,0xcf,0
+
+_pmds:
+       /* 32 bit protected mode data segment */
+       .word   0xffff,0
+       .byte   0,0x93,0xcf,0
+
+_rmcs:
+       /* 16 bit real mode code segment */
+       .word   0xffff,(RELOC&0xffff)
+       .byte   (RELOC>>16),0x9b,0x00,(RELOC>>24)
+
+_rmds:
+       /* 16 bit real mode data segment */
+       .word   0xffff,(RELOC&0xffff)
+       .byte   (RELOC>>16),0x93,0x00,(RELOC>>24)
+
+       .align  4
+RUN_GDT:                       /* POINTER TO GDT IN RAM */
+        .byte   0x7f,0         /* [BSP_GDT_NUM*8]-1 */
+        .long   Gdt_Table
+
+       .align  4
+
+       .section ".rodata"
+err_not386:
+       .ascii  "Etherboot/32 requires 386+"
+       .byte   0x0d, 0x0a
+err_not386_end:
+
+days:  .long   0
+irq_num: .long
+
+        .data
+       .align  4
+        .org 2048
+.global stktop
+stktop:
+       .long
+
+.section ".armando"
+/* Â  Â   Â  Â  Â  Â  Â  Â 1:::::::::2:::::::::3:::::::3 */
+/* Â  Â  Â  Â 12345678901234567890123456789012345678 */
+/* Â  Â  Â  v----+----v----+----v----+----v----+--- */
+
+.global EtherbootString
+EtherbootString:
+.ascii "EtherBoot MPCC  "      /* fw identifier */
+
+.byte  0, 0            /* mandatory hole */
+
+.long  _start          /* entry point */
+.word  0
+.byte  'E'             /* type */
+.byte  0               /* selector */
+.word  0               /* CRC */
diff --git a/contrib/bin2intelhex/Makefile b/contrib/bin2intelhex/Makefile
new file mode 100644 (file)
index 0000000..7406968
--- /dev/null
@@ -0,0 +1,9 @@
+
+CC=gcc
+CFLAGS=-Wall -O2
+
+bin2intelhex:
+
+
+clean:
+       rm -f bin2intelhex core *.o
diff --git a/contrib/bin2intelhex/bin2intelhex.c b/contrib/bin2intelhex/bin2intelhex.c
new file mode 100644 (file)
index 0000000..75b88c1
--- /dev/null
@@ -0,0 +1,148 @@
+/* name : bin2intelhex.c
+ * from : Jean Marc Lacroix <jeanmarc.lacroix@free.fr>
+ * date : 06/12/1997.
+ * abstract : Y have rewrite this program from ????? with some modifications
+ * to add :
+ * - the Intel specification.
+ * - correct a bug because my prom programmer don't understand the
+ * initial format. Y suspect a bug in the calcul of the lrc
+ * in the original program.
+ * - correct the format of printf . In the original program, it was
+ *   %x, and it is in fact %X, because in the Intel Format, all the
+ * char are in upper case.
+ * - correct the lrc calculation.
+ * usage:
+ *-------
+ * this program read the standard input and put to the standard output
+ * the result of the conversion.
+ * an example of use :
+ * cat my_bin | bin2intelhex > my_bin.hex or.....
+ * bin2intelhex < my_bin > my_bin.hex
+ */
+
+
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2005/05/17 16:45:06  mcb30
+ * Initial revision
+ *
+ * Revision 1.9  1997/12/14 05:14:54  install
+ * - some documentation....
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Intel Hex format specifications
+
+The 8-bit Intel Hex File Format is a printable ASCII format consisting of one
+ or more data records followed by an end of file record. Each
+record consists of one line of information. Data records may appear in any
+ order. Address and data values are represented as 2 or 4 hexadecimal
+digit values. 
+
+Record Format 
+:LLAAAARRDDDD......DDDDCC 
+
+
+LL
+AAAA
+RR
+DD
+CC
+Length field. Number of data bytes.
+Address field. Address of first byte.
+Record type field. 00 for data and 01 for end of record.
+Data field.
+Checksum field. One's complement of length, address, record type and data
+ fields modulo 256. 
+CC = LL + AAAA + RR + all DD = 0
+
+Example: 
+:06010000010203040506E4 
+:00000001FF 
+
+The first line in the above example Intel Hex file is a data record addressed
+ at location 100H with data values 1 to 6. The second line is the end
+of file record, so that the LL field is 0
+
+*/
+
+
+typedef unsigned char t_u8;
+typedef unsigned short t_u16;
+/*
+ * the choice for the total length (16) of a line, but the specification
+ * can support an another value
+ */
+#define LL_MAX_LINE 16
+typedef struct 
+{ 
+  t_u8 intel_lg_data;
+  t_u16 intel_adr;
+  t_u8 intel_type;
+  t_u8 intel_data [LL_MAX_LINE];
+  t_u8 intel_lrc;
+} t_one_line;
+#define INTEL_DATA_TYPE 0
+#define EXIT_OK 0
+int main (const int argc, const char ** const argv)
+{
+  t_one_line line;
+  /*
+   * init for the adress, please note that it is assume that the program begin at 0
+   */
+  line.intel_adr = 0;
+  line.intel_type = INTEL_DATA_TYPE;
+  /*
+   * read the data on the standard input
+   */
+  while ((line.intel_lg_data = read (0, &line.intel_data [0] ,LL_MAX_LINE )) > 0) 
+    {
+      t_u8 i; 
+      /*
+       * and now for this line, calculate the lrc.
+       */
+      line.intel_lrc = line.intel_lg_data;
+      line.intel_lrc += ((line.intel_adr >> 8) & 0xff);
+      line.intel_lrc += (line.intel_adr &0xff);
+      line.intel_lrc += line.intel_type;
+      /*
+       * the structure is ready, print it to stdout in the
+       * right format
+       */
+      (void) printf (":%02X%04X%02X",
+                    line.intel_lg_data,
+                    line.intel_adr,
+                    line.intel_type);
+      /*
+       * edit all the data read
+       */
+      for (i=0; i<line.intel_lg_data; i++)
+       {
+         (void) printf ("%02X",
+                        (line.intel_data [i] & 0xff));   
+         /*
+          * add to the lrc the data print
+          */
+         line.intel_lrc +=line.intel_data [i];
+       }
+      /*
+       * edit the value of the lrc and new line for the next
+       */
+      (void) printf ("%02X\n",
+                        (0x100 - line.intel_lrc) & 0xff);
+      /* 
+       * prepare the new adress for the next line
+       */
+      line.intel_adr+=line.intel_lg_data;     
+    }
+  /*
+   * print the last line with a length of 0 data, so that the lrc is easy to
+   * calculate (ff+01 =0)
+   */
+  printf (":00000001FF\n");
+  exit (EXIT_OK); 
+}
diff --git a/contrib/bin2intelhex/bin2intelhex.c.simple b/contrib/bin2intelhex/bin2intelhex.c.simple
new file mode 100644 (file)
index 0000000..3cb279a
--- /dev/null
@@ -0,0 +1,74 @@
+/* 
+
+  Quick and dirty program to make intel-hex from a binary.
+
+  Written by R.E.Wolff@BitWizard.nl
+  This file is in the public domain
+
+  Typing started:
+
+  Mon Jun 16 00:24:15 MET DST 1997
+
+  programming stopped:
+
+  Mon Jun 16 00:31:27 MET DST 1997
+
+  debugging finished (2 bugs found):
+  Mon Jun 16 00:32:52 MET DST 1997
+
+--------------------------------------------------------- 
+
+  Doc written in timeout. Everything else in this file was done while
+  the timer was running.
+
+  I promised "Mark Kopecki" that writing the bin-to-intel-hex
+  converter would cost less than 15 minutes, and that it would be more
+  trouble to find a converter on the net than to write the converter
+  myself.  I ended up spending over half an hour searching for
+  spec/converter/docs because of unreachable hosts on the internet. I
+  got a file with docs, after that it was 8 minutes.....
+
+--------------------------------------------------------- 
+
+*/
+
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Intel Hex format:
+   
+   ll aaaa tt dd....dd cc
+   ll = length
+   aaaa = address
+   tt = type
+   dd....dd = data
+   cc = checksum.
+*/
+
+
+int main (int argc, char **argv)
+{
+  unsigned char buf[32];
+  int addr = 0;
+  int n,i;
+
+  while ((n = read (0, buf+4, 16)) > 0) {
+    buf[0] = n;
+    buf[1] = addr >> 8;
+    buf[2] = addr & 0xff;
+    buf[3] = 0x00;
+    buf[4+n] = 0x00;
+
+    for (i=0;i<4+n;i++)
+      buf[4+n] -= buf[i];
+    printf (":");
+    for (i=0;i<= 4+n;i++)
+      printf ("%02x", buf[i]);
+    printf ("\n");
+    addr += n;
+  }
+  printf (":0000000001ff\n");
+  exit (0);
+}
diff --git a/contrib/bochs/.cvsignore b/contrib/bochs/.cvsignore
new file mode 100644 (file)
index 0000000..baadb8c
--- /dev/null
@@ -0,0 +1,5 @@
+bochsout.txt
+parport.out
+ne2k-tx.log
+ne2k-txdump.txt
+
diff --git a/contrib/bochs/Makefile b/contrib/bochs/Makefile
new file mode 100644 (file)
index 0000000..3c0e645
--- /dev/null
@@ -0,0 +1,7 @@
+all : serial-console.1
+
+%.1 : %
+       pod2man $< > $@
+
+clean :
+       rm -f serial-console.1
diff --git a/contrib/bochs/README b/contrib/bochs/README
new file mode 100644 (file)
index 0000000..80e1529
--- /dev/null
@@ -0,0 +1,121 @@
+Running Etherboot within Bochs
+==============================
+
+Michael Brown <mbrown@fensystems.co.uk>
+Based on an idea suggested by H. Peter Anvin <hpa@zytor.com>.
+
+$Id$
+
+Bochs is a program that simulates a complete Intel x86 computer,
+including hardware.  It can be used to test Etherboot.  There is a
+special pseudo NIC ("pnic") implemented in Bochs, with a corresponding
+driver in Etherboot.  (There is also an NE2000 ISA driver in Bochs,
+but it doesn't seem to quite work.)
+
+To get bochs running is fairly simple:
+
+1.  Get the bochs source code:
+    a)  cvs -d:pserver:anonymous:@cvs.sourceforge.net:/cvsroot/bochs login
+    b)  cvs -d:pserver:anonymous:@cvs.sourceforge.net:/cvsroot/bochs co bochs
+
+2.  Configure bochs with
+      ./configure --enable-all-optimisations --enable-pci \
+                --enable-ne2000 --enable-pnic
+    Other potentially useful configure options:
+      --prefix=/usr
+          to force use of standard file locations
+      --enable-debugger
+          to enable the internal debugger
+
+3.  Build bochs:
+      make
+
+4.  Configure Etherboot with CONFIG_PCI_DIRECT: add the line
+      CFLAGS += -DCONFIG_PCI_DIRECT
+    to the end of src/arch/i386/Config.
+
+5.  Build bin/pnic.zrom:
+      make bin/pnic.zrom
+
+6.  Load the TUN/TAP kernel module:
+      modprobe tun
+    You should see the device /dev/net/tun is created automatically if
+    you're using devfs, otherwise you may have to create it by hand with:
+      mknod /dev/net/tun c 10 200
+
+7.  Grant yourself write access to /dev/net/tun:
+      su -c 'chown <your user id> /dev/net/tun'
+    The alternative to this is to run Bochs as root.  Don't do that.
+
+8.  Add the following fragment to /etc/dhcpd.conf:
+      subnet 10.254.254.0 netmask 255.255.255.252 {
+        range dynamic-bootp 10.254.254.1 10.254.254.1;
+      }
+    You will also need to add in any of your usual declarations for
+    Etherboot, e.g. 'filename "vmlinuz.ltsp";'.  Note that this setup
+    assumes that your DHCP server, TFTP server etc. all live on the
+    machine you are using for running Bochs.  If not, then you're on
+    your own.
+
+9.  Change back to this directory and run bochs from your Bochs source tree:
+      cd /path/to/Etherboot/contrib/bochs
+      /path/to/bochs/source/tree/bochs
+
+10. Select option 5 (Begin simulation).  You will be prompted for your
+    root password.  This is required in order to configure the tun1
+    network interface and to restart the DHCP server.
+
+11. You should see Bochs start up and attempt to boot from the network,
+    with a screen that looks like:
+
+VGA BIOS - Version 2.40
+Copyright (C) 1990-2000 Elpin Systems, Inc.
+All rights reserved.
+
+Licensed for use with bochs, courtesy of MandrakeSoft.
+
+For information on this or other VGA development products, contact
+Elpin Systems at: (800) 723-9038 or www.elpin.com
+
+Bochs BIOS, 1 cpu, $Revision$ $Date$
+
+
+Etherboot 5.3.6 (GPL) http://etherboot.org Tagged ELF for [PNIC]
+Relocating _text from: [00091020,0009fb50) to [01ef14d0,01f00000)
+Boot from (N)etwork or (Q)uit?
+
+Probing pci nic...
+[pnic] - Detected Bochs Pseudo NIC MAC FE:FD:00:00:00:01 (API v1.0) at 0xdc00
+Searching for server (DHCP)...
+..Me: 10.254.254.1, Server: 10.254.254.2
+Loading 10.254.254.2:/tftpboot/kernel
+
+
+
+
+Serial console
+==============
+
+You can use the program "serial-console" to obtain a virtual serial
+console for Etherboot running within Bochs.  Simply run
+"./serial-console" on a spare tty (e.g. a separate xterm window)
+before starting Bochs, and ensure that you have compiled Etherboot
+with appropriate settings such as
+  CFLAGS+=      -DCONSOLE_DUAL -DCOMCONSOLE=0x3F8 -DCONSPEED=9600
+
+There is a manual page for "serial-console"; use
+"man ./serial-console.1" to view it.
+
+
+
+TODO
+====
+
+Packet forwarding/masquerading - document what must be set up.
+
+Mention possibility of using RFB as the display device - in
+conjunction with the serial console, gives you a test facility that
+can be accessed remotely.
+
+Mention use of BOCHSBP instruction (xchgw %bx,%bx) to avoid need to
+calculate breakpoints.
diff --git a/contrib/bochs/bochsrc.txt b/contrib/bochs/bochsrc.txt
new file mode 100644 (file)
index 0000000..d7ba043
--- /dev/null
@@ -0,0 +1,658 @@
+# You many now use double quotes around pathnames, in case
+# your pathname includes spaces.
+
+#=======================================================================
+# CONFIG_INTERFACE
+#
+# The configuration interface is a series of menus or dialog boxes that
+# allows you to change all the settings that control Bochs's behavior.
+# There are two choices of configuration interface: a text mode version
+# called "textconfig" and a graphical version called "wx".  The text
+# mode version uses stdin/stdout and is always compiled in.  The graphical
+# version is only available when you use "--with-wx" on the configure 
+# command.  If you do not write a config_interface line, Bochs will 
+# choose a default for you.
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#=======================================================================
+#config_interface: textconfig
+#config_interface: wx
+
+#=======================================================================
+# DISPLAY_LIBRARY
+#
+# The display library is the code that displays the Bochs VGA screen.  Bochs 
+# has a selection of about 10 different display library implementations for 
+# different platforms.  If you run configure with multiple --with-* options, 
+# the display_library command lets you choose which one you want to run with.
+# If you do not write a display_library line, Bochs will choose a default for
+# you.
+#
+# The choices are: 
+#   x              use X windows interface, cross platform
+#   win32          use native win32 libraries
+#   carbon         use Carbon library (for MacOS X)
+#   beos           use native BeOS libraries
+#   macintosh      use MacOS pre-10
+#   amigaos        use native AmigaOS libraries
+#   sdl            use SDL library, cross platform
+#   svga           use SVGALIB library for Linux, allows graphics without X11
+#   term           text only, uses curses/ncurses library, cross platform
+#   rfb            provides an interface to AT&T's VNC viewer, cross platform
+#   wx             use wxWindows library, cross platform
+#   nogui          no display at all
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#=======================================================================
+#display_library: amigaos
+#display_library: beos
+#display_library: carbon
+#display_library: macintosh
+#display_library: nogui
+#display_library: rfb
+#display_library: sdl
+#display_library: term
+#display_library: win32
+#display_library: wx
+#display_library: x
+
+#=======================================================================
+# ROMIMAGE:
+# You now need to load a ROM BIOS into F0000-FFFFF.  I've wiped
+# out most of the BIOS hooks, and replace them with real BIOS
+# support.  Normally, you can use a precompiled BIOS in the bios/
+# directory, named BIOS-bochs-latest. 
+#=======================================================================
+#romimage: bios/BIOS-bochs-970717a
+#romimage: file=bios/BIOS-bochs-latest, address=0xf0000
+romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000
+#romimage: file=bios/BIOS-bochs-2-processors, address=0xf0000
+#romimage: file=bios/BIOS-bochs-4-processors, address=0xf0000
+#romimage: file=bios/rombios.bin, address=0xf0000
+
+#=======================================================================
+# MEGS
+# set this to the default number of Megabytes of memory you want
+# to emulate.  You may also pass the '-megs xyz' option to bochs
+#
+# The default is 32MB, most OS's won't need more than that. 
+#=======================================================================
+#megs: 256
+#megs: 128
+#megs: 64
+megs: 32
+#megs: 16
+#megs: 8
+
+#=======================================================================
+# OPTROMIMAGE[1-4]:
+# You may now load up to 4 optional ROM images. Be sure to use a 
+# read-only area, typically between C8000 and EFFFF. These optional
+# ROM images should not overwrite the rombios (located at
+# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
+# Those ROM images will be initialized by the bios if they contain 
+# the right signature (0x55AA).
+# It can also be a convenient way to upload some arbitary code/data
+# in the simulation, that can be retrieved by the boot loader
+#=======================================================================
+#optromimage1: file=optionalrom.bin, address=0xd0000
+#optromimage2: file=optionalrom.bin, address=0xd1000
+#optromimage3: file=optionalrom.bin, address=0xd2000
+#optromimage4: file=optionalrom.bin, address=0xd3000
+#optromimage1: file=../../src/bin/ne.zrom, address=0xd0000
+optromimage1: file=../../src/bin/pnic.zrom, address=0xd0000
+
+#=======================================================================
+# VGAROMIMAGE
+# You now need to load a VGA ROM BIOS into C0000.
+#=======================================================================
+#vgaromimage: bios/VGABIOS-lgpl-latest
+#vgaromimage: bios/VGABIOS-elpin-2.40
+vgaromimage: $BXSHARE/VGABIOS-elpin-2.40
+
+#=======================================================================
+# FLOPPYA:
+# Point this to pathname of floppy image file or device
+# This should be of a bootable floppy(image/device) if you're 
+# booting from 'a'.
+#
+# You can set the initial status of the media to 'ejected' or 'inserted'.
+#   floppya: 2_88=path, status=ejected             (2.88M 3.5" floppy)
+#   floppya: 1_44=path, status=inserted            (1.44M 3.5" floppy)
+#   floppya: 1_2=path, status=ejected              (1.2M  5.25" floppy)
+#   floppya: 720k=path, status=inserted            (720K  3.5" floppy)
+#   floppya: 360k=path, status=inserted            (360K  5.25" floppy)
+#
+# The path should be the name of a disk image file.  On unix, you can use
+# a raw device name such as /dev/fd0 on Linux.  On WinNT and Win2k, use
+# drive letters such as a: or b: as the path.  Raw floppy access is not
+# supported on Windows 95 and 98.
+#=======================================================================
+floppya: 1_44=/dev/fd0, status=inserted
+#floppya: file=../1.44, status=inserted
+#floppya: 1_44=/dev/fd0H1440, status=inserted
+#floppya: 1_2=../1_2, status=inserted
+#floppya: 1_44=a:, status=inserted
+#floppya: 1_44=a.img, status=inserted
+
+#=======================================================================
+# FLOPPYB:
+# See FLOPPYA above for syntax
+#=======================================================================
+#floppyb: 1_44=b:, status=inserted
+floppyb: 1_44=b.img, status=inserted
+
+#=======================================================================
+# ATA0, ATA1, ATA2, ATA3
+# ATA controller for hard disks and cdroms
+#
+# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
+# 
+# These options enables up to 4 ata channels. For each channel
+# the two base io address and the irq must be specified.
+# 
+# ata0 is enabled by default, with ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+#
+# Examples:
+#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=11
+#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x368, irq=9
+#=======================================================================
+ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
+ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=11
+ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x368, irq=9
+
+#=======================================================================
+# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
+#
+# This defines the type and characteristics of all attached ata devices:
+#   type=       type of attached device [disk|cdrom] 
+#   path=       path of the image
+#   cylinders=  only valid for disks
+#   heads=      only valid for disks
+#   spt=        only valid for disks
+#   status=     only valid for cdroms [inserted|ejected]
+#   biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
+#   translation=type of transation of the bios, only for disks [none|lba|large|rechs|auto]
+#   model=      string returned by identify device command
+#   
+# Point this at a hard disk image file, cdrom iso file, or physical cdrom
+# device.  To create a hard disk image, try running bximage.  It will help you
+# choose the size and then suggest a line that works with it.
+#
+# In UNIX it may be possible to use a raw device as a Bochs hard disk, 
+# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
+#
+# In windows, the drive letter + colon notation should be used for cdroms.
+# Depending on versions of windows and drivers, you may only be able to 
+# access the "first" cdrom in the system.  On MacOSX, use path="drive"
+# to access the physical drive.
+#
+# The path, cylinders, heads, and spt are mandatory for type=disk
+# The path is mandatory for type=cdrom
+#
+# Default values are:
+#   biosdetect=auto, translation=auto, model="Generic 1234"
+#
+# The biosdetect option has currently no effect on the bios
+#
+# Examples:
+#   ata0-master: type=disk, path=10M.sample, cylinders=306, heads=4, spt=17
+#   ata0-slave:  type=disk, path=20M.sample, cylinders=615, heads=4, spt=17
+#   ata1-master: type=disk, path=30M.sample, cylinders=615, heads=6, spt=17
+#   ata1-slave:  type=disk, path=46M.sample, cylinders=940, heads=6, spt=17
+#   ata2-master: type=disk, path=62M.sample, cylinders=940, heads=8, spt=17
+#   ata2-slave:  type=disk, path=112M.sample, cylinders=900, heads=15, spt=17
+#   ata3-master: type=disk, path=483M.sample, cylinders=1024, heads=15, spt=63
+#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
+#=======================================================================
+#ata0-master: type=disk, path="30M.sample", cylinders=615, heads=6, spt=17
+#ata0-slave: type=cdrom, path=D:, status=inserted
+#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
+#ata0-slave: type=cdrom, path="drive", status=inserted
+
+#=======================================================================
+#
+# The DISKC option is deprecated. Use ATA* options instead.
+#
+# DISKC: file=, cyl=, heads=, spt=
+# Point this at a hard disk image file.  To create 
+# a hard disk image, try running bximage.  It will help you choose the
+# size and then suggest a diskc line that works with it.
+#
+# In UNIX it may be possible to use a raw device as a Bochs hard disk, 
+# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
+#
+# Examples:
+#   diskc: file=10M.sample, cyl=306, heads=4, spt=17
+#   diskc: file=20M.sample, cyl=615, heads=4, spt=17
+#   diskc: file=30M.sample, cyl=615, heads=6, spt=17
+#   diskc: file=46M.sample, cyl=940, heads=6, spt=17
+#   diskc: file=62M.sample, cyl=940, heads=8, spt=17
+#   diskc: file=112M.sample, cyl=900, heads=15, spt=17
+#   diskc: file=483M.sample, cyl=1024, heads=15, spt=63
+#=======================================================================
+#diskc: file="30M.sample", cyl=615, heads=6, spt=17
+
+#=======================================================================
+#
+# The DISKD option is deprecated. Use ATA* options instead.
+#
+# DISKD:
+# See DISKC above for syntax
+#
+# NOTE: diskd and cdromd must not be used together!
+#=======================================================================
+#diskd: file="diskd.img", cyl=615, heads=6, spt=17
+
+#=======================================================================
+#
+# The CDROMD option is deprecated. Use ATA* options instead.
+#
+# CDROMD:
+#
+# cdromd: dev=/dev/cdrom, status=inserted
+# cdromd: dev=/dev/cdrom, status=ejected
+# cdromd: dev=e:, status=ejected
+#
+# In windows, the drive letter + colon notation should be used for cdroms.
+# Depending on versions of windows and drivers, you may only be able to 
+# access the "first" cdrom in the system.  On MacOSX, use path="drive"
+# to access the physical drive.
+#
+# NOTE: diskd and cdromd must not be used together!
+#=======================================================================
+#cdromd: dev=D:, status=inserted
+#cdromd: dev=/dev/cdrom, status=inserted
+#cdromd: dev="drive", status=inserted
+
+#=======================================================================
+# NEWHARDDRIVESUPPORT: enabled=[0|1]
+# As of cvs version on 5/17/2001, newharddrivesupport is on by default.
+#=======================================================================
+#newharddrivesupport: enabled=1
+
+#=======================================================================
+# BOOT:
+# This defines your boot drive.  
+# You can either boot from 'floppy', 'disk' or 'cdrom'
+# legacy 'a' and 'c' are also supported
+# Examples:
+#   boot: floppy
+#   boot: disk
+#   boot: cdrom
+#   boot: c
+#   boot: a
+#=======================================================================
+#boot: floppy
+#boot: disk
+
+#=======================================================================
+# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
+# Enables or disables the 0xaa55 signature check on boot floppies
+# Defaults to disabled=0
+# Examples:
+#   floppy_bootsig_check: disabled=0
+#   floppy_bootsig_check: disabled=1
+#=======================================================================
+#floppy_bootsig_check: disabled=1
+floppy_bootsig_check: disabled=0
+
+#=======================================================================
+# LOG:
+# Give the path of the log file you'd like Bochs debug and misc. verbage
+# to be written to.  If you really don't want it, make it /dev/null. :^(
+#
+# Examples:
+#   log: ./bochs.out
+#   log: /dev/tty
+#=======================================================================
+#log: /dev/null
+log: bochsout.txt
+
+#=======================================================================
+# LOGPREFIX:
+# This handles the format of the string prepended to each log line.
+# You may use those special tokens :
+#   %t : 11 decimal digits timer tick
+#   %i : 8 hexadecimal digits of cpu0 current eip
+#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
+#   %d : 5 characters string of the device, between brackets
+# 
+# Default : %t%e%d
+# Examples:
+#   logprefix: %t-%e-@%i-%d
+#   logprefix: %i%e%d
+#=======================================================================
+#logprefix: %t%e%d
+
+#=======================================================================
+# LOG CONTROLS
+#
+# Bochs now has four severity levels for event logging.
+#   panic: cannot proceed.  If you choose to continue after a panic, 
+#          don't be surprised if you get strange behavior or crashes.
+#   error: something went wrong, but it is probably safe to continue the
+#          simulation.
+#   info: interesting or useful messages.
+#   debug: messages useful only when debugging the code.  This may
+#          spit out thousands per second.
+#
+# For events of each level, you can choose to crash, report, or ignore.
+# TODO: allow choice based on the facility: e.g. crash on panics from
+#       everything except the cdrom, and only report those.
+#
+# If you are experiencing many panics, it can be helpful to change
+# the panic action to report instead of fatal.  However, be aware
+# that anything executed after a panic is uncharted territory and can 
+# cause bochs to become unstable.  The panic is a "graceful exit," so
+# if you disable it you may get a spectacular disaster instead.
+#=======================================================================
+panic: action=ask
+error: action=report
+info: action=report
+debug: action=ignore
+
+#=======================================================================
+# DEBUGGER_LOG:
+# Give the path of the log file you'd like Bochs to log debugger output.
+# If you really don't want it, make it /dev/null or '-'. :^(
+#
+# Examples:
+#   debugger_log: ./debugger.out
+#=======================================================================
+#debugger_log: /dev/null
+#debugger_log: debugger.out
+debugger_log: -
+
+#=======================================================================
+# com1:
+# This defines a serial (COM) port. You can specify a device to use as com1.
+# This can be a real serial line, or a pty.  To use a pty (under X/Unix),
+# create two windows (xterms, usually).  One of them will run bochs, and the
+# other will act as com1. Find out the tty the com1 window using the `tty'
+# command, and use that as the `dev' parameter.  Then do `sleep 1000000' in
+# the com1 window to keep the shell from messing with things, and run bochs in
+# the other window.  Serial I/O to com1 (port 0x3f8) will all go to the other
+# window.
+#=======================================================================
+#com1: enabled=1, dev=/dev/ttyp9
+#com1: enabled=1, dev=/tmp/serial.log
+
+
+#=======================================================================
+# PARPORT1:
+# This defines a parallel (printer) port. When turned on and an output file is
+# defined the emulated printer port sends characters printed by the guest OS
+# into the output file. On some platforms a device filename can be used to
+# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
+# win32 platforms).
+#
+# Examples:
+#   parport1: enabled=1, file="parport.out"
+#   parport1: enabled=1, file="/dev/lp0"
+#   parport1: enabled=0
+#=======================================================================
+parport1: enabled=1, file="parport.out"
+
+#=======================================================================
+# SB16:
+# This defines the SB16 sound emulation. It can have several of the
+# following properties.
+# All properties are in the format sb16: property=value
+# midi: The filename is where the midi data is sent. This can be a
+#       device or just a file if you want to record the midi data.
+# midimode:
+#      0=no data
+#      1=output to device (system dependent. midi denotes the device driver)
+#      2=SMF file output, including headers
+#      3=output the midi data stream to the file (no midi headers and no
+#        delta times, just command and data bytes)
+# wave: This is the device/file where wave output is stored
+# wavemode:
+#      0=no data
+#      1=output to device (system dependent. wave denotes the device driver)
+#      2=VOC file output, incl. headers
+#      3=output the raw wave stream to the file
+# log:  The file to write the sb16 emulator messages to.
+# loglevel:
+#      0=no log
+#      1=only midi program and bank changes
+#      2=severe errors
+#      3=all errors
+#      4=all errors plus all port accesses
+#      5=all errors and port accesses plus a lot of extra info
+# dmatimer:
+#      microseconds per second for a DMA cycle.  Make it smaller to fix
+#      non-continous sound.  750000 is usually a good value.  This needs a
+#      reasonably correct setting for IPS.
+#
+# For an example look at the next line:
+#=======================================================================
+
+#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000
+
+#=======================================================================
+# VGA_UPDATE_INTERVAL:
+# Video memory is scanned for updates and screen updated every so many
+# virtual seconds.  The default is 300000, about 3Hz.  This is generally
+# plenty.  Keep in mind that you must tweak the 'ips:' directive
+# to be as close to the number of emulated instructions-per-second
+# your workstation can do, for this to be accurate.
+#
+# Examples:
+#   vga_update_interval: 250000
+#=======================================================================
+vga_update_interval: 300000
+
+# using for Winstone '98 tests
+#vga_update_interval:  100000
+
+#=======================================================================
+# KEYBOARD_SERIAL_DELAY:
+# Approximate time in microseconds that it takes one character to
+# be transfered from the keyboard to controller over the serial path.
+# Examples:
+#   keyboard_serial_delay: 200
+#=======================================================================
+keyboard_serial_delay: 250
+
+#=======================================================================
+# KEYBOARD_PASTE_DELAY:
+# Approximate time in microseconds between attempts to paste
+# characters to the keyboard controller. This leaves time for the
+# guest os to deal with the flow of characters.  The ideal setting
+# depends on how your operating system processes characters.  The
+# default of 100000 usec (.1 seconds) was chosen because it works 
+# consistently in Windows.
+#
+# If your OS is losing characters during a paste, increase the paste
+# delay until it stops losing characters.
+#
+# Examples:
+#   keyboard_paste_delay: 100000
+#=======================================================================
+keyboard_paste_delay: 100000
+
+#=======================================================================
+# FLOPPY_COMMAND_DELAY:
+# Time in microseconds to wait before completing some floppy commands
+# such as read/write/seek/etc, which normally have a delay associated.
+# I had this hardwired to 50,000 before.
+#
+# Examples:
+#   floppy_command_delay: 50000
+#=======================================================================
+floppy_command_delay: 500
+
+#=======================================================================
+# IPS:
+# Emulated Instructions Per Second.  This is the number of IPS that bochs
+# is capable of running on your machine.  Read the note in config.h
+# on how to find this.  Make sure to recompile after.
+#
+# IPS is used to calibrate many time-dependent events within the bochs 
+# simulation.  For example, changing IPS affects the frequency of VGA
+# updates, the duration of time before a key starts to autorepeat, and 
+# the measurement of BogoMips and other benchmarks.
+#
+# Examples:
+# Machine                                         Mips
+# ________________________________________________________________
+# 650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66 2 to 2.5 Mips
+# 400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3  1 to 1.8 Mips
+# 166Mhz 64bit Sparc with Solaris 2.x             approx 0.75 Mips
+# 200Mhz Pentium with Linux 2.x                   approx 0.5 Mips
+#
+#=======================================================================
+ips: 1000000
+
+#=======================================================================
+# PIT:
+# The PIT is the programmable interval timer.  It has an option that tries to
+# keep the PIT in sync with real time.  This feature is still experimental,
+# but it may be useful if you want to prevent Bochs from running too fast, for
+# example a DOS video game.  Be aware that with the realtime pit option, your
+# simulation will not be repeatable; this can a problem if you are debugging.
+#=======================================================================
+#pit: realtime=1
+
+#=======================================================================
+# mouse: Not used in any of the GUI specific modules, but the option
+#        bx_options.mouse_enabled is set to this value.  The idea,
+#        is that the GUI code should not generate mouse events when
+#        not enabled.  The hardware emualation itself is not disabled
+#        by this.  This is to facilitate deterministic runs of bochs.
+#
+# Examples:
+#   mouse: enabled=1
+#   mouse: enabled=0
+#
+# I wouldn't recommend enabling the mouse by default, unless you have a
+# really good reason to do so.
+#=======================================================================
+mouse: enabled=0
+
+#=======================================================================
+# private_colormap: Request that the GUI create and use it's own
+#                   non-shared colormap.  This colormap will be used
+#                   when in the bochs window.  If not enabled, a
+#                   shared colormap scheme may be used.  Not implemented
+#                   on all GUI's.
+#
+# Examples:
+#   private_colormap: enabled=1
+#   private_colormap: enabled=0
+#=======================================================================
+private_colormap: enabled=0
+
+#=======================================================================
+# fullscreen: ONLY IMPLEMENTED ON AMIGA
+#             Request that Bochs occupy the entire screen instead of a 
+#             window.
+#
+# Examples:
+#   fullscreen: enabled=0
+#   fullscreen: enabled=1
+#=======================================================================
+fullscreen: enabled=0
+screenmode: name="sample"
+
+#=======================================================================
+# ne2k: NE2000 compatible ethernet adapter
+#
+# Examples:
+# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
+#
+# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there
+# are IRQ conflicts.
+#
+# mac: The MAC address MUST NOT match the address of any machine on the net.
+# Also, the first byte must be an even number (bit 0 set means a multicast
+# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
+# address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
+# be other restrictions too.  To be safe, just use the b0:c4... address.
+#
+# ethdev: The ethdev value is the name of the network interface on your host
+# platform.  On UNIX machines, you can get the name by running ifconfig.  On
+# Windows machines, you must run niclist to get the name of the ethdev.
+# Niclist source code is in misc/niclist.c and it is included in Windows 
+# binary releases.
+#
+# script: The script value is optionnal, and is the name of a script that 
+# is executed after bochs initialize the network interface. You can use 
+# this script to configure this network interface, or enable masquerading.
+# This is mainly useful for the tun/tap devices that only exist during
+# Bochs execution. The network interface name is supplied to the script
+# as first parameter
+#=======================================================================
+# ne2k: ioaddr=0x280, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
+# ne2k: ioaddr=0x280, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
+# ne2k: ioaddr=0x280, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
+# ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+# ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=tun0, script=./ifup.tun
+# ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=tun0
+
+# Pseudo NIC adaptor.  The way bochs is structured at the moment means
+# that you need to enable ne2k support in order to compile in any of
+# the networking code.
+pnic: ioaddr=0xdc00, irq=11, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=tun1, script=./ifup.tun
+
+#=======================================================================
+# KEYBOARD_MAPPING:
+# This enables a remap of a physical localized keyboard to a 
+# virtualized us keyboard, as the PC architecture expects.
+# If enabled, the keymap file must be specified.
+# 
+# Examples:
+#   keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map
+#=======================================================================
+keyboard_mapping: enabled=0, map=
+
+#=======================================================================
+# KEYBOARD_TYPE:
+# Type of keyboard return by a "identify keyboard" command to the
+# keyboard controler. It must be one of "xt", "at" or "mf".
+# Defaults to "mf". It should be ok for almost everybody. A known
+# exception is french macs, that do have a "at"-like keyboard.
+#
+# Examples:
+#   keyboard_type: mf
+#=======================================================================
+#keyboard_type: mf
+
+#=======================================================================
+# USER_SHORTCUT:
+# This defines the keyboard shortcut to be sent when you press the "user"
+# button in the headerbar. The shortcut string can be a combination of
+# these key names: "alt", "ctrl", "del", "esc", "f1", "f4", "tab", "win".
+# Up to 3 keys can be pressed at a time.
+#
+# Example:
+#   user_shortcut: keys=ctrlaltdel
+#=======================================================================
+user_shortcut: keys=ctrlaltdel
+
+#=======================================================================
+# other stuff
+#=======================================================================
+magic_break: enabled=1
+
+#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
+#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
+i440fxsupport: enabled=1
+#time0: 938581955
+
+#=======================================================================
+# for Macintosh, use the style of pathnames in the following
+# examples.
+#
+# vgaromimage: :bios:VGABIOS-elpin-2.20
+# romimage: file=:bios:BIOS-bochs-981222a, address=0xf0000
+# floppya: 1_44=[fd:], status=inserted
+#=======================================================================
+
diff --git a/contrib/bochs/ifup.tun b/contrib/bochs/ifup.tun
new file mode 100755 (executable)
index 0000000..8e2ede2
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+SCRIPT=$0
+INTERFACE=$1
+
+if [ `id -u` != 0 ]; then
+    echo ""
+    echo "Enter root password for configuring network interface $INTERFACE"
+    echo "(To avoid this prompt, make the script $SCRIPT setuid-root)"
+    /bin/su -c "$SCRIPT $INTERFACE" || exit 1
+    exit 0
+fi
+
+/sbin/ifconfig $INTERFACE 10.254.254.2 netmask 255.255.255.252
+
+# Force dhcpd to notice the new network interface
+if [ -x /etc/init.d/dhcpd ]; then
+  /etc/init.d/dhcpd reload # Redhat
+elif [ -x /etc/init.d/dhcp ]; then
+  /etc/init.d/dhcp restart # Debian
+fi
diff --git a/contrib/bochs/serial-console b/contrib/bochs/serial-console
new file mode 100755 (executable)
index 0000000..3ea877c
--- /dev/null
@@ -0,0 +1,278 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+serial-console
+
+=head1 SYNOPSIS
+
+serial-console [options]
+
+Options:
+
+    -h,--help         Display brief help message
+    -v,--verbose      Increase verbosity
+    -q,--quiet        Decrease verbosity
+    -l,--log FILE     Log output to file
+    -r,--rcfile        FILE  Modify specified bochsrc file
+
+=head1 DESCRIPTION
+
+C<serial-console> provides a virtual serial console for use with
+Bochs.  Running C<serial-console> creates a pseudo-tty.  The master
+side of this pty is made available to the user for interaction; the
+slave device is written to the Bochs configuration file
+(C<bochsrc.txt>) for use by a subsequent Bochs session.
+
+=head1 EXAMPLES
+
+=over 4
+
+=item C<serial-console>
+
+Create a virtual serial console for Bochs, modify C<bochsrc.txt>
+appropriately.
+
+=item C<serial-console -r ../.bochsrc -l serial.log>
+
+Create a virtual serial console for Bochs, modify C<../.bochsrc>
+appropriately, log output to C<serial.log>.
+
+=back
+
+=head1 INVOCATION
+
+Before starting Bochs, run C<serial-console> in a different session
+(e.g. a different xterm window).  When you subsequently start Bochs,
+anything that the emulated machine writes to its serial port will
+appear in the window running C<serial-console>, and anything typed in
+the C<serial-console> window will arrive on the emulated machine's
+serial port.
+
+You do B<not> need to rerun C<serial-console> afresh for each Bochs
+session.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-l,--log FILE>
+
+Log all output (i.e. everything that is printed in the
+C<serial-console> window) to the specified file.
+
+=item B<-r,--rcfile FILE>
+
+Modify the specified bochsrc file.  The file will be updated to
+contain the path to the slave side of the psuedo tty that we create.
+The original file will be restored when C<serial-console> exits.  The
+default is to modify the file C<bochsrc.txt> in the current directory.
+
+To avoid modifying any bochsrc file, use C<--norcfile>.
+
+=back
+
+=cut
+
+use IO::Pty;
+use IO::Select;
+use File::Spec::Functions qw ( :ALL );
+use Getopt::Long;
+use Pod::Usage;
+use POSIX qw ( :termios_h );
+use strict;
+use warnings;
+
+my $o;
+my $restore_file = {};
+my $restore_termios;
+use constant BLOCKSIZE => 8192;
+
+##############################################################################
+#
+# Parse command line options into options hash ($o)
+#
+# $o = parse_opts();
+
+sub parse_opts {
+  # $o is the hash that will hold the options
+  my $o = {
+    verbosity => 1,
+    rcfile => 'bochsrc.txt',
+  };
+  # Special handlers for some options
+  my $opt_handlers = {
+    verbose => sub { $o->{verbosity}++; },
+    quiet => sub { $o->{verbosity}--; },
+    help => sub { pod2usage(1); },
+    norcfile => sub { delete $o->{rcfile}; },
+  };
+  # Merge handlers into main options hash (so that Getopt::Long can find them)
+  $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
+  # Option specifiers for Getopt::Long
+  my @optspec = ( 'help|h|?',
+                  'quiet|q+',
+                  'verbose|v+',
+                 'log|l=s',
+                 'rcfile|r=s',
+                 'norcfile',
+                  );
+  # Do option parsing
+  Getopt::Long::Configure ( 'bundling' );
+  pod2usage("Error parsing command-line options") unless GetOptions (
+  $o, @optspec );
+  # Clean up $o by removing the handlers
+  delete $o->{$_} foreach keys %$opt_handlers;
+  return $o;
+}
+
+##############################################################################
+#
+# Modify bochsrc file
+
+sub patch_bochsrc {
+  my $active = shift;
+  my $pty = shift;
+
+  # Rename active file to backup file
+  ( my $vol, my $dir, my $file ) = splitpath ( $active );
+  $file = '.'.$file.".serial-console";
+  my $backup = catpath ( $vol, $dir, $file );
+  rename $active, $backup
+      or die "Could not back up $active to $backup: $!\n";
+
+  # Derive line to be inserted
+  my $patch = "com1: enabled=1, dev=$pty\n";
+
+  # Modify file
+  open my $old, "<$backup" or die "Could not open $backup: $!\n";
+  open my $new, ">$active" or die "Could not open $active: $!\n";
+  print $new <<"EOF";
+##################################################
+#
+# This file has been modified by serial-console.
+#
+# Do not modify this file; it will be erased when
+# serial-console (pid $$) exits and will be
+# replaced with the backup copy held in
+# $backup.
+#
+##################################################
+
+
+EOF
+  my $patched;
+  while ( my $line = <$old> ) {
+    if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
+      if ( ! $patched ) {
+       $line = $patch;
+       $patched = 1;
+      } else {
+       $line = '# '.$line unless $line =~ /^\s*\#/;
+      }
+    }
+    print $new $line;
+  }
+  print $new $patch unless $patched;
+  close $old;
+  close $new;
+
+  return $backup;
+}
+
+##############################################################################
+#
+# Attach/detach message printing and terminal settings
+
+sub bochs_attached {
+  print STDERR "Bochs attached.\n\n\n"
+      if $o->{verbosity} >= 1;
+}
+
+sub bochs_detached {
+  print STDERR "\n\nWaiting for bochs to attach...\n"
+      if $o->{verbosity} >= 1;
+}
+
+##############################################################################
+#
+# Main program
+
+$o = parse_opts();
+pod2usage(1) if @ARGV;
+
+# Catch signals
+my $sigdie = sub { die "Exiting via signal\n"; };
+$SIG{INT} = $sigdie;
+
+# Create Pty, close slave side
+my $pty = IO::Pty->new();
+$pty->close_slave();
+$pty->set_raw();
+print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
+
+# Open logfile
+my $log;
+if ( $o->{log} ) {
+  open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
+}
+
+# Set up terminal
+my $termios;
+if ( -t STDIN ) {
+  $termios = POSIX::Termios->new;
+  $restore_termios = POSIX::Termios->new;
+  $termios->getattr ( fileno(STDIN) );
+  $restore_termios->getattr ( fileno(STDIN) );
+  $termios->setlflag ( $termios->getlflag &
+                      ~(ICANON) & ~(ECHO) );
+  $termios->setattr ( fileno(STDIN), TCSANOW );
+}
+
+# Modify bochsrc file
+$restore_file = { $o->{rcfile} =>
+                 patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) }
+    if $o->{rcfile};
+
+# Start character shunt
+my $attached = 1;
+my $select = IO::Select->new ( \*STDIN, $pty );
+while ( 1 ) {
+  my %can_read = map { $_ => 1 }
+                    $select->can_read ( $attached ? undef : 1 );
+  if ( $can_read{\*STDIN} ) {
+    sysread ( STDIN, my $data, BLOCKSIZE )
+       or die "Cannot read from STDIN: $!\n";
+    $pty->syswrite ( $data );
+  }
+  if ( $can_read{$pty} ) {
+    if ( $pty->sysread ( my $data, BLOCKSIZE ) ) {
+      # Actual data available
+      bochs_attached() if $attached == 0;
+      $attached = 1;
+      syswrite ( STDOUT, $data );
+      $log->syswrite ( $data ) if $log;
+    } else {
+      # No data available but select() says we can read.  This almost
+      # certainly indicates that nothing is attached to the slave.
+      bochs_detached() if $attached == 1;
+      $attached = 0;
+      sleep ( 1 );
+    }
+  } else {
+    bochs_attached() if $attached == 0;
+    $attached = 1;
+  }
+}
+
+END {
+  # Restore bochsrc file if applicable
+  if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {
+    unlink $orig_file;
+    rename $backup_file, $orig_file;
+  }
+  # Restore terminal settings if applicable
+  if ( $restore_termios ) {
+    $restore_termios->setattr ( fileno(STDIN), TCSANOW );
+  }
+}
diff --git a/contrib/bochs/serial-console.1 b/contrib/bochs/serial-console.1
new file mode 100644 (file)
index 0000000..210de55
--- /dev/null
@@ -0,0 +1,191 @@
+.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  | will give a
+.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used to
+.\" do unbreakable dashes and therefore won't be available.  \*(C` and \*(C'
+.\" expand to `' in nroff, nothing in troff, for use with C<>.
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.\"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "SERIAL-CONSOLE 1"
+.TH SERIAL-CONSOLE 1 "2004-03-10" "perl v5.8.0" "User Contributed Perl Documentation"
+.SH "NAME"
+serial\-console
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+serial-console [options]
+.PP
+Options:
+.PP
+.Vb 5
+\&    -h,--help         Display brief help message
+\&    -v,--verbose      Increase verbosity
+\&    -q,--quiet        Decrease verbosity
+\&    -l,--log FILE     Log output to file
+\&    -r,--rcfile FILE  Modify specified bochsrc file
+.Ve
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with
+Bochs.  Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo\-tty.  The master
+side of this pty is made available to the user for interaction; the
+slave device is written to the Bochs configuration file
+(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+.ie n .IP """serial\-console""" 4
+.el .IP "\f(CWserial\-console\fR" 4
+.IX Item "serial-console"
+Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR
+appropriately.
+.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4
+.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4
+.IX Item "serial-console -r ../.bochsrc -l serial.log"
+Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR
+appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR.
+.SH "INVOCATION"
+.IX Header "INVOCATION"
+Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session
+(e.g. a different xterm window).  When you subsequently start Bochs,
+anything that the emulated machine writes to its serial port will
+appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in
+the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's
+serial port.
+.PP
+You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs
+session.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4
+.IX Item "-l,--log FILE"
+Log all output (i.e. everything that is printed in the
+\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file.
+.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4
+.IX Item "-r,--rcfile FILE"
+Modify the specified bochsrc file.  The file will be updated to
+contain the path to the slave side of the psuedo tty that we create.
+The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits.  The
+default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory.
+.Sp
+To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR.
diff --git a/contrib/bootptodhcp/bootptodhcp.pl b/contrib/bootptodhcp/bootptodhcp.pl
new file mode 100755 (executable)
index 0000000..c8d6465
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/perl -w
+#
+# Quick hack to convert /etc/bootptab to format required by ISC DHCPD
+# This only outputs the fixed hosts portion of the config file
+# You still have to provide the global options and the subnet scoping
+#
+# Turn $useipaddr on if you prefer to use IP addresses in the config file
+# I run DNS so I prefer domain names
+$useipaddr = 0;
+# This will be appended to get the FQDN unless the hostname is already FQDN
+$domainname = "ken.com.au";
+$tftpdir = "/tftpdir/";
+open(B, "/etc/bootptab") or die "/etc/bootptab: $!\n";
+while(<B>) {
+       if (/^[^a-z]/) {
+               $prevline = $_;
+               next;
+       }
+       chomp($_);
+       ($hostname, @tags) = split(/:/, $_, 5);
+       ($fqdn = $hostname) .= ".$domainname" unless($hostname =~ /\./);
+       ($macaddr) = grep(/^ha=/, @tags);
+       $macaddr =~ s/ha=//;
+       $macaddr =~ s/(..)(..)(..)(..)(..)(..)/$1:$2:$3:$4:$5:$6/g;
+       ($ipaddr) = grep(/^ip=/, @tags);
+       $ipaddr =~ s/ip=//;
+       ($bootfile) = grep(/^bf=/, @tags);
+       $bootfile =~ s/bf=//;
+       $bootfile = $tftpdir . $bootfile;
+# I have a comment line above most entries and I like to carry this over
+       print $prevline if ($prevline =~ /^#/);
+       $address = $useipaddr ? $ipaddr : $fqdn;
+       print <<EOF
+       host $hostname {
+               hardware ethernet $macaddr;
+               fixed-address $address;
+               filename "$bootfile";
+       }
+EOF
+;
+       $prevline = $_;
+}
diff --git a/contrib/compressor/COPYING b/contrib/compressor/COPYING
new file mode 100644 (file)
index 0000000..e574f7c
--- /dev/null
@@ -0,0 +1,23 @@
+The compression code as implemented in "lzhuf.c" was taken from a BBS
+program written by Joachim Schurig <jschurig@zedat.fu-berlin.de>. He
+states that the code can be used freely for programs that are covered
+by a "freeware" license. This probably includes both BSD style
+licenses and the GPL.
+
+The code in "loader.asm" is a reimplementation of the uncompressor. It
+has been written from scratch and is hereby placed under the
+conditions of the GNU General Public License (GPL). The algorithm is
+outlined in "algorithm.doc".
+
+Thus, there are no copyright problems with using this code, but there
+still might be difficulties with software patents. These patents are
+not legal in most parts of the world, but if you live in a country
+that honors software patents then you should verify that using these
+algorithms is legally permitted. Unless you are absolutely sure, that
+there are no legal obstacles, you should use the code for educational
+purposes only (this assumes that your educational institution is
+exempted from patent laws). The author cannot be held responsible for
+using the program code in violation of applicable local laws.
+
+If you are aware of patents that might affect the legality of using
+the code in some parts of the world, please let me know.
diff --git a/contrib/compressor/algorithm.doc b/contrib/compressor/algorithm.doc
new file mode 100644 (file)
index 0000000..74a7646
--- /dev/null
@@ -0,0 +1,58 @@
+The  compressor achieves  an  average compression  rate of 60%  of the
+original size which is on par with "gzip". It seems that you cannot do
+much better for compressing  compiled  binaries.  This means that  the
+break even  point  for using compressed  images is   reached, once the
+uncompressed size approaches 1.5kB. We  can stuff more than 12kB  into
+an 8kB EPROM and more than 25kB into an 16kB EPROM.   As there is only
+32kB of RAM  for both the uncompressed  image  and its BSS  area, this
+means that 32kB EPROMs will hardly ever be required.
+
+The compression  algorithm uses a  4kB  ring buffer  for buffering the
+uncompressed data. Before   compression starts,  the  ring buffer   is
+filled  with spaces (ASCII  character  0x20).  The algorithm tries  to
+find repeated  input sequences of a  maximum length of  60 bytes.  All
+256 different input  bytes  plus the 58 (60   minus a threshold of  2)
+possible  repeat lengths form a set  of 314 symbols. These symbols are
+adaptively Huffman encoded.  The  algorithm starts out with a Huffmann
+tree  that  assigns equal code lengths    to each of  the  314 symbols
+(slightly favoring the repeat  symbols over symbols for regular  input
+characters), but  it will be changed whenever  the frequency of any of
+the symbols  changes. Frequency counts are  kept in 16bit  words until
+the total number of compressed codes totals 2^15.  Then, all frequency
+counts will be halfed (rounding to the bigger number).  For unrepeated
+characters (symbols 0..255) the Huffman code  is written to the output
+stream.  For repeated characters the  Huffmann code, which denotes the
+length of the repeated character sequence, is written out and then the
+index in the ring buffer is computed.   From this index, the algorithm
+computes  the offset   relative to  the current  index  into  the ring
+buffer. Thus,  for typical input data,  one would expect that short to
+medium range offsets are more frequent  than extremely short or medium
+range to long range offsets. Thus the  12bit (for a 4kB buffer) offset
+value  is statically Huffman encoded  using a precomputed Huffman tree
+that favors  those  offset  values    that  are deemed to   be    more
+frequent. The  Huffman encoded offset  is  written to the output  data
+stream,  directly  following the code  that   determines the length of
+repeated characters.
+
+This algorithm, as implemented in the  C example code, looks very good
+and  its operating parameters are   already well optimized. This  also
+explains   why  it achieves     compression ratios    comparable  with
+"gzip". Depending on the input data, it sometimes excells considerably
+beyond what "gzip -9" does, but this  phenomenon does not appear to be
+typical. There are some flaws with  the algorithm, such as the limited
+buffer  sizes, the  adaptive  Huffman tree  which takes  very  long to
+change, if    the input  characters  experience   a sudden   change in
+distribution, and the static Huffman   tree for encoding offsets  into
+the  buffer.   The slow  changes of   the  adaptive  Huffman  tree are
+partially counteracted by  artifically keeping  a 16bit precision  for
+the frequency counts, but  this does not  come into play until 32kB of
+compressed data is output, so  it does not  have any impact on our use
+for "etherboot", because  the BOOT Prom  does not support uncompressed
+data of more then 32kB (c.f. doc/spec.doc).
+
+Nonetheless,  these problems  do  not  seem  to affect  compression of
+compiled  programs very much.  Mixing  object code with English  text,
+would not work too  well though, and  the algorithm should be reset in
+between. Actually, we  might  gain a little  improvement, if  text and
+data   segments    were compressed  individually,    but   I have  not
+experimented with this option, yet.
diff --git a/contrib/compressor/loader.h b/contrib/compressor/loader.h
new file mode 100644 (file)
index 0000000..20fa9af
--- /dev/null
@@ -0,0 +1,14 @@
+/* Do not change these values unless you really know what you are doing;
+   the pre-computed lookup tables rely on the buffer size being 4kB or
+   smaller. The buffer size must be a power of two. The lookahead size has
+   to fit into 6 bits. If you change any of these numbers, you will also
+   have to adjust the decompressor accordingly.
+ */
+
+#define BUFSZ           4096
+#define LOOKAHEAD       60
+#define THRESHOLD       2
+#define NCHAR           (256+LOOKAHEAD-THRESHOLD)
+#define TABLESZ         (NCHAR+NCHAR-1)
+#define NIL             ((unsigned short)-1)
+
diff --git a/contrib/compressor/lzhuf.c b/contrib/compressor/lzhuf.c
new file mode 100644 (file)
index 0000000..ea65b5e
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+----------------------------------------------------------------------------
+
+M. LZHuf Compression
+
+This is the LZHuf compression algorithm as used in DPBOX and F6FBB.
+
+----------------------------------------------------------------------------
+*/
+/**************************************************************
+    lzhuf.c
+    written by Haruyasu Yoshizaki 11/20/1988
+    some minor changes 4/6/1989
+    comments translated by Haruhiko Okumura 4/7/1989
+
+    minor beautifications and adjustments for compiling under Linux
+    by Markus Gutschke <gutschk@math.uni-muenster.de>
+                                               1997-01-27
+
+    Modifications to allow use as a filter by  Ken Yap <ken_yap@users.sourceforge.net>.
+                                               1997-07-01
+
+    Small mod to cope with running on big-endian machines
+    by Jim Hague <jim.hague@acm.org)
+                                               1998-02-06
+
+    Make compression statistics report shorter
+    by Ken Yap <ken_yap@users.sourceforge.net>.
+                                               2001-04-25
+**************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr     0
+#else
+#define Fprintf(x) fprintf x
+#if defined(ENCODE) || defined(DECODE)
+static char wterr[] = "Can't write.";
+#ifdef ENCODE
+static unsigned long int codesize = 0;
+#endif
+static unsigned long int printcount = 0;
+#endif
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE  *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned long int  textsize = 0;
+
+static __inline__ void Error(char *message)
+{
+    Fprintf((stderr, "\n%s\n", message));
+    exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+    unsigned long res = 0;
+    int i;
+    union
+    {
+       unsigned char c[4];
+       unsigned long ul;
+    } u;
+
+    u.ul = ul;
+    for (i = 3; i >= 0; i--)
+       res = (res << 8) + u.c[i];
+    return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+    int i;
+    union
+    {
+       unsigned char c[4];
+       unsigned long ul;
+    } u;
+
+    for (i = 0; i < 4; i++)
+    {
+       u.c[i] = ul & 0xff;
+       ul >>= 8;
+    }
+    return u.ul;
+}
+#endif
+
+/********** LZSS compression **********/
+
+#define N       4096    /* buffer size */
+/* Attention: When using this file for f6fbb-type compressed data exchange,
+   set N to 2048 ! (DL8HBS) */
+#define F       60  /* lookahead buffer size */
+#define THRESHOLD   2
+#define NIL     N   /* leaf of tree */
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned char
+        text_buf[N + F - 1];
+#endif
+
+#ifdef ENCODE
+static int     match_position, match_length,
+               lson[N + 1], rson[N + 257], dad[N + 1];
+
+static void InitTree(void)  /* initialize trees */
+{
+    int  i;
+
+    for (i = N + 1; i <= N + 256; i++)
+        rson[i] = NIL;          /* root */
+    for (i = 0; i < N; i++)
+        dad[i] = NIL;           /* node */
+}
+
+static void InsertNode(int r)  /* insert to tree */
+{
+    int  i, p, cmp;
+    unsigned char  *key;
+    unsigned c;
+
+    cmp = 1;
+    key = &text_buf[r];
+    p = N + 1 + key[0];
+    rson[r] = lson[r] = NIL;
+    match_length = 0;
+    for ( ; ; ) {
+        if (cmp >= 0) {
+            if (rson[p] != NIL)
+                p = rson[p];
+            else {
+                rson[p] = r;
+                dad[r] = p;
+                return;
+            }
+        } else {
+            if (lson[p] != NIL)
+                p = lson[p];
+            else {
+                lson[p] = r;
+                dad[r] = p;
+                return;
+            }
+        }
+        for (i = 1; i < F; i++)
+            if ((cmp = key[i] - text_buf[p + i]) != 0)
+                break;
+        if (i > THRESHOLD) {
+            if (i > match_length) {
+                match_position = ((r - p) & (N - 1)) - 1;
+                if ((match_length = i) >= F)
+                    break;
+            }
+            if (i == match_length) {
+                if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
+                    match_position = c;
+                }
+            }
+        }
+    }
+    dad[r] = dad[p];
+    lson[r] = lson[p];
+    rson[r] = rson[p];
+    dad[lson[p]] = r;
+    dad[rson[p]] = r;
+    if (rson[dad[p]] == p)
+        rson[dad[p]] = r;
+    else
+        lson[dad[p]] = r;
+    dad[p] = NIL;  /* remove p */
+}
+
+static void DeleteNode(int p)  /* remove from tree */
+{
+    int  q;
+
+    if (dad[p] == NIL)
+        return;         /* not registered */
+    if (rson[p] == NIL)
+        q = lson[p];
+    else
+    if (lson[p] == NIL)
+        q = rson[p];
+    else {
+        q = lson[p];
+        if (rson[q] != NIL) {
+            do {
+                q = rson[q];
+            } while (rson[q] != NIL);
+            rson[dad[q]] = lson[q];
+            dad[lson[q]] = dad[q];
+            lson[q] = lson[p];
+            dad[lson[p]] = q;
+        }
+        rson[q] = rson[p];
+        dad[rson[p]] = q;
+    }
+    dad[q] = dad[p];
+    if (rson[dad[p]] == p)
+        rson[dad[p]] = q;
+    else
+        lson[dad[p]] = q;
+    dad[p] = NIL;
+}
+#endif
+
+/* Huffman coding */
+
+#define N_CHAR      (256 - THRESHOLD + F)
+                /* kinds of characters (character code = 0..N_CHAR-1) */
+#define T       (N_CHAR * 2 - 1)    /* size of table */
+#define R       (T - 1)         /* position of root */
+#define MAX_FREQ    0x8000      /* updates tree when the */
+                    /* root frequency comes to this value. */
+typedef unsigned char uchar;
+
+/* table for encoding and decoding the upper 6 bits of position */
+
+/* for encoding */
+
+#ifdef ENCODE
+static uchar p_len[64] = {
+    0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+
+static uchar p_code[64] = {
+    0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
+    0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
+    0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
+    0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
+    0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
+    0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
+    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+#endif
+
+#ifdef DECODE
+/* for decoding */
+static uchar d_code[256] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+    0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+    0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+    0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+    0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+    0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+    0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+    0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
+    0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
+    0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
+    0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+    0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
+    0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+};
+
+static uchar d_len[256] = {
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+};
+#endif
+
+#if defined(ENCODE) || defined(DECODE)
+static unsigned freq[T + 1];   /* frequency table */
+
+static int prnt[T + N_CHAR];   /* pointers to parent nodes, except for the */
+            /* elements [T..T + N_CHAR - 1] which are used to get */
+            /* the positions of leaves corresponding to the codes. */
+
+static int son[T];     /* pointers to child nodes (son[], son[] + 1) */
+#endif
+
+#ifdef DECODE
+static unsigned getbuf = 0;
+static uchar getlen = 0;
+
+static int GetBit(void)    /* get one bit */
+{
+    int i;
+
+    while (getlen <= 8) {
+        if ((i = getc(infile)) < 0) i = 0;
+        getbuf |= i << (8 - getlen);
+        getlen += 8;
+    }
+    i = getbuf;
+    getbuf <<= 1;
+    getlen--;
+    return ((signed short)i < 0);
+}
+
+static int GetByte(void)   /* get one byte */
+{
+    unsigned short i;
+
+    while (getlen <= 8) {
+        if ((signed short)(i = getc(infile)) < 0) i = 0;
+        getbuf |= i << (8 - getlen);
+        getlen += 8;
+    }
+    i = getbuf;
+    getbuf <<= 8;
+    getlen -= 8;
+    return i >> 8;
+}
+#endif
+
+#ifdef ENCODE
+static unsigned putbuf = 0;
+static uchar putlen = 0;
+
+static void Putcode(int l, unsigned c)     /* output c bits of code */
+{
+    putbuf |= c >> putlen;
+    if ((putlen += l) >= 8) {
+        if (putc(putbuf >> 8, outfile) == EOF) {
+            Error(wterr);
+        }
+        if ((putlen -= 8) >= 8) {
+            if (putc(putbuf, outfile) == EOF) {
+                Error(wterr);
+            }
+#ifdef VERBOSE
+            codesize += 2;
+#endif
+            putlen -= 8;
+            putbuf = c << (l - putlen);
+        } else {
+         putbuf <<= 8;
+#ifdef VERBOSE
+         codesize++;
+#endif
+        }
+    }
+}
+#endif
+
+/* initialization of tree */
+
+#if defined(ENCODE) || defined(DECODE)
+static void StartHuff(void)
+{
+    int i, j;
+
+    for (i = 0; i < N_CHAR; i++) {
+        freq[i] = 1;
+        son[i] = i + T;
+        prnt[i + T] = i;
+    }
+    i = 0; j = N_CHAR;
+    while (j <= R) {
+        freq[j] = freq[i] + freq[i + 1];
+        son[j] = i;
+        prnt[i] = prnt[i + 1] = j;
+        i += 2; j++;
+    }
+    freq[T] = 0xffff;
+    prnt[R] = 0;
+}
+
+/* reconstruction of tree */
+
+static void reconst(void)
+{
+    int i, j, k;
+    unsigned f, l;
+
+    /* collect leaf nodes in the first half of the table */
+    /* and replace the freq by (freq + 1) / 2. */
+    j = 0;
+    for (i = 0; i < T; i++) {
+        if (son[i] >= T) {
+            freq[j] = (freq[i] + 1) / 2;
+            son[j] = son[i];
+            j++;
+        }
+    }
+    /* begin constructing tree by connecting sons */
+    for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
+        k = i + 1;
+        f = freq[j] = freq[i] + freq[k];
+        for (k = j - 1; f < freq[k]; k--);
+        k++;
+        l = (j - k) * 2;
+        memmove(&freq[k + 1], &freq[k], l);
+        freq[k] = f;
+        memmove(&son[k + 1], &son[k], l);
+        son[k] = i;
+    }
+    /* connect prnt */
+    for (i = 0; i < T; i++) {
+        if ((k = son[i]) >= T) {
+            prnt[k] = i;
+        } else {
+            prnt[k] = prnt[k + 1] = i;
+        }
+    }
+}
+
+/* increment frequency of given code by one, and update tree */
+
+static void update(int c)
+{
+    int i, j, k, l;
+
+    if (freq[R] == MAX_FREQ) {
+        reconst();
+    }
+    c = prnt[c + T];
+    do {
+        k = ++freq[c];
+
+        /* if the order is disturbed, exchange nodes */
+        if (k > freq[l = c + 1]) {
+            while (k > freq[++l]);
+            l--;
+            freq[c] = freq[l];
+            freq[l] = k;
+
+            i = son[c];
+            prnt[i] = l;
+            if (i < T) prnt[i + 1] = l;
+
+            j = son[l];
+            son[l] = i;
+
+            prnt[j] = c;
+            if (j < T) prnt[j + 1] = c;
+            son[c] = j;
+
+            c = l;
+        }
+    } while ((c = prnt[c]) != 0);   /* repeat up to root */
+}
+#endif
+
+#ifdef ENCODE
+#if 0
+static unsigned code, len;
+#endif
+
+static void EncodeChar(unsigned c)
+{
+    unsigned i;
+    int j, k;
+
+    i = 0;
+    j = 0;
+    k = prnt[c + T];
+
+    /* travel from leaf to root */
+    do {
+        i >>= 1;
+
+        /* if node's address is odd-numbered, choose bigger brother node */
+        if (k & 1) i += 0x8000;
+
+        j++;
+    } while ((k = prnt[k]) != R);
+    Putcode(j, i);
+#if 0
+    code = i;
+    len = j;
+#endif
+    update(c);
+}
+
+static void EncodePosition(unsigned c)
+{
+    unsigned i;
+
+    /* output upper 6 bits by table lookup */
+    i = c >> 6;
+    Putcode(p_len[i], (unsigned)p_code[i] << 8);
+
+    /* output lower 6 bits verbatim */
+    Putcode(6, (c & 0x3f) << 10);
+}
+
+static void EncodeEnd(void)
+{
+    if (putlen) {
+        if (putc(putbuf >> 8, outfile) == EOF) {
+            Error(wterr);
+        }
+#ifdef VERBOSE
+        codesize++;
+#endif
+    }
+}
+#endif
+
+#ifdef DECODE
+static int DecodeChar(void)
+{
+    unsigned c;
+
+    c = son[R];
+
+    /* travel from root to leaf, */
+    /* choosing the smaller child node (son[]) if the read bit is 0, */
+    /* the bigger (son[]+1} if 1 */
+    while (c < T) {
+        c += GetBit();
+        c = son[c];
+    }
+    c -= T;
+    update(c);
+    return c;
+}
+
+static int DecodePosition(void)
+{
+    unsigned i, j, c;
+
+    /* recover upper 6 bits from table */
+    i = GetByte();
+    c = (unsigned)d_code[i] << 6;
+    j = d_len[i];
+
+    /* read lower 6 bits verbatim */
+    j -= 2;
+    while (j--) {
+        i = (i << 1) + GetBit();
+    }
+    return c | (i & 0x3f);
+}
+#endif
+
+#ifdef ENCODE
+/* compression */
+
+void Encode(void)  /* compression */
+{
+    int  i, c, len, r, s, last_match_length;
+    unsigned long tw;
+
+    fseek(infile, 0L, 2);
+    textsize = ftell(infile);
+#ifdef VERBOSE
+    if ((signed long)textsize < 0)
+      Fprintf((stderr, "Errno: %d", errno));
+#endif
+    tw = host_to_i86ul(textsize);
+    if (fwrite(&tw, sizeof tw, 1, outfile) < 1)
+        Error(wterr);   /* output size of text */
+    if (textsize == 0)
+        return;
+    rewind(infile);
+    textsize = 0;           /* rewind and re-read */
+    StartHuff();
+    InitTree();
+    s = 0;
+    r = N - F;
+    for (i = s; i < r; i++)
+        text_buf[i] = ' ';
+    for (len = 0; len < F && (c = getc(infile)) != EOF; len++)
+        text_buf[r + len] = c;
+    textsize = len;
+    for (i = 1; i <= F; i++)
+        InsertNode(r - i);
+    InsertNode(r);
+    do {
+        if (match_length > len)
+            match_length = len;
+        if (match_length <= THRESHOLD) {
+            match_length = 1;
+            EncodeChar(text_buf[r]);
+        } else {
+            EncodeChar(255 - THRESHOLD + match_length);
+            EncodePosition(match_position);
+        }
+        last_match_length = match_length;
+        for (i = 0; i < last_match_length &&
+                (c = getc(infile)) != EOF; i++) {
+            DeleteNode(s);
+            text_buf[s] = c;
+            if (s < F - 1)
+                text_buf[s + N] = c;
+            s = (s + 1) & (N - 1);
+            r = (r + 1) & (N - 1);
+            InsertNode(r);
+        }
+        if ((textsize += i) > printcount) {
+#if defined(VERBOSE) && defined(EXTRAVERBOSE)
+            Fprintf((stderr, "%12ld\r", textsize));
+#endif
+            printcount += 1024;
+        }
+        while (i++ < last_match_length) {
+            DeleteNode(s);
+            s = (s + 1) & (N - 1);
+            r = (r + 1) & (N - 1);
+            if (--len) InsertNode(r);
+        }
+    } while (len > 0);
+    EncodeEnd();
+#ifdef LONG_REPORT
+    Fprintf((stderr, "input size    %ld bytes\n", codesize));
+    Fprintf((stderr, "output size   %ld bytes\n", textsize));
+    Fprintf((stderr, "input/output  %.3f\n", (double)codesize / textsize));
+#else
+    Fprintf((stderr, "input/output = %ld/%ld = %.3f\n", codesize, textsize,
+               (double)codesize / textsize));
+#endif
+}
+#endif
+
+#ifdef DECODE
+void Decode(void)  /* recover */
+{
+    int  i, j, k, r, c;
+    unsigned long int  count;
+    unsigned long tw;
+
+    if (fread(&tw, sizeof tw, 1, infile) < 1)
+        Error("Can't read");  /* read size of text */
+    textsize = i86ul_to_host(tw);
+    if (textsize == 0)
+        return;
+    StartHuff();
+    for (i = 0; i < N - F; i++)
+        text_buf[i] = ' ';
+    r = N - F;
+    for (count = 0; count < textsize; ) {
+        c = DecodeChar();
+        if (c < 256) {
+            if (putc(c, outfile) == EOF) {
+                Error(wterr);
+            }
+            text_buf[r++] = c;
+            r &= (N - 1);
+            count++;
+        } else {
+            i = (r - DecodePosition() - 1) & (N - 1);
+            j = c - 255 + THRESHOLD;
+            for (k = 0; k < j; k++) {
+                c = text_buf[(i + k) & (N - 1)];
+                if (putc(c, outfile) == EOF) {
+                    Error(wterr);
+                }
+                text_buf[r++] = c;
+                r &= (N - 1);
+                count++;
+            }
+        }
+        if (count > printcount) {
+#if defined(VERBOSE) && defined(EXTRAVERBOSE)
+            Fprintf((stderr, "%12ld\r", count));
+#endif
+            printcount += 1024;
+        }
+    }
+    Fprintf((stderr, "%12ld\n", count));
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+    char  *s;
+    FILE  *f;
+    int    c;
+
+    if (argc == 2) {
+       outfile = stdout;
+       if ((f = tmpfile()) == NULL) {
+           perror("tmpfile");
+           return EXIT_FAILURE;
+       }
+       while ((c = getchar()) != EOF)
+           fputc(c, f);
+       rewind(infile = f);
+    }
+    else if (argc != 4) {
+        Fprintf((stderr, "'lzhuf e file1 file2' encodes file1 into file2.\n"
+                "'lzhuf d file2 file1' decodes file2 into file1.\n"));
+        return EXIT_FAILURE;
+    }
+    if (argc == 4) {
+       if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+         || (s = argv[2], (infile  = fopen(s, "rb")) == NULL)
+         || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+           Fprintf((stderr, "??? %s\n", s));
+           return EXIT_FAILURE;
+       }
+    }
+    if (toupper(*argv[1]) == 'E')
+        Encode();
+    else
+        Decode();
+    fclose(infile);
+    fclose(outfile);
+    return EXIT_SUCCESS;
+}
+#endif
diff --git a/contrib/dhcpdconfeg/dhcpd.conf b/contrib/dhcpdconfeg/dhcpd.conf
new file mode 100644 (file)
index 0000000..4d13e0f
--- /dev/null
@@ -0,0 +1,16 @@
+This is an example of using vendor tags in DHCPD config, supplied by
+Bernd Wiebelt.
+
+
+subnet 10.97.0.0 netmask 255.255.0.0 {
+       range 10.97.0.2 10.97.0.254;
+       option option-128  e4:45:74:68:0:0;
+       option option-160 "default=193";
+       option option-184  "HALLO";
+               option option-192 "Linux:::linux.tagged:";
+       option option-193 "DOS Bootdisk:::dosboot.tagged";
+       option option-194 "RH61 Bootdisk:::boot.tagged";
+       option option-195 "Local Disk:::/dev/hda:85b103482a20682da703aa388933a6d8";
+}
+
+
diff --git a/contrib/dhcpdconfeg/vendorclassid.txt b/contrib/dhcpdconfeg/vendorclassid.txt
new file mode 100644 (file)
index 0000000..7b1f391
--- /dev/null
@@ -0,0 +1,140 @@
+From: Dax Kelson
+To: Etherboot users list
+Subject: [Etherboot-users] Example ISC DHCP v3 dhcpd.conf using conditional operations
+Date: Wed, 13 Jun 2001 20:22:21 -0600
+
+Hopefully someone will find this useful.  I spent a long time tracking
+down and figuring out all the pieces.  To the powers that be, feel free to
+stick this in contrib if you like it.
+
+Goal:  Use the vendor-class-identifier and ISC DHCP v3 "match" option to
+conditionally send proper options only when the DHCP discover/request from
+etherboot comes in.  We use static-MAC-to-IP mappings for classroom
+computers, and dynamic dhcp ranges for other clients (student laptops,
+etc).
+
+I used Etherboot 5.0.1 and the patch (required) in this email:
+
+http://www.geocrawler.com/lists/3/SourceForge/5299/0/5952625/
+
+Furture versions of Etherboot will likely already have this patch
+included.
+
+Dax Kelson
+Guru Labs
+
+######### Begin ISC DHCP v3 dhcpd.conf #############
+
+ddns-update-style ad-hoc;
+
+# Global default, can be overridden
+filename "/exports/kickstart/class1-rh7.1.ks";
+
+# Define options for Etherboot
+# There are more, these are just the ones I'm using
+option ebootmagic code 128 = string;
+option cmdline code 129 = string;
+option menudflts code 160 = string;
+option menuline1 code 192 = string;
+option menuline2 code 193 = string;
+option menuline3 code 194 = string;
+option menuline4 code 195 = string;
+option menuline5 code 196 = string;
+option menuline6 code 197 = string;
+option menuline7 code 198 = string;
+option menuline8 code 199 = string;
+option menuline9 code 200 = string;
+option menuline10 code 201 = string;
+option menuline11 code 202 = string;
+option menuline12 code 203 = string;
+option menuline13 code 204 = string;
+option menuline14 code 205 = string;
+option menuline15 code 206 = string;
+option menuline16 code 207 = string;
+option motdline1 code 184 = string;
+
+class "Etherboot" {
+    match if substring (option vendor-class-identifier, 0, 9) = "Etherboot";
+
+        option ebootmagic  = E4:45:74:68:00:00;
+
+# We don't use this here, because different menu items require
+# different cmdlines.  In our ".nbi" files we specify the cmdlines
+
+#        option cmdline  = "ks initrd=initrd.img lang= devfs=nomount";
+
+        option motdline1  = "Welcome to Guru Labs classroom";
+
+        option menudflts  = "timeout=30:default=192";
+
+        option menuline1  = "Boot from Hard Drive (Default):::/dev/hda:::";
+        option menuline2  = "Boot from Floppy:::/dev/fd0:::";
+        option menuline3  = "Boot from CDROM::::::";
+        option menuline4  = "Kickstart install Red Hat 7.1:::rh71-ks-etherboot.nbi:::";
+        option menuline5  = "Red Hat 7.1 network rescue:::rh71-rescue-etherboot.nbi:::";
+        option menuline6  = "Boot Win98SE startup floppy:::win98se-startupdisk.nbi:::";
+        option menuline7  = "Jumpstart install Solaris 8 (not working yet):::/dev/hda:::";
+        option menuline8  = "Install Windows 98 SE (not working yet):::/dev/hda:::";
+        option menuline9  = "Install Windows 2000 (not working yet):::/dev/hda:::";
+        option menuline10  = "Install FreeBSD 4.3 (not working yet):::/dev/hda:::";
+        option menuline11  = "Install OpenBSD 2.9 (not working yet):::/dev/hda:::";
+
+       # This is a hidden menu item, it should be password protected too
+        option menuline12  = "^[[3D^[[K^[[1A^M:::/dev/hda:::";
+
+# We are using the menu, with different bootfiles.  So we don't use this.
+# If you weren't using a menu, you could use this override the global
+# default "filename" setting.
+
+#        filename "rh71-ks-etherboot";
+
+# Use the following if etherboot compiled with -DREQUIRE_VCI_ETHERBOOT
+
+        option vendor-encapsulated-options 3c:09:45:74:68:65:72:62:6f:6f:74:ff;
+
+}
+
+subnet 10.100.0.0 netmask 255.255.255.0 {
+        authoritative;
+        option routers                  10.100.0.254;
+        option subnet-mask              255.255.255.0;
+        option domain-name              "example.com";
+        option domain-name-servers      10.100.0.254;
+        option time-offset              -7; # US/Mountain
+        option ntp-servers              10.100.0.254;
+        range dynamic-bootp 10.100.0.175 10.100.0.250;
+        default-lease-time 21600;
+        max-lease-time 43200;
+        option netbios-name-servers     10.100.0.254;
+        option netbios-node-type 2;
+        use-host-decl-names on;
+        next-server server1.example.com;
+
+}
+
+host station1 {
+        hardware ethernet 00:01:03:de:57:e2;
+        fixed-address 10.100.0.1;
+}
+host station2 {
+        hardware ethernet 00:01:03:de:57:e7;
+        fixed-address 10.100.0.2;
+}
+host station3 {
+        hardware ethernet 00:01:03:de:57:b4;
+        fixed-address 10.100.0.3;
+}
+host station4 {
+        hardware ethernet 00:01:03:de:57:38;
+        fixed-address 10.100.0.4;
+}
+host station5 {
+        hardware ethernet 00:01:03:de:58:3d;
+        fixed-address 10.100.0.5;
+}
+
+#
+# Etc, etc
+#
+
+############## End ISC DHCP v3 dhcpd.conf #############
diff --git a/contrib/dhcpid/dhcpid.txt b/contrib/dhcpid/dhcpid.txt
new file mode 100644 (file)
index 0000000..e6b5d27
--- /dev/null
@@ -0,0 +1,884 @@
+From daniel@insu.com Thu Apr 27 14:14:55 2000
+Sender: root@iNsu.COM
+Message-ID: <39075669.FAEB20F2@insu.com>
+Date: Wed, 26 Apr 2000 16:49:45 -0400
+From: Daniel Shane <daniel@insu.com>
+X-Mailer: Mozilla 4.72 [en] (X11; U; Linux 2.2.14-5.0 i686)
+X-Accept-Language: en
+MIME-Version: 1.0
+Subject: Re: New feature added to etherboot
+References: <20000425170804.6677127D8A@Goffman.iNsu.COM>
+Content-Type: multipart/mixed;
+ boundary="------------4734FDA0BF2F2FBDF8EB8DF6"
+
+This is a multi-part message in MIME format.
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+
+Ok, here is a diff for etherboot 4.6.0 that adds identifiers.
+
+To test this you need to use a class in the dhcpd.conf file and
+also send back a string in option 208.
+
+These identifiers prevent a client from booting from other DHCP
+servers when you have more than 1 in your network.
+
+In will also prevent any client, except the valid ones, to use this
+DHCP server.
+
+Here is a subset of my dhcpd.conf :
+
+option iNdiskless-state code 208 = text;
+
+class "iNdiskless-boot" {
+    match if substring(option iNdiskless-state,0,4) = "BOOT";
+}
+class "iNdiskless-setup" {
+    match if substring(option iNdiskless-state,0,5) = "SETUP";
+}           
+
+subnet 10.4.1.0 netmask 255.255.255.0 {
+pool {
+  allow members of "iNdiskless-boot";
+  deny unknown clients;
+  range 10.4.1.2 10.4.1.200;
+  next-server 10.4.1.1;
+
+# Identify ourselves to the etherboot/DHCP client
+  option iNdiskless-state       "BOOT"; 
+
+  host labo01 {
+       hardware ethernet 00:80:c8:ec:04:1b;
+     }
+  host labo02 {
+       hardware ethernet 00:4f:4c:04:45:d6;
+     }
+  host labo03 {
+       hardware ethernet 00:50:ba:c8:db:d6;
+  }
+}
+pool {
+  allow members of "iNdiskless-setup";
+  range 10.4.1.201 10.4.1.254;
+  option iNdiskless-state       "SETUP";
+
+# send another kernel to setup the diskless workstation
+  }
+}    
+
+Daniel Shane.
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="main.c.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="main.c.diff"
+
+--- etherboot-4.6.0/src/main.c Tue Apr 25 08:30:01 2000
++++ etherboot-4.5.6-new/src/main.c     Wed Apr 26 16:17:09 2000
+@@ -42,6 +42,23 @@ char        *motd[RFC1533_VENDOR_NUMOFMOTD];
+ #ifdef        IMAGE_FREEBSD
+ int freebsd_howto = 0;
+ #endif
++
++#ifdef SERVER_IDENT 
++#ifdef DEFAULT_SERVER_IDENT
++char server_ident[9] = DEFAULT_SERVER_IDENT;
++#else
++char server_ident[9] = {};
++#endif   
++#endif
++
++#ifdef CLIENT_IDENT 
++#ifdef DEFAULT_CLIENT_IDENT
++char client_ident[9] = DEFAULT_CLIENT_IDENT;
++#else
++char client_ident[9] = {};
++#endif
++#endif
++
+ int     vendorext_isvalid;
+ char  config_buffer[TFTP_MAX_PACKET+1];       /* +1 for null byte */
+ unsigned long netmask;
+@@ -63,61 +80,85 @@ char    rfc1533_cookie[5] = { RFC1533_CO
+ char    rfc1533_cookie[] = { RFC1533_COOKIE};
+ char    rfc1533_end[]={RFC1533_END };
+ static const char dhcpdiscover[]={
+-              RFC2132_MSG_TYPE,1,DHCPDISCOVER,
+-              RFC2132_MAX_SIZE,2,2,64,
+-              RFC2132_PARAM_LIST,4,RFC1533_NETMASK,RFC1533_GATEWAY,
+-              RFC1533_HOSTNAME,RFC1533_EXTENSIONPATH
+-      };
+-static const char dhcprequest []={
+-              RFC2132_MSG_TYPE,1,DHCPREQUEST,
+-              RFC2132_SRV_ID,4,0,0,0,0,
+-              RFC2132_REQ_ADDR,4,0,0,0,0,
+-              RFC2132_MAX_SIZE,2,2,64,
+-              /* request parameters */
+-              RFC2132_PARAM_LIST,
+-#ifdef        IMAGE_FREEBSD
+-              /* 4 standard + 4 vendortags + 8 motd + 16 menu items */
+-              4 + 4 + 8 + 16,
++      RFC2132_MSG_TYPE,1,DHCPDISCOVER,
++      RFC2132_MAX_SIZE,2,2,64,
++#ifdef CLIENT_IDENT 
++      RFC1533_VENDOR_CLIENT_IDENT,8,0,0,0,0,0,0,0,0,
++#endif
++      RFC2132_PARAM_LIST,
++#ifdef SERVER_IDENT 
++      5,
+ #else
+-              /* 4 standard + 3 vendortags + 8 motd + 16 menu items */
+-              4 + 3 + 8 + 16,
++      4,
+ #endif
+-              /* Standard parameters */
+-              RFC1533_NETMASK, RFC1533_GATEWAY,
+-              RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
+-              /* Etherboot vendortags */
+-              RFC1533_VENDOR_MAGIC,
++#ifdef SERVER_IDENT 
++      RFC1533_VENDOR_SERVER_IDENT,   
++#endif
++      RFC1533_NETMASK,
++      RFC1533_GATEWAY,
++      RFC1533_HOSTNAME,
++      RFC1533_EXTENSIONPATH
++};
++static const char dhcprequest []={
++      RFC2132_MSG_TYPE,1,DHCPREQUEST,
++      RFC2132_SRV_ID,4,0,0,0,0,
++      RFC2132_REQ_ADDR,4,0,0,0,0,
++#ifdef CLIENT_IDENT 
++      RFC1533_VENDOR_CLIENT_IDENT,8,0,0,0,0,0,0,0,0,
++#endif
++      RFC2132_MAX_SIZE,2,2,64,
++      /* request parameters */
++      RFC2132_PARAM_LIST,
++      /* 4 standard + 3 vendortags + 8 motd + 16 menu items */
++      4 + 
++      3 + 
++#ifdef  IMAGE_FREEBSD
++      1 + /* One more vendortags for VENDOR_HOWTO */
++#endif
++#ifdef SERVER_IDENT 
++      1 + /* One more vendortags for VENDOR_SERVER_IDENT */
++#endif
++      8 + 
++      16,
++      /* Standard parameters */
++      RFC1533_NETMASK, RFC1533_GATEWAY,
++      RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
++      /* Etherboot vendortags */
++      RFC1533_VENDOR_MAGIC,
+ #ifdef        IMAGE_FREEBSD
+-              RFC1533_VENDOR_HOWTO,
++      RFC1533_VENDOR_HOWTO,
+ #endif
+-              RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION,
+-              /* 8 MOTD entries */
+-              RFC1533_VENDOR_MOTD,
+-              RFC1533_VENDOR_MOTD+1,
+-              RFC1533_VENDOR_MOTD+2,
+-              RFC1533_VENDOR_MOTD+3,
+-              RFC1533_VENDOR_MOTD+4,
+-              RFC1533_VENDOR_MOTD+5,
+-              RFC1533_VENDOR_MOTD+6,
+-              RFC1533_VENDOR_MOTD+7,
+-              /* 16 image entries */
+-              RFC1533_VENDOR_IMG,
+-              RFC1533_VENDOR_IMG+1,
+-              RFC1533_VENDOR_IMG+2,
+-              RFC1533_VENDOR_IMG+3,
+-              RFC1533_VENDOR_IMG+4,
+-              RFC1533_VENDOR_IMG+5,
+-              RFC1533_VENDOR_IMG+6,
+-              RFC1533_VENDOR_IMG+7,
+-              RFC1533_VENDOR_IMG+8,
+-              RFC1533_VENDOR_IMG+9,
+-              RFC1533_VENDOR_IMG+10,
+-              RFC1533_VENDOR_IMG+11,
+-              RFC1533_VENDOR_IMG+12,
+-              RFC1533_VENDOR_IMG+13,
+-              RFC1533_VENDOR_IMG+14,
+-              RFC1533_VENDOR_IMG+15,
+-      };
++#ifdef SERVER_IDENT
++      RFC1533_VENDOR_SERVER_IDENT,
++#endif
++      RFC1533_VENDOR_MNUOPTS, RFC1533_VENDOR_SELECTION,
++      /* 8 MOTD entries */
++      RFC1533_VENDOR_MOTD,
++      RFC1533_VENDOR_MOTD+1,
++      RFC1533_VENDOR_MOTD+2,
++      RFC1533_VENDOR_MOTD+3,
++      RFC1533_VENDOR_MOTD+4,
++      RFC1533_VENDOR_MOTD+5,
++      RFC1533_VENDOR_MOTD+6,
++      RFC1533_VENDOR_MOTD+7,
++      /* 16 image entries */
++      RFC1533_VENDOR_IMG,
++      RFC1533_VENDOR_IMG+1,
++      RFC1533_VENDOR_IMG+2,
++      RFC1533_VENDOR_IMG+3,
++      RFC1533_VENDOR_IMG+4,
++      RFC1533_VENDOR_IMG+5,
++      RFC1533_VENDOR_IMG+6,
++      RFC1533_VENDOR_IMG+7,
++      RFC1533_VENDOR_IMG+8,
++      RFC1533_VENDOR_IMG+9,
++      RFC1533_VENDOR_IMG+10,
++      RFC1533_VENDOR_IMG+11,
++      RFC1533_VENDOR_IMG+12,
++      RFC1533_VENDOR_IMG+13,
++      RFC1533_VENDOR_IMG+14,
++      RFC1533_VENDOR_IMG+15,
++};
+ #endif        /* NO_DHCP_SUPPORT */
+ static const char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+@@ -176,6 +217,55 @@ done:
+                       break;
+       }
+ #endif
++
++#ifdef SHIFTED_IDENT_INPUT
++      if (getshift() & 3)
++              {
++#endif
++      
++#ifdef  CLIENT_IDENT
++#   ifdef ASK_CLIENT_IDENT
++                      {
++                              char tmp_ident[9] = {};
++#      ifdef  DEFAULT_CLIENT_IDENT
++                              printf("Enter the client identifier (8 char max.) default [%s] : ",client_ident);
++#      else
++                              printf("Enter the client identifier (8 char max.) : ");
++#      endif
++                              getstr(tmp_ident,8);
++                              if (strlen(tmp_ident) != 0)
++                                      memcpy(client_ident,tmp_ident,8);
++                              else
++                                      printf("%s",client_ident);
++                              putchar('\n');
++                      }
++#   endif
++#endif
++
++#ifdef  SERVER_IDENT
++#   ifdef ASK_SERVER_IDENT
++                      {
++                              char tmp_ident[9] = {};
++#      ifdef  DEFAULT_SERVER_IDENT
++                              printf("Enter the server identifier (8 char max.) default [%s] : ",server_ident);
++#      else
++                              printf("Enter the server identifier (8 char max.) : ");
++#      endif
++                              getstr(tmp_ident,8);
++                              if (strlen(tmp_ident) != 0)
++                                      memcpy(server_ident,tmp_ident,8);
++                              else
++                                      printf("%s",server_ident);
++                              putchar('\n');
++                      }
++#   endif
++#endif
++
++#ifdef SHIFTED_IDENT_INPUT
++              }
++#endif
++
++      print_config();
+ #if   (TRY_FLOPPY_FIRST > 0) && defined(FLOPPY)
+       disk_init();
+       printf("Trying floppy");
+@@ -188,7 +278,7 @@ done:
+       }
+       printf("no floppy\n");
+ #endif        /* TRY_FLOPPY_FIRST && FLOPPY */
+-      print_config();
++        print_config();
+       gateA20_set();
+ #ifdef        EMERGENCYDISKBOOT
+       if (!eth_probe()) {
+@@ -663,6 +753,8 @@ BOOTP - Get my IP address and load infor
+ int bootp()
+ {
+       int retry;
++        int offset = 0;
++
+ #ifndef       NO_DHCP_SUPPORT
+       int retry1;
+ #endif        /* NO_DHCP_SUPPORT */
+@@ -680,11 +772,18 @@ int bootp()
+       bp.bp_xid = xid = starttime = currticks();
+       memcpy(bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+ #ifdef        NO_DHCP_SUPPORT
+-      memcpy(bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */
++      memcpy(bp.bp_vend+offset, rfc1533_cookie, 5); /* request RFC-style options */
++      offset += sizeof rfc1533_cookie;
+ #else
+-      memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
+-      memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover);
+-      memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end);
++      memcpy(bp.bp_vend+offset, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
++      offset += sizeof rfc1533_cookie;        
++      memcpy(bp.bp_vend+offset, dhcpdiscover, sizeof dhcpdiscover);
++      offset += sizeof dhcpdiscover;
++#ifdef CLIENT_IDENT 
++      memcpy(bp.bp_vend+13, client_ident, strlen(client_ident));
++#endif
++      memcpy(bp.bp_vend+offset, rfc1533_end, sizeof rfc1533_end);
++      offset += sizeof rfc1533_end;
+ #endif        /* NO_DHCP_SUPPORT */
+       for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
+@@ -715,19 +814,22 @@ int bootp()
+ #else
+               if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT)){
+                       if (dhcp_reply==DHCPOFFER){
+-              dhcp_reply=0;
+-              memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
+-              memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
+-              memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end);
+-              memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr));
+-              memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr));
+-                      for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) {
+-                      udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
+-                              sizeof(struct bootp_t), &bp);
+                               dhcp_reply=0;
+-                              if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
+-                                      if (dhcp_reply==DHCPACK)
+-                                              return(1);
++                              memcpy(bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
++                              memcpy(bp.bp_vend+sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
++                              memcpy(bp.bp_vend+sizeof rfc1533_cookie +sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end);
++                              memcpy(bp.bp_vend+9, &dhcp_server, sizeof(in_addr));
++                              memcpy(bp.bp_vend+15, &dhcp_addr, sizeof(in_addr));
++#ifdef CLIENT_IDENT
++                              memcpy(bp.bp_vend+21, client_ident, strlen(client_ident));
++#endif
++                              for (retry1 = 0; retry1 < MAX_BOOTP_RETRIES;) {
++                                      udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
++                                                   sizeof(struct bootp_t), &bp);
++                                      dhcp_reply=0;
++                                      if (await_reply(AWAIT_BOOTP, 0, NULL, TIMEOUT))
++                                              if (dhcp_reply==DHCPACK)
++                                                      return(1);
+                                       rfc951_sleep(++retry1);
+                               }
+                       } else
+@@ -750,6 +852,7 @@ AWAIT_REPLY - Wait until we get a respon
+ **************************************************************************/
+ int await_reply(int type, int ival, void *ptr, int timeout)
+ {
++      int result;
+       unsigned long time;
+       struct  iphdr *ip;
+       struct  udphdr *udp;
+@@ -757,6 +860,7 @@ int await_reply(int type, int ival, void
+       struct  bootp_t *bootpreply;
+       struct  rpc_t *rpc;
+       unsigned short ptype;
++      unsigned int min_packetlen;
+       unsigned int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
+                               sizeof(struct udphdr);
+@@ -766,35 +870,35 @@ int await_reply(int type, int ival, void
+        * needs a negligible amount of time.  */
+       for (;;) {
+               if (eth_poll()) {       /* We have something! */
+-                                      /* Check for ARP - No IP hdr */
++                      /* Check for ARP - No IP hdr */
+                       if (nic.packetlen >= ETHER_HDR_SIZE) {
+                               ptype = ((unsigned short) nic.packet[12]) << 8
+                                       | ((unsigned short) nic.packet[13]);
+                       } else continue; /* what else could we do with it? */
+                       if ((nic.packetlen >= ETHER_HDR_SIZE +
+-                              sizeof(struct arprequest)) &&
+-                         (ptype == ARP) ) {
++                           sizeof(struct arprequest)) &&
++                          (ptype == ARP) ) {
+                               unsigned long tmp;
+-
++                              
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
+-                                 !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
+-                                 (type == AWAIT_ARP)) {
++                                  !memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) &&
++                                  (type == AWAIT_ARP)) {
+                                       memcpy(arptable[ival].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       return(1);
+                               }
+                               memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                               if ((arpreply->opcode == ntohs(ARP_REQUEST)) &&
+-                                      (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
++                                  (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
+                                       arpreply->opcode = htons(ARP_REPLY);
+                                       memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->thwaddr, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
+                                       memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETHER_ADDR_SIZE);
+                                       eth_transmit(arpreply->thwaddr, ARP,
+-                                              sizeof(struct  arprequest),
+-                                              arpreply);
++                                                   sizeof(struct  arprequest),
++                                                   arpreply);
+ #ifdef        MDEBUG
+                                       memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
+                                       printf("Sent ARP reply to: %I\n",tmp);
+@@ -802,20 +906,20 @@ int await_reply(int type, int ival, void
+                               }
+                               continue;
+                       }
+-
++                      
+                       if (type == AWAIT_QDRAIN) {
+                               continue;
+                       }
+-
+-                                      /* Check for RARP - No IP hdr */
++                      
++                      /* Check for RARP - No IP hdr */
+                       if ((type == AWAIT_RARP) &&
+-                         (nic.packetlen >= ETHER_HDR_SIZE +
+-                              sizeof(struct arprequest)) &&
+-                         (ptype == RARP)) {
++                          (nic.packetlen >= ETHER_HDR_SIZE +
++                           sizeof(struct arprequest)) &&
++                          (ptype == RARP)) {
+                               arpreply = (struct arprequest *)
+                                       &nic.packet[ETHER_HDR_SIZE];
+                               if ((arpreply->opcode == ntohs(RARP_REPLY)) &&
+-                                 !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) {
++                                  !memcmp(arpreply->thwaddr, ptr, ETHER_ADDR_SIZE)) {
+                                       memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETHER_ADDR_SIZE);
+                                       memcpy(& arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
+                                       memcpy(& arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
+@@ -823,64 +927,72 @@ int await_reply(int type, int ival, void
+                               }
+                               continue;
+                       }
+-
+-                                      /* Anything else has IP header */
++                      
++                      /* Anything else has IP header */
+                       if ((nic.packetlen < protohdrlen) ||
+-                         (ptype != IP) ) continue;
++                          (ptype != IP) ) continue;
+                       ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((ip->verhdrlen != 0x45) ||
+-                              ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
+-                              (ip->protocol != IP_UDP)) continue;
++                          ipchksum((unsigned short *)ip, sizeof(struct iphdr)) ||
++                          (ip->protocol != IP_UDP)) continue;
+                       udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE +
+-                              sizeof(struct iphdr)];
+-
+-                                      /* BOOTP ? */
++                                                        sizeof(struct iphdr)];
++                      
++                      /* BOOTP ? */
+                       bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE];
+-                      if ((type == AWAIT_BOOTP) &&
+-                         (nic.packetlen >= (ETHER_HDR_SIZE +
+-#ifdef        NO_DHCP_SUPPORT
+-                           sizeof(struct bootp_t))) &&
++#ifdef  NO_DHCP_SUPPORT
++                      min_packetlen = ETHER_HDR_SIZE + sizeof(struct bootp_t);
+ #else
+-                           sizeof(struct bootp_t))-DHCP_OPT_LEN) &&
+-#endif        /* NO_DHCP_SUPPORT */
+-                         (ntohs(udp->dest) == BOOTP_CLIENT) &&
+-                         (bootpreply->bp_op == BOOTP_REPLY) &&
+-                         (bootpreply->bp_xid == xid)) {
+-                              arptable[ARP_CLIENT].ipaddr.s_addr =
+-                                      bootpreply->bp_yiaddr.s_addr;
++                      min_packetlen = ETHER_HDR_SIZE + sizeof(struct bootp_t) - DHCP_OPT_LEN;
++#endif
++                      if (
++                          (type == AWAIT_BOOTP) &&
++                          (nic.packetlen >= min_packetlen) &&
++                          (ntohs(udp->dest) == BOOTP_CLIENT) &&
++                          (bootpreply->bp_op == BOOTP_REPLY) &&
++                          (bootpreply->bp_xid == xid)
++                          ) {
++                              arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
+ #ifndef       NO_DHCP_SUPPORT
+                               dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
+ #endif        /* NO_DHCP_SUPPORT */
+                               netmask = default_netmask();
+-                              arptable[ARP_SERVER].ipaddr.s_addr =
+-                                      bootpreply->bp_siaddr.s_addr;
++                              arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
+                               memset(arptable[ARP_SERVER].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+-                              arptable[ARP_GATEWAY].ipaddr.s_addr =
+-                                      bootpreply->bp_giaddr.s_addr;
++                              arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
+                               memset(arptable[ARP_GATEWAY].node, 0, ETHER_ADDR_SIZE);  /* Kill arp */
+                               if (bootpreply->bp_file[0]) {
+                                       memcpy(kernel_buf, bootpreply->bp_file, 128);
+                                       kernel = kernel_buf;
+                               }
+                               memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
+-                              decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
+-#ifdef        NO_DHCP_SUPPORT
+-                                             0, BOOTP_VENDOR_LEN +
+-                                             MAX_BOOTP_EXTLEN, 1);
+-#else
+-                                             0, DHCP_OPT_LEN, 1);
+-#endif        /* NO_DHCP_SUPPORT */
+-                              return(1);
++#ifdef  NO_DHCP_SUPPORT
++                              if (decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
++                                                 0, BOOTP_VENDOR_LEN +
++                                                 MAX_BOOTP_EXTLEN, 1)) {
++                                      return(1);
++                              }
++                              else {
++                                      continue;
++                              }
++#else 
++                              if (decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend,
++                                                 0, DHCP_OPT_LEN, 1)) {
++                                      return(1);
++                              }
++                              else {
++                                      continue;
++                              }
+                       }
+-
++#endif        /* NO_DHCP_SUPPORT */
+ #ifdef        DOWNLOAD_PROTO_TFTP
+-                                      /* TFTP ? */
++                      /* TFTP ? */
+                       if ((type == AWAIT_TFTP) &&
+-                              (ntohs(udp->dest) == ival)) return(1);
++                          (ntohs(udp->dest) == ival)) return(1);
+ #endif        /* DOWNLOAD_PROTO_TFTP */
+-
++                      
+ #ifdef        DOWNLOAD_PROTO_NFS
+-                                      /* RPC ? */
++                      /* RPC ? */
+                       rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE];
+                       if ((type == AWAIT_RPC) &&
+                           (ntohs(udp->dest) == ival) &&
+@@ -889,19 +1001,19 @@ int await_reply(int type, int ival, void
+                               return (1);
+                       }
+ #endif        /* DOWNLOAD_PROTO_NFS */
+-
++                      
+               } else {
+-                      /* Check for abort key only if the Rx queue is empty -
+-                       * as long as we have something to process, don't
+-                       * assume that something failed.  It is unlikely that
+-                       * we have no processing time left between packets.  */
++                              /* Check for abort key only if the Rx queue is empty -
++                               * as long as we have something to process, don't
++                               * assume that something failed.  It is unlikely that
++                               * we have no processing time left between packets.  */
+                       if (iskey() && (getchar() == ESC))
+ #ifdef        EMERGENCYDISKBOOT
+                               exit(0);
+ #else
+-                              longjmp(jmp_bootmenu,1);
++                      longjmp(jmp_bootmenu,1);
+ #endif
+-                      /* Do the timeout after at least a full queue walk.  */
++                              /* Do the timeout after at least a full queue walk.  */
+                       if ((timeout == 0) || (currticks() > time)) {
+                               break;
+                       }
+@@ -914,13 +1026,15 @@ int await_reply(int type, int ival, void
+ DECODE_RFC1533 - Decodes RFC1533 header
+ **************************************************************************/
+ int decode_rfc1533(p, block, len, eof)
+-      register unsigned char *p;
+-      int block, len, eof;
++        register unsigned char *p;
++        int block, len, eof;  
+ {
+       static unsigned char *extdata = NULL, *extend = NULL;
+       unsigned char        *extpath = NULL;
+       unsigned char        *endp;
+-
++#ifdef SERVER_IDENT
++      char rcvd_server_ident[9] = {};
++#endif
+       if (block == 0) {
+ #ifdef        IMAGE_MENU
+               memset(imagelist, 0, sizeof(imagelist));
+@@ -1002,11 +1116,16 @@ int decode_rfc1533(p, block, len, eof)
+                       }
+ #endif
+ #ifdef        MOTD
+-                      else if (c >= RFC1533_VENDOR_MOTD &&
++                        else if (c >= RFC1533_VENDOR_MOTD &&
+                                c < RFC1533_VENDOR_MOTD +
+                                RFC1533_VENDOR_NUMOFMOTD)
+                               motd[c - RFC1533_VENDOR_MOTD] = p;
+ #endif
++#ifdef SERVER_IDENT 
++                      else if (c == RFC1533_VENDOR_SERVER_IDENT) {
++                              memcpy(rcvd_server_ident,p+2,TAG_LEN(p));
++                      }
++#endif
+                       else {
+ #if   0
+                               unsigned char *q;
+@@ -1018,6 +1137,30 @@ int decode_rfc1533(p, block, len, eof)
+                       }
+                       p += TAG_LEN(p) + 2;
+               }
++#if defined(SERVER_IDENT) && defined(DBG_IDENT)
++              if (strcasecmp(rcvd_server_ident,server_ident)) {
++                      char ip[16];
++
++                      inet_ntoa(dhcp_server,ip);
++                      printf("[%s]: Option %d (%s), invalid response. Wanted (%s).\n",
++                             ip,
++                             RFC1533_VENDOR_SERVER_IDENT,
++                             rcvd_server_ident,
++                             server_ident);
++                      strcpy(rcvd_server_ident,"");
++                      return(0);
++              }
++              else {
++                      char ip[16];
++
++                      inet_ntoa(dhcp_server,ip);
++                      printf("[%s]: Option %d (%s), valid response.\n",
++                             ip,
++                             RFC1533_VENDOR_SERVER_IDENT,
++                             rcvd_server_ident);
++                      strcpy(rcvd_server_ident,"");
++              }
++#endif
+               extdata = extend = endp;
+               if (block == 0 && extpath != NULL) {
+                       char fname[64];
+@@ -1103,3 +1246,4 @@ void cleanup(void)
+  *  c-basic-offset: 8
+  * End:
+  */
++
+
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="misc.c.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="misc.c.diff"
+
+--- etherboot-4.6.0/src/misc.c Tue Apr 25 08:30:25 2000
++++ etherboot-4.5.6-new/src/misc.c     Wed Apr 26 16:26:38 2000
+@@ -140,9 +140,11 @@ void printf(const char *fmt, ...)
+ #ifdef        IMAGE_MENU
+ /**************************************************************************
+-INET_ATON - Convert an ascii x.x.x.x to binary form
++INET_NTOA - Convert an ascii x.x.x.x to binary form
+ **************************************************************************/
+-int inet_aton(char *p, in_addr *i)
++int inet_aton(p, i)
++      char *p;
++      in_addr *i;
+ {
+       unsigned long ip = 0;
+       int val;
+@@ -165,7 +167,19 @@ int inet_aton(char *p, in_addr *i)
+ #endif        /* IMAGE_MENU */
+-int getdec(char **ptr)
++#if  defined(CLIENT_IDENT) || defined (SERVER_IDENT)
++/**************************************************************************
++INET_NTOA - Convert a binary form to an ascii x.x.x.x form
++**************************************************************************/
++char *inet_ntoa(in_addr i, char *p)
++{
++      sprintf(p,"%d.%d.%d.%d",i.s_addr>>24,i.s_addr<<8>>24,i.s_addr<<16>>24,i.s_addr<<24>>24);
++      return p;
++}
++#endif
++
++int getdec(ptr)
++      char **ptr;
+ {
+       char *p = *ptr;
+       int ret=0;
+@@ -308,6 +322,45 @@ iskey(void)
+       return 0;
+ }
+ #endif        /* ETHERBOOT32 */
++
++/**************************************************************************
++GETSTR - Read a string of size bytes from the keyboard 
++(without echoing the final return)
++**************************************************************************/
++void getstr(char *s, int size)
++{
++   int i=0;
++   char c;
++
++   while(1) {
++      c = getc();
++        
++                          
++      if (c == 13)
++         {
++         s[i]='\0';
++         break;
++         }
++      else if ( 
++              ((c >= 'a') && (c <='z')) ||  
++              ((c >= 'A') && (c <='Z')) ||
++              ((c >= '0') && (c <='9'))
++            ) {
++                 if (i==8) {
++                     putchar(8);
++                     putchar(s[i-1]=c);
++                  }
++                  else
++                     putchar(s[i++]=c);      
++                }
++     else if ( c == 8 ) {   
++         if (i != 0) {
++                 --i;
++                 s[i]='\0';
++                 putchar(8);
++                 putchar(32);
++                 putchar(8);
++         }
++     }
++   }
++}
+ /*
+  * Local variables:
+
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="Config.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="Config.diff"
+
+--- etherboot-4.6.0/src/Config Tue Apr 25 08:30:57 2000
++++ etherboot-4.5.6-new/src/Config     Wed Apr 26 15:55:57 2000
+@@ -59,6 +59,27 @@
+ #                       may no longer be appropriate.  You might need to set
+ #                       MAX_ARP_RETRIES, MAX_BOOTP_RETRIES, MAX_TFTP_RETRIES
+ #                       and MAX_RPC_RETRIES to a larger value.
++#     -DDEFAULT_CLIENT_IDENT
++#                       The default client identifier that is sent to the
++#                       DHCP server to identify itself. 
++#     -DDEFAULT_SERVER_IDENT
++#                       The expected response that the client will wait
++#                       for when a DHCP server responds to the the initial
++#                       client discovery.
++#     -DASK_CLIENT_IDENT
++#     -DASK_SERVER_IDENT
++#                       If these are set, the boot process will include
++#                       a question period where you can manualy specify
++#                       the client and/or server identifiers.
++#     -DSHIFTED_IDENT_INPUT
++#                       If this is set then the boot process will only
++#                       ask for the identifiers if one of the shift keys
++#                       is pressed. Else it will send the default identifiers
++#                       automatically
++#     -DDBG_IDENT
++#                       This will give show all the DHCP responses with
++#                       their identifiers.
++#                       
+ #
+ # Etherboot/32 only options:
+ #     -DAOUT_IMAGE    - Add a.out kernel boot support (generic)
+@@ -147,6 +168,14 @@ CFLAGS32+=        -DASK_BOOT=3 -DANS_DEFAULT=AN
+ # Change download protocol to NFS.  Only available for Etherboot/32 for now.
+ # CFLAGS32+=  -DDOWNLOAD_PROTO_NFS
++
++# If you have more than one DHCP server you might want to
++# enable these to be able to sort out which one you want to
++# respond to.  
++CFLAGS32+= -DDEFAULT_CLIENT_IDENT=\"BOOT\" -DDEFAULT_SERVER_IDENT=\"BOOT\"
++CFLAGS32+= -DASK_CLIENT_IDENT -DASK_SERVER_IDENT
++CFLAGS32+= -DSHIFTED_IDENT_INPUT
++CFLAGS32+= -DDBG_IDENT 
+ # These flags affect the loader that is prepended to the Etherboot image
+ LCONFIG+=     -DMOVEROM
+
+--------------4734FDA0BF2F2FBDF8EB8DF6
+Content-Type: text/plain; charset=us-ascii;
+ name="etherboot.h.diff"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline;
+ filename="etherboot.h.diff"
+
+--- etherboot-4.6.0/src/etherboot.h    Tue Apr 25 08:30:55 2000
++++ etherboot-4.5.6-new/src/etherboot.h        Wed Apr 26 16:07:16 2000
+@@ -8,6 +8,14 @@ Author: Martin Renters
+ #include "osdep.h"
++#if (! defined(NO_DHCP_SUPPORT)) && (defined(ASK_CLIENT_IDENT) || defined(DEFAULT_CLIENT_IDENT))
++#   define CLIENT_IDENT
++#endif
++
++#if (! defined(NO_DHCP_SUPPORT)) && (defined(ASK_SERVER_IDENT) || defined(DEFAULT_SERVER_IDENT))
++#   define SERVER_IDENT
++#endif
++
+ /* These could be customised for different languages perhaps */
+ #define       ASK_PROMPT      "Boot from (N)etwork or from (L)ocal? "
+ #define       ANS_NETWORK     'N'
+@@ -224,6 +232,12 @@ Author: Martin Renters
+ #ifdef        IMAGE_FREEBSD
+ #define RFC1533_VENDOR_HOWTO    132
+ #endif
++#ifdef CLIENT_IDENT
++#define RFC1533_VENDOR_CLIENT_IDENT    208
++#endif
++#ifdef SERVER_IDENT
++#define RFC1533_VENDOR_SERVER_IDENT    208
++#endif
+ #define RFC1533_VENDOR_MNUOPTS        160
+ #define RFC1533_VENDOR_SELECTION 176
+ #define RFC1533_VENDOR_MOTD   184
+@@ -477,11 +491,13 @@ extern int getdec P((char **));
+ extern void printf P((const char *, ...));
+ extern char *sprintf P((char *, const char *, ...));
+ extern int inet_aton P((char *p, in_addr *i));
++extern char *inet_ntoa P((in_addr i, char *p));
+ extern void gateA20_set P((void));
+ extern void gateA20_unset P((void));
+ extern void putchar P((int));
+ extern int getchar P((void));
+ extern int iskey P((void));
++extern void getstr P((char *s, int size));
+ /* start*.S */
+ extern int getc P((void));
+@@ -528,8 +544,10 @@ extern int hostnamelen;
+ extern unsigned long netmask;
+ extern int jmp_bootmenu[10];
+ extern struct arptable_t arptable[MAX_ARP];
+-#ifdef        IMAGE_MENU
++#ifdef MOTD
+ extern char *motd[RFC1533_VENDOR_NUMOFMOTD];
++#endif
++#ifdef        IMAGE_MENU
+ extern int menutmo,menudefault;
+ extern unsigned char *defparams;
+ extern int defparams_max;
+
+--------------4734FDA0BF2F2FBDF8EB8DF6--
+
diff --git a/contrib/eepro100notes/flash-1.txt b/contrib/eepro100notes/flash-1.txt
new file mode 100644 (file)
index 0000000..61579b4
--- /dev/null
@@ -0,0 +1,73 @@
+Date: Tue, 18 May 1999 15:45:55 +0200 (MEST)
+From: Erik Starback <erik@math.uu.se>
+To: netboot@baghira.han.de
+Subject: Netboot with Intel EEPRO100+ Management
+Message-ID: <Pine.LNX.3.96.990518154313.3875A-100000@anarchy.math.uu.se>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=iso-8859-1
+Content-Transfer-Encoding: 8BIT
+Sender: owner-netboot@baghira.han.de
+Precedence: bulk
+Reply-To: netboot@baghira.han.de
+X-Moderator: netboot-owner@baghira.han.de
+X-UIDL: 6ca8453c19c46d622813e9be8ada9517
+Status: O
+X-Status: 
+
+Hello!
+
+When Intel eepro100+ NIC disappeared from the market, I didn't know
+what to do. I didn't find any information if anyone has used the
+new eepro100+ Management Adapter to netboot linux. 
+
+I thought that the card should netboot with the same configuration as
+the old card when I read Donald Beckers comment:
+> The driver should "just work" with the '559. It's not supposed to be
+> substantially different than the '558. (I don't have a datasheet
+> or sample card to confirm this statement.)
+
+The problem was now only to put the netboot-program to the built in
+flash memory on the NIC. With the old card I used a flash memory (Intel
+N28F020 [N28010 didn't work])) and the program FUTIL.EXE from Intel to
+flash it. FUTIL did't recognize the memory on the management card
+and did not work therefore.
+
+I found the intel program FBOOT.EXE that was made to upgrade the built
+in Intel BOOT agent. I did: Boot dos from floppy, Run FBOOT (choose
+adapter), choose (u)pdate, choose Create restore image, rename the
+backup file (in my case 2743BE52.FLS [the eight last hex digits from
+the MAC address]), rename your netboot code (in my case netboot 0.8.1)
+to the backup files original name (in my case 2743BE52.FLS), run
+FBOOT, choose (r)estore.
+
+Voila!
+
+A shorter way (if you don't need the backup of the old Intel BOOT
+agent code) is of course: rename netboot file to [the eight last hex
+digits from the MAC address].FLS, run FBOOT, choose restore.
+Caution: I think it is possible to make a NIC unusable if you have
+made the netboot (or etherboot) file with "wrong" parameters. A couple
+of month ago I did a etherboot boot file and put it on an old
+EEPRO100+ card. It worked fine, but it was impossible to boot local
+with it. So I could not boot dos and with FUTIL or FBOOT erase the
+flash memory!  To erase the chip I had to take out the memory chip,
+boot dos and then put in the memory chip. This isn't possible when the
+memory chip is build in.
+
+Links:
+<http://support.intel.com/support/landesk/configmgr/LSA1_193.HTM>
+FUTIL.EXE  is a part of LSA1_193.ZIP
+
+<http://support.intel.com/support/etherexpress/pro100/100pboot.htm>
+FBOOT.EXE is a part of 100pboot.exe
+
+/Erik S
+
+-------------------------------------------------------------------------
+Erik Starbäck, System administrator    E-mail address:    erik@math.uu.se
+Uppsala University                     Telephone (o):     +46 18 4713277
+Department of Mathematics              Cellular phone:    +46 70 4250260
+P. O. Box 480                          Fax (o):           +46 18 4713201
+SE-751 06  UPPSALA                  
+Sweden                                
diff --git a/contrib/eepro100notes/flash-2.txt b/contrib/eepro100notes/flash-2.txt
new file mode 100644 (file)
index 0000000..1128c30
--- /dev/null
@@ -0,0 +1,149 @@
+Subject: Look Mom, no PROM burner! (eepro100b flashing instructions) :-)
+Date: Sun, 23 Jan 2000 01:53:08 -0500
+x-sender: mdc%thinguin.org@cdi.entity.com
+x-mailer: Claris Emailer 2.0v3, January 22, 1998
+From: Marty Connor <mdc@thinguin.org>
+To: "Netboot List" <netboot@baghira.han.de>
+Mime-Version: 1.0
+Content-Type: text/plain; charset="US-ASCII"
+Message-ID: <1263512144-341319205@entity.com>
+
+Continuing the Etherboot World Domination theme, I noticed that there was 
+a PCI ethernet card on my bookshelf that still contained the original 
+vendor's code in its flash memory.  The card virtually cried out to be 
+flashed with Etherboot 4.4.1. :-)
+
+After having figured out how to flash the 3C905C last week, and owing to 
+the fact that the temperature here in Cambridge, Massachusetts (USA) has 
+dropped well below freezing, I decided to explore the possibility of 
+flashing the Intel eepro100b that was sitting on my bookcase.
+
+After determining that it was unlikely that one could flash the chip in 
+user mode under linux like the 3C509C,  I turned to other options.  (the 
+reason is that the flash is memory mapped to a place that causes a core 
+dump if accessed.  i suppose one could to patch the kernel to flash the 
+card, or add a linux device driver, but... :-)  
+
+By the way, If you are ever looking for Linux utilities for Ethernet 
+cards, you may want to check out: 
+
+   http://cesdis.gsfc.nasa.gov/linux/diag/
+
+which is a treasure trove of tools for manipulating and testing Ethernet 
+cards, all with source, courtesy of Donald Becker.
+
+At this point, I felt it was time to make a virtual trip to the Intel 
+site (http://www.intel.com/), and search for utilities that might work 
+with the eepro100B.  I found two candidates:  FUTIL and FBOOT.  I 
+downloaded, decompressed, and transferred them to a DOS formatted floppy. 
+Next I determined (after a few tries) that F8 will let me get to DOS 
+instead of booting windows. (I tend to avoid Windows when I can).
+
+I first tried FUTIL.EXE.  No good.  It told me it didn't recognize the 
+flash on my eepro100B.  how unfortunate.  and I had such hopes :-)
+
+Next I tested FBOOT.EXE  (available at 
+http://support.intel.com/support/network/adapter/pro100/100PBOOT.htm)  
+This program did in fact recognize my eepro100b card.
+
+The thing about FBOOT however, is that it thinks it only can load certain 
+files.  I of course needed to load an Etherboot image.  It appeared to 
+have no option for doing that.  Things looked grim.
+
+Then I noticed that FBOOT was kind enough to do the following dialog:
+
+   Select Option (U)pdate or (R)estore: U
+
+I chose Update and it then offered to back up my flash rom for later 
+restore:
+
+   Create Restore Image (Y)es or (N)o: Y
+
+I chose "Y" and it proceeded to write a file of my flash memory, which 
+contained the Intel code.
+
+   Writing FLASH image to file... 100%
+
+It then erased the device:
+
+   Erasing FLASH Device... 100%
+
+and then programmed it with fresh code (stored inside the program, no 
+doubt):
+
+   Programming FLASH Device... 100%
+
+So now I had a backup of the Intel boot code in a file strangely called:
+
+   2794FC60.FLS
+
+Hmmmm, interesting name.  The MAC address of the card is 09902794FC60.  
+They just name the file with the last 4 octets of the MAC address and 
+.FLS.  The file is exactly 65536 bytes, which would make sense for a 64K 
+Flash Memory device.
+
+Then I got to thinking, I wonder how carefully the "restore" part of 
+FBOOT looks at what it is loading?  What if I took an Etherboot .rom 
+file, padded it with 48K of 0xFFs and named it 2794FC60.FLS.  What if I 
+then told FBOOT.EXE to "restore" that?
+
+Well, I guess by now, you know it worked :-) 
+
+The card came up with the delightful Etherboot banner, Did DHCP, tftp, 
+and started a kernel.
+
+The only unfortunate part is that you need to do this under DOS because 
+you seem to need to be in real mode to program the card.  Oh well, 
+sacrifices have to be made :-)
+
+So, in summary, to prepare Etherboot image for flashing into the Intel 
+EEPRO100B card with FBOOT, you need to first make an eepro100.rom file, 
+as usual.
+
+Then, see how large it is, with an "ls -l eepro100.rom". the answer will 
+probably be 16,384.  You need to pad it with hex FFs to make it 64K for 
+FBOOT.  I used the following two lines to create the flash image file.
+
+   $ perl -e 'print "\xFF" x 49152' > 48kpad.bin
+   $ cat eepro100.rom 48kpad.bin > 2794FC60.FLS
+
+Next write it to a DOS Floppy:
+
+   $ mount -t msdos /dev/fd0 /mnt/floppy
+   $ cp 2794FC60.FLS /mnt/floppy
+   $ umount /mnt/floppy
+
+Now you need to get to DOS.  You could actually use a bootable DOS floppy 
+with FBOOT.EXE and 2794FC60.FLS on it.  I started a Windows box and hit 
+F8 right before Windows started, and chose option 5, "Command Prompt 
+Only", which gives you DOS.  This program can't run in a DOS window under 
+Windows or anything like that.  You need to be in real DOS.
+
+Next it's time to run FBOOT.  It will detect your ethernet card(s), ask 
+you which one you want to program, and let you choose it from a menu.
+
+now the fun part:
+
+   Select Option (U)pdate or (R)estore: R
+   Erasing FLASH Device... 100%
+   Writing FLASH image from file... 100%
+
+Time to reboot and let Etherboot take over.
+
+So there you go, a way to make Intel EEPRO100Bs play nicely with 
+Etherboot.  Maybe we should put these instructions in the Etherboot 
+contrib directory so people who have eepro100b cards will be able to 
+avoid 3C905C envy :-)
+
+I hope this helps a few people out.
+
+Regards,
+
+Marty
+
+---
+   Name: Martin D. Connor
+US Mail: Entity Cyber, Inc.; P.O. Box 391827; Cambridge, MA 02139; USA
+  Voice: (617) 491-6935, Fax: (617) 491-7046 
+  Email: mdc@thinguin.org
+    Web: http://www.thinguin.org/
diff --git a/contrib/eepro100notes/flash-3.txt b/contrib/eepro100notes/flash-3.txt
new file mode 100644 (file)
index 0000000..1a865a4
--- /dev/null
@@ -0,0 +1,57 @@
+Date: Sun, 23 Jan 2000 09:47:15 +0100 (MET)
+From: Erik Starbäck <erik@math.uu.se>
+To: Netboot List <netboot@baghira.han.de>
+Subject: Re: Look Mom, no PROM burner! (eepro100b flashing instructions) :-)
+In-Reply-To: <1263512144-341319205@entity.com>
+Message-ID: <Pine.LNX.3.96.1000123094505.28562A-100000@anarchy.math.uu.se>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=iso-8859-1
+Content-Transfer-Encoding: 8BIT
+Sender: owner-netboot@baghira.han.de
+Precedence: bulk
+Reply-To: netboot@baghira.han.de
+X-Moderator: netboot-owner@baghira.han.de
+
+
+Hello!
+
+In <http://www.han.de/~gero/netboot/archive/msg01718.html> I wrote what I
+did know about futil and fboot then. It is about the same as Martys
+instructions, but I have a few comments now.
+
+> Then, see how large it is, with an "ls -l eepro100.rom". the answer will 
+> probably be 16,384.  You need to pad it with hex FFs to make it 64K for 
+> FBOOT.  I used the following two lines to create the flash image file.
+
+>   $ perl -e 'print "\xFF" x 49152' > 48kpad.bin
+>   $ cat eepro100.rom 48kpad.bin > 2794FC60.FLS
+
+It worked for me without any padding. When I burned a smaller image
+the program printed 50% instead of 100% and then it
+stopped. Everything worked anyway.
+
+
+I also did a brutal way of install etherboot or netboot on a
+EEPRO100+Mng without creating a file of type "2794FC60.FLS" for
+every card. It was necessary for me when I installed 70 clients...
+
+I chopped the binary file fboot.exe (my version was 99811 bytes, I
+don't remember the version name) in three parts:
+
+fboot1 30096 bytes
+fboot2 65536 bytes
+fboot3 4179  bytes
+
+Then you cat put them together again, but with a different part 2 and
+save it as fbootown.exe and execute it. It worked for me anyway. Of
+course you have to use padding to get a 64k part instead of fboot2.
+
+/Erik S
+
+-------------------------------------------------------------------------
+Erik Starbäck, System administrator    E-mail address:    erik@math.uu.se
+Uppsala University                     Telephone (o):     +46 18 4713277
+Department of Mathematics              Cellular phone:    +46 70 4250260
+P. O. Box 480                          Fax (o):           +46 18 4713201
+SE-751 06  UPPSALA                  
+Sweden                                
diff --git a/contrib/flashimg/Makefile b/contrib/flashimg/Makefile
new file mode 100644 (file)
index 0000000..39f58e2
--- /dev/null
@@ -0,0 +1,29 @@
+CPPFLAGS       = -x assembler-with-cpp
+AS86           = as86
+LD86           = ld86
+OBJDUMP                = objdump
+
+.SUFFIXES:     .s86 .asm .aout .img
+
+all:   flashimg.img
+
+clean:
+       rm -rf *.o *.s86 *.aout *.img
+
+realclean: clean
+       rm -rf *.img
+
+.asm.s86: $*.asm $*.inc
+         $(CPP) $(CPPFLAGS) -o $@ $*.asm
+
+.s86.img: $*.s86
+         $(AS86) -0 -b $@ $*.s86
+
+# .s86.o:      $*.s86
+#        $(AS86) -0 -a -o $@ $*.s86
+# 
+# .o.aout: $*.o
+#        $(LD86) -0 -s -o $@ $*.o
+# 
+# .aout.img:
+#        dd if=$*.aout of=$@ bs=32 skip=1
diff --git a/contrib/flashimg/flashimg.asm b/contrib/flashimg/flashimg.asm
new file mode 100644 (file)
index 0000000..7a37ed5
--- /dev/null
@@ -0,0 +1,497 @@
+; Copyright (C) 1997 Markus Gutschke <gutschk@uni-muenster.de>
+;
+; 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
+; any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, write to the Free Software
+; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+; Prepend this image file to an arbitrary ROM image. The resulting binary
+; can be loaded from any BOOT-Prom that supports the "nbi" file format.
+; When started, the image will reprogram the flash EPROM on the FlashCard
+; ISA card. The flash EPROM has to be an AMD 29F010, and the programming
+; algorithm is the same as that suggested by AMD in the appropriate data
+; sheets.
+
+
+#define SEGLOW         0xC800          /* lower range for EPROM segment     */
+#define SEGHIGH                0xE800          /* upper range for EPROM segment     */
+#define AMD_ID         0x2001          /* flash EPROM ID, only support AMD  */
+#define ERASE1_CMD     0x80            /* first cmd for erasing full chip   */
+#define ERASE2_CMD     0x10            /* second cmd for erasing full chip  */
+#define READID_CMD     0x90            /* cmd to read chip ID               */
+#define PROG_CMD       0xA0            /* cmd to program a byte             */
+#define RESET_CMD      0xF0            /* cmd to reset chip state machine   */
+
+;----------------------------------------------------------------------------\f
+
+
+       .text
+       .org    0
+
+;      .globl  _main
+_main: mov     ax,#0x0FE0
+       mov     ds,ax
+       mov     ax,magic                ; verify that we have been loaded by
+       cmp     ax,#0xE4E4              ; boot prom
+       jnz     lderr
+       jmpi    0x200,0x0FE0            ; adjust code segment
+lderr: mov     si,#loaderr
+       cld
+lderrlp:seg    cs
+       lodsb                           ; loop over all characters of
+       or      al,al                   ; string
+       jnz     lderrnx
+       xor     ah,ah
+       int     0x16                    ; wait for keypress
+       jmpi    0x0000,0xFFFF           ; reboot!
+lderrnx:mov    ah,#0x0E                ; print it
+       mov     bl,#0x07
+       xor     bh,bh
+       int     0x10
+       jmp     lderrlp
+
+loaderr:.ascii "The flash EPROM utility has to be loaded from a BOOT-Prom"
+       .byte   0xa,0xd
+       .ascii  "that knows about the 'nbi' file format!"
+       .byte   0xa,0xd
+       .ascii  "Reboot to proceed..."
+       .byte   0
+
+       .org    510
+       .byte   0x55,0xAA
+
+!----------------------------------------------------------------------------\f
+
+start: mov     ax,cs
+       mov     ds,ax
+       mov     ax,romdata              ; verify that there is an Prom image
+       cmp     ax,#0xAA55              ; attached to the utility
+       jnz     resmag
+       mov     al,romdata+2
+       or      al,al                   ; non-zero size is required
+       jnz     magicok
+resmag:        mov     si,#badmagic            ; print error message
+reset: call    prnstr
+       xor     ah,ah
+       int     0x16                    ; wait for keypress
+       jmpi    0x0000,0xFFFF           ; reboot!
+magicok:mov    di,#clrline1
+       mov     si,#welcome             ; print welcome message
+inpnew:        call    prnstr
+inprest:xor    bx,bx
+       mov     cl,#0xC                 ; expect 4 nibbles input data
+inploop:xor    ah,ah
+       int     0x16
+       cmp     al,#0x8                 ; <Backspace>
+       jnz     inpnobs
+       or      bx,bx                   ; there has to be at least one input ch
+       jz      inperr
+       mov     si,#delchar             ; wipe out char from screen
+       call    prnstr
+       add     cl,#4                   ; compute bitmask for removing input
+       mov     ch,cl
+       mov     cl,#0xC
+       sub     cl,ch
+       mov     ax,#0xFFFF
+       shr     ax,cl
+       not     ax
+       and     bx,ax
+       mov     cl,ch
+inploop1:jmp   inploop
+inpnobs:cmp    al,#0x0D                ; <Return>
+       jnz     inpnocr
+       or      bx,bx                   ; zero input -> autoprobing
+       jz      inpdone
+       cmp     cl,#-4                  ; otherwise there have to be 4 nibbles
+       jz      inpdone
+inperr:        mov     al,#7                   ; ring the console bell
+       jmp     inpecho
+inpnocr:cmp    al,#0x15                ; <CTRL-U>
+       jnz     inpnokl
+       mov     si,di
+       call    prnstr                  ; clear entire input and restart
+       jmp     inprest
+inpnokl:cmp    cl,#-4                  ; cannot input more than 4 nibbles
+       jz      inperr
+       cmp     al,#0x30                ; '0'
+       jb      inperr
+       ja      inpdig
+       or      bx,bx                   ; leading '0' is not allowed
+       jz      inperr
+inpdig:        cmp     al,#0x39                ; '9'
+       ja      inpnodg
+       mov     ch,al
+       sub     al,#0x30
+inpnum:        xor     ah,ah                   ; compute new input value
+       shl     ax,cl
+       add     ax,bx
+       test    ax,#0x1FF               ; test for 8kB boundary
+       jnz     inperr
+       cmp     ax,#SEGHIGH             ; input has to be below E800
+       jae     inperr
+       cmp     ax,#SEGLOW              ; and above/equal C800
+       jae     inpok
+       cmp     cl,#0xC                 ; if there is just one nibble, yet,
+       jnz     inperr                  ;   then the lower limit ix C000
+       cmp     ax,#0xC000
+       jb      inperr
+inpok: mov     bx,ax                   ; adjust bitmask
+       sub     cl,#4
+       mov     al,ch
+inpecho:call   prnchr                  ; output new character
+       jmp     inploop1
+inpnodg:and    al,#0xDF                ; lower case -> upper case
+       cmp     al,#0x41                ; 'A'
+       jb      inperr
+       cmp     al,#0x46                ; 'F'
+       ja      inperr
+       mov     ch,al
+       sub     al,#0x37
+       jmp     inpnum
+inpdone:or     bx,bx                   ; zero -> autoprobing
+       jnz     probe
+       mov     si,#automsg
+       call    prnstr
+       mov     cx,#0x10
+       mov     bx,#SEGHIGH             ; scan from E800 to C800
+autoprb:sub    bx,#0x0200              ; stepping down in 8kB increments
+       mov     di,bx
+       call    readid
+       cmp     ax,#AMD_ID
+       jz      prbfnd
+       loop    autoprb
+       mov     si,#failmsg
+nofnd: mov     di,#clrline2
+       jmp     near inpnew             ; failure -> ask user for new input
+probe: mov     di,bx
+       test    bx,#0x07FF              ; EPROM might have to be aligned to
+       jz      noalign                 ;   32kB boundary
+       call    readid
+       cmp     ax,#AMD_ID              ; check for AMDs id
+       jz      prbfnd
+       mov     si,#alignmsg
+       call    prnstr
+       and     bx,#0xF800              ; enforce alignment of hardware addr
+noalign:call   readid                  ; check for AMDs id
+       cmp     ax,#AMD_ID
+       jz      prbfnd
+       mov     si,#nofndmsg            ; could not find any EPROM at speci-
+       call    prnstr                  ;   fied location --- even tried
+       mov     si,#basemsg             ;   aligning to 32kB boundary
+       jmp     nofnd                   ; failure -> ask user for new input
+prbfnd:        mov     si,#fndmsg
+       call    prnstr                  ; we found a flash EPROM
+       mov     ax,bx
+       call    prnwrd
+       mov     si,#ersmsg
+       call    prnstr
+       call    erase                   ; erase old contents
+       jnc     ersdone
+       mov     si,#failresmsg          ; failure -> reboot machine
+       jmp     near reset
+ersdone:mov    si,#prg1msg             ; tell user that we are about
+       call    prnstr                  ;   to program the new data into
+       mov     ax,di                   ;   the specified range
+       call    prnwrd
+       mov     si,#prg2msg
+       call    prnstr
+       xor     dh,dh
+       mov     dl,romdata+2
+       shl     dx,#1
+       mov     ah,dh
+       mov     cl,#4
+       shl     ah,cl
+       xor     al,al
+       add     ax,di
+       call    prnwrd
+       mov     al,#0x3A                ; ':'
+       call    prnchr
+       mov     ah,dl
+       xor     al,al
+       dec     ax
+       call    prnwrd
+       mov     al,#0x20
+       call    prnchr
+       mov     dh,romdata+2            ; number of 512 byte blocks
+       push    ds
+       mov     ax,ds
+       add     ax,#romdata>>4          ; adjust segment descriptor, so that
+       mov     ds,ax                   ;   we can handle images which are
+prgloop:mov    cx,#0x200               ;   larger than 64kB
+       xor     si,si
+       xor     bp,bp
+       call    program                 ; program 512 data bytes
+       jc      prgerr                  ; check error condition
+       mov     ax,ds
+       add     ax,#0x20                ; increment segment descriptors
+       mov     ds,ax
+       add     di,#0x20
+       dec     dh                      ; decrement counter
+       jnz     prgloop
+       pop     ds
+       mov     si,#donemsg             ; success -> reboot
+prgdone:call   prnstr
+       mov     si,#resetmsg
+       jmp     near reset
+prgerr:        pop     ds                      ; failure -> reboot
+       mov     si,#failresmsg
+       jmp     prgdone
+
+
+;----------------------------------------------------------------------------\f
+
+; READID -- read EPROM id number, base address is passed in BX
+; ======
+;
+; changes: AX, DL, ES
+
+readid:        mov     dl,#RESET_CMD           ; reset chip
+       call    sendop
+       mov     dl,#READID_CMD
+       call    sendop                  ; send READID command
+       mov     es,bx
+       seg     es
+       mov     ax,0x00                 ; read manufacturer ID
+       mov     dl,#RESET_CMD
+       jmp     sendop                  ; reset chip
+
+
+;----------------------------------------------------------------------------\f
+
+; ERASE -- erase entire EPROM, base address is passed in BX
+; =====
+;
+; changes: AL, CX, DL, ES, CF
+
+erase: mov     dl,#ERASE1_CMD
+       call    sendop                  ; send ERASE1 command
+       mov     dl,#ERASE2_CMD
+       call    sendop                  ; send ERASE2 command
+       xor     bp,bp
+       mov     al,#0xFF
+       push    di
+       mov     di,bx
+       call    waitop                  ; wait until operation finished
+       pop     di
+       jnc     erfail
+       mov     dl,#RESET_CMD
+       call    sendop                  ; reset chip
+       stc
+erfail:        ret
+
+
+;----------------------------------------------------------------------------\f
+
+; PROGRAM -- write data block at DS:SI of length CX into EPROM at DI:BP
+; =======
+;
+; changes: AX, CX, DL, BP, ES, CF
+
+program:mov    dl,#PROG_CMD
+       call    sendop                  ; send programming command
+       lodsb                           ; get next byte from buffer
+       mov     es,di
+       seg     es
+       mov     byte ptr [bp],al        ; write next byte into flash EPROM
+       call    waitop                  ; wait until programming operation is
+       jc      progdn                  ; completed
+       inc     bp
+       loop    program                 ; continue with next byte
+       clc                             ; return without error
+progdn:        ret
+
+
+;----------------------------------------------------------------------------\f
+
+; SENDOP -- send command in DL to EPROM, base address is passed in BX
+; ======
+;
+; changes: ES
+
+sendop:        mov     es,bx
+       seg     es
+       mov     byte ptr 0x5555,#0xAA   ; write magic data bytes into
+       jcxz    so1                     ;   magic locations. This unlocks
+so1:   jcxz    so2                     ;   the flash EPROM. N.B. that the
+so2:   seg     es                      ;   magic locations are mirrored
+       mov     byte ptr 0x2AAA,#0x55   ;   every 32kB; the hardware address
+       jcxz    so3                     ;   might have to be adjusted to a
+so3:   jcxz    so4                     ;   32kB boundary
+so4:   seg     es
+       mov     byte ptr 0x5555,dl
+       ret
+
+
+;----------------------------------------------------------------------------\f
+
+; WAITOP -- wait for command to complete, address is passed in DI:BP
+; ======
+;
+; for details on the programming algorithm, c.f. http://www.amd.com
+;
+; changes: AX, DL, ES, CF
+
+waitop:        and     al,#0x80                ; monitor bit 7
+       mov     es,di
+wait1: seg     es                      ; read contents of EPROM cell that is
+       mov     ah,byte ptr [bp]        ;   being programmed
+       mov     dl,ah
+       and     ah,#0x80
+       cmp     al,ah                   ; bit 7 indicates sucess
+       je      waitok
+       test    dl,#0x20                ; bit 5 indicates timeout/error
+       jz      wait1                   ; otherwise wait for cmd to complete
+       seg     es
+       mov     ah,byte ptr [bp]        ; check error condition once again,
+       and     ah,#0x80                ;   because bits 7 and 5 can change
+       cmp     al,ah                   ;   simultaneously
+       je      waitok
+       stc
+       ret
+waitok:        clc
+       ret
+
+;----------------------------------------------------------------------------\f
+
+; PRNSTR -- prints a string in DS:SI onto the console
+; ======
+;
+; changes: AL
+
+prnstr:        push    si
+       cld
+prns1: lodsb                           ; loop over all characters of
+       or      al,al                   ; string
+       jz      prns2
+       call    prnchr                  ; print character
+       jmp     prns1
+prns2: pop     si
+       ret
+
+
+;----------------------------------------------------------------------------\f
+
+; PRNWRD, PRNBYT, PRNNIB, PRNCHR -- prints hexadezimal values, or ASCII chars
+; ======  ======  ======  ======
+;
+; changes: AX
+
+prnwrd:        push    ax
+       mov     al,ah
+       call    prnbyt                  ; print the upper byte
+       pop     ax
+prnbyt: push   ax
+       shr     al,1                    ; prepare upper nibble
+       shr     al,1
+       shr     al,1
+       shr     al,1
+       call    prnnib                  ; print it
+       pop     ax
+prnnib:        and     al,#0x0F                ; prepare lower nibble
+       add     al,#0x30
+       cmp     al,#0x39                ; convert it into hex
+       jle     prnchr
+       add     al,#7
+prnchr:        push    bx
+       mov     ah,#0x0E                ; print it
+       mov     bl,#0x07
+       xor     bh,bh
+       int     0x10
+       pop     bx
+       ret
+
+
+;----------------------------------------------------------------------------\f
+
+magic: .byte   0xE4,0xE4
+
+badmagic:.byte 0xa,0xd
+       .ascii  "There does not appear to be a ROM image attached to the"
+       .ascii  "flash EPROM utility;"
+       .byte   0xa,0xd
+resetmsg:.ascii        "Reboot to proceed..."
+       .byte   0
+       
+welcome:.byte  0xa,0xd
+       .ascii  "Flash EPROM programming utility V1.0"
+       .byte   0xa,0xd
+       .ascii  "Copyright (c) 1997 by M. Gutschke <gutschk@uni-muenster.de>"
+       .byte   0xa,0xd
+       .ascii  "==========================================================="
+       .byte   0xa,0xd
+prompt:        .byte   0xa,0xd
+       .ascii  "Enter base address for AMD29F010 flash EPROM on FlashCard or"
+       .byte   0xa,0xd
+       .ascii  "press <RETURN> to start autoprobing; the base address has"
+       .byte   0xa
+clrline1:.byte 0xd
+       .ascii  "to be in the range C800..E600: "
+       .ascii  "    "
+       .byte   0x8,0x8,0x8,0x8
+       .byte   0
+
+delchar:.byte  0x8,0x20,0x8
+       .byte   0
+
+automsg:.ascii "autoprobing... "
+       .byte   0
+
+failmsg:.ascii "failed!"
+basemsg:.byte  0xa
+clrline2:.byte 0xd
+       .ascii  "Enter base address: "
+       .ascii  "    "
+       .byte   0x8,0x8,0x8,0x8
+       .byte   0
+
+fndmsg:        .byte   0xa,0xd
+       .ascii  "Found flash EPROM at: "
+       .byte   0
+
+alignmsg:.byte 0xa,0xd
+       .ascii  "FlashCard requires the hardware address to be aligned to a"
+       .byte   0xa,0xd
+       .ascii  "32kB boundary; automatically adjusting..."
+       .byte   0
+       
+nofndmsg:.byte 0xa,0xd
+       .ascii  "No AMD29F010 flash EPROM found"
+       .byte   0
+
+ersmsg:        .byte   0xa,0xd
+       .ascii  "Erasing old contents... "
+       .byte   0
+
+prg1msg:.ascii "done"
+       .byte   0xa,0xd
+       .ascii  "Programming from "
+       .byte   0
+       
+prg2msg:.ascii ":0000 to "
+       .byte   0
+
+donemsg:.ascii "done!"
+       .byte   0xa,0xd
+       .byte   0
+       
+failresmsg:
+       .ascii  "failed!"
+       .byte   0xa,0xd
+       .byte   0
+
+
+;----------------------------------------------------------------------------\f
+
+       .align  16
+       .org    *-1
+       .byte   0x00
+romdata:
diff --git a/contrib/flashimg/flashimg.img b/contrib/flashimg/flashimg.img
new file mode 100644 (file)
index 0000000..263d339
Binary files /dev/null and b/contrib/flashimg/flashimg.img differ
diff --git a/contrib/hdload/Makefile b/contrib/hdload/Makefile
new file mode 100644 (file)
index 0000000..9ed750d
--- /dev/null
@@ -0,0 +1,15 @@
+# Use nasm or as86
+ASM=nasm
+# ASM=as86
+
+hdload.bin:    hdload.S
+ifeq ($(ASM),as86)
+       gcc $(CFLAGS) -DUSE_AS86 -E -traditional -o hdload.s hdload.S
+       as86 -0 -b hdload.bin hdload.s
+else
+       gcc $(CFLAGS) -DUSE_NASM -E -traditional -o hdload.s hdload.S
+       nasm -f bin hdload.s -o hdload.bin
+endif
+
+clean:
+       $(RM) -f hdload.s hdload.bin
diff --git a/contrib/hdload/hdload.S b/contrib/hdload/hdload.S
new file mode 100644 (file)
index 0000000..3bb5649
--- /dev/null
@@ -0,0 +1,162 @@
+#if    !defined(USE_NASM) && !defined(USE_AS86)\r
+#define        USE_AS86\r
+#endif\r
+\r
+#ifdef USE_AS86\r
+#define        CON(x)          *x\r
+#define        BCON(x)         *x\r
+#define        WCON(x)         *x\r
+#define        LOC(x)          x\r
+#define        BLOC(x)         byte ptr x\r
+#define        WLOC(x)         word ptr x\r
+#define        JMP(x)          jmp x\r
+#define        STRDECL(s)      .ascii  s\r
+#define        SEGCS           seg     cs\r
+#define        SEGES           seg     es\r
+#define        ALIGN(x)        .align  x\r
+#define        SPACE(x)        .space  x\r
+#endif\r
+\r
+#ifdef USE_NASM\r
+#define        CON(x)          x\r
+#define        BCON(x)         byte x\r
+#define        WCON(x)         word x\r
+#define        LOC(x)          [x]\r
+#define        BLOC(x)         byte [x]\r
+#define        WLOC(x)         word [x]\r
+#define        JMP(x)          jmp short x\r
+#define        STRDECL(s)      db      s\r
+#define        SEGCS           cs\r
+#define        SEGES           es\r
+#define        ALIGN(x)        align x, db 0\r
+#define        SPACE(x)        times x db 0\r
+#endif\r
+\r
+ROMLOAD        equ     0x5000\r
+\r
+start:\r
+       cli\r
+       xor     ax, ax\r
+       mov     ss, ax\r
+       mov     sp, CON(0x7C00)\r
+       mov     si, sp\r
+       mov     es, ax\r
+       mov     ds, ax\r
+       sti\r
+       cld\r
+       mov     di, CON(0x600)\r
+       mov     cx, CON(0x100)\r
+       rep\r
+       movsw\r
+       db      0xEA\r
+       dw      jump\r
+       dw      0\r
+jump:\r
+       mov     si, CON(Hlaska)\r
+       call    print\r
+\r
+        ; rozmery prvniho HD\r
+        mov     ah, CON(8)\r
+        mov     dl, CON(0x80)\r
+        int     0x13\r
+        jc      chyba\r
+        ; dh - H, cx - CS\r
+\r
+        ; prvi stopa obsahuje bootrom, tak ji natahneme do RAM\r
+        mov     ah, CON(2)\r
+        mov     al, cl\r
+        and     al, CON(0x3F)\r
+        dec     al\r
+        mov     dx, CON(0x80)\r
+        mov     cx, CON(2)\r
+        mov     bx, CON(ROMLOAD)\r
+        mov     es, bx\r
+        xor     bx, bx\r
+        int     0x13\r
+        jc      chyba\r
+\r
+        ; hromada kodu podle zdrojaku netboot\r
+        xor     di, di\r
+        mov     es, di\r
+        mov     di, CON(0x380)\r
+        push    di\r
+        mov     cx, CON(10)\r
+        cld\r
+        rep\r
+       stosw\r
+        pop     di\r
+#ifdef USE_AS86\r
+        mov     word ptr [ di ], CON(0x5a5a)\r
+        mov     byte ptr [ di + 2 ], CON(0x50)\r
+        mov     word ptr [ di + 0x10 ], CON(0xFFFF)\r
+        mov     word ptr [ di + 0x12 ], CON(0xFFFF)\r
+#endif\r
+#ifdef USE_NASM\r
+        mov     word [ di ], CON(0x5a5a)\r
+        mov     byte [ di + 2 ], CON(0x50)\r
+        mov     word [ di + 10h ], CON(0xFFFF)\r
+        mov     word [ di + 12h ], CON(0xFFFF)\r
+#endif\r
+\r
+        ; navratova adresa, kdyby nezabrala ROM\r
+       SEGCS\r
+        mov    WLOC(OfsErr), CON(RomErr)\r
+        push    cs\r
+        push    WCON(chyba)\r
+        mov     ax, CON(ROMLOAD)\r
+        mov     es, ax\r
+        push    es\r
+        ; kouzelny jump....\r
+       SEGES\r
+        mov     si, [ 0x1a ]\r
+       SEGES\r
+#ifdef USE_AS86\r
+        push    word ptr [ si + 0x1a ] ; ...do bootrom v RAM\r
+#endif\r
+#ifdef USE_NASM\r
+        push    word [ si + 0x1a ] ; ...do bootrom v RAM\r
+#endif\r
+        retf\r
+\r
+chyba:\r
+       SEGCS\r
+       mov     si, LOC(OfsErr)\r
+       call    print\r
+        mov     si, CON(CRLF)\r
+       call    print\r
+        JMP(chyba)\r
+\r
+print:\r
+       lodsb\r
+       cmp     al,CON(0)\r
+       je      navrat\r
+       push    si\r
+       mov     bx,CON(7)\r
+       mov     ah,CON(0x0E)\r
+       int     0x10\r
+       pop     si\r
+       JMP(print)\r
+\r
+navrat:\r
+       ret\r
+\r
+Hlaska:        db      13, 10\r
+       STRDECL('HD Net Loader v1.0 (c) poli 1999')\r
+       db      13, 10, 0\r
+CRLF:  db      13, 10, 0\r
+OfsErr:        dw      Error\r
+Error: STRDECL('Error load from HD !')\r
+       db      0\r
+RomErr:        STRDECL('ROM Error !')\r
+       db      0\r
+\r
+mbrend:\r
+       ret\r
+\r
+#ifdef  USE_AS86\r
+       org     510\r
+#endif\r
+#ifdef  USE_NASM\r
+       times   510-($-$$) db 0\r
+#endif\r
+        dw     0xAA55\r
diff --git a/contrib/hdload/petr.msg b/contrib/hdload/petr.msg
new file mode 100644 (file)
index 0000000..a3134d0
--- /dev/null
@@ -0,0 +1,175 @@
+From netboot-owner@baghira.han.de Thu Sep 16 12:08:44 1999
+Return-Path: <netboot-owner@baghira.han.de>
+Received: (from factotum@localhost)
+       by baghira.han.de (8.9.3/8.9.3) id NAA23838
+       for netboot-outgoing; Wed, 15 Sep 1999 13:12:44 +0200
+X-Authentication-Warning: baghira.han.de: factotum set sender to owner-netboot using -f
+Received: from hathi.han.de (root@hathi.han.de [192.109.225.1])
+       by baghira.han.de (8.9.3/8.9.3) with ESMTP id NAA23785
+       for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:11:02 +0200
+Received: from vsb.cz (root@decsys.vsb.cz [158.196.149.9])
+       by hathi.han.de (8.9.3/8.9.3) with ESMTP id NAA04707
+       for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:11:00 +0200
+Received: from nwfei1.vsb.cz (nwfei1.vsb.cz [158.196.146.13])
+       by vsb.cz (8.9.3/8.9.1) with ESMTP id NAA22363
+       for <netboot@baghira.han.de>; Wed, 15 Sep 1999 13:10:52 +0200 (MET DST)
+Received: from FEI1/SpoolDir by nwfei1.vsb.cz (Mercury 1.44);
+    15 Sep 99 13:10:50 +0100
+Received: from SpoolDir by FEI1 (Mercury 1.44); 15 Sep 99 13:10:27 +0100
+Received: from pcd403z.vsb.cz (158.196.146.9) by nwfei1.vsb.cz (Mercury 1.44) with ESMTP;
+    15 Sep 99 13:10:25 +0100
+Received: from oli10 by pcd403z.vsb.cz with local-esmtp (Exim 2.05 #1 (Debian))
+       id 11RCxI-0000oT-00; Wed, 15 Sep 1999 13:10:28 +0200
+Date: Wed, 15 Sep 1999 13:10:28 +0200 (CEST)
+From: Petr Olivka <Petr.Olivka@vsb.cz>
+To: netboot@baghira.han.de
+Subject: netboot image on hard disk - it is easy
+In-Reply-To: <37DF4BD4.E8FFF8FC@gsmbox.com>
+Message-ID: <Pine.LNX.4.10.9909151247430.2936-100000@pcd403z.vsb.cz>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=US-ASCII
+Sender: owner-netboot@baghira.han.de
+Precedence: bulk
+Reply-To: netboot@baghira.han.de
+X-Moderator: netboot-owner@baghira.han.de
+
+It is good joke, at this moment I have only simple version of MBR to load
+image from HD, but only from track 0. HD have to have enough sectors per
+track for rom image.
+And small program in turbo-pascal to download image to HD.
+
+below is assembler code for MBR. Is writen for tasm and tlink. 
+If you have 512 bytes binary file with MBR code, then concat it with
+rom-image and download to hda. BUT NOT DIRECTLY !!!! You have to copy 
+partition table ( and NT signature ) to MBR and then download. BUT ONLY tO
+TRACK 0.
+
+Everything in your own risk.
+
+If I will have some free time, I will write some code directly to netboot.
+
+poli
+
+.model large, pascal
+
+.code
+.386
+       public  mbrasm, mbrend
+
+ROMLOAD        equ     5000h
+
+       org     600h
+
+mbrasm proc
+
+       cli
+       xor     ax, ax
+       mov     ss, ax
+       mov     sp, 7C00h
+       mov     si, sp
+       mov     es, ax
+       mov     ds, ax
+       sti
+       cld
+       mov     di, 600h
+       mov     cx, 100h
+       rep     movsw
+       db      0EAh
+       dw      offset @@jump
+       dw      0
+@@jump:
+       mov     si, offset Hlaska
+       call    @@print
+
+        ; rozmery prvniho HD
+        mov     ah, 8
+        mov     dl, 80h
+        int     13h
+        jc      @@chyba
+        ; dh - H, cx - CS
+
+        ; prvi stopa obsahuje bootrom, tak ji natahneme do RAM
+        mov     ah, 2
+        mov     al, cl
+        and     al, 3Fh
+        dec     al
+        mov     dx, 80h
+        mov     cx, 2
+        mov     bx, ROMLOAD
+        mov     es, bx
+        xor     bx, bx
+        int     13h
+        jc      @@chyba
+
+        ; hromada kodu podle zdrojaku netboot
+        xor     di, di
+        mov     es, di
+        mov     di, 380h
+        push    di
+        mov     cx, 10
+        cld
+        rep     stosw
+        pop     di
+        mov     word ptr [ di ], 5a5ah
+        mov     byte ptr [ di + 2 ], 50h
+        mov     word ptr [ di + 10h ], 0FFFFh
+        mov     word ptr [ di + 12h ], 0FFFFh
+
+        ; navratova adresa, kdyby nezabrala ROM
+        mov    OfsErr, offset RomErr
+        push    cs
+        push    offset @@chyba
+
+        mov     ax, ROMLOAD
+        mov     es, ax
+        push    es
+        ; kouzelny jump....
+        mov     si,  es:[ 1ah ]
+        push    word ptr es:[ si + 1ah ] ; ...do bootrom v RAM
+        retf
+
+@@chyba:
+       mov     si, OfsErr
+       call    @@print
+        mov     si, offset CRLF
+       call    @@print
+        jmp     @@chyba
+
+@@print:
+       lodsb
+       cmp     al,0
+       je      @@navrat
+       push    si
+       mov     bx,7
+       mov     ah,0Eh
+       int     10h
+       pop     si
+       jmp     @@print
+
+@@navrat:
+       retn
+
+Hlaska db      13, 10, 'HD Net Loader v1.0 (c) poli 1999', 13, 10, 0
+CRLF   db      13, 10, 0
+OfsErr dw      offset Error
+Error  db      'Error load from HD !', 0
+RomErr db      'ROM Error !', 0
+
+mbrasm endp
+
+mbrend proc
+       ret
+mbrend endp
+
+        org 800h - 2
+        dw  0AA55h
+
+end
+
+===========================================================================
+This Mail was sent to netboot mailing list by:
+Petr Olivka <Petr.Olivka@vsb.cz>
+To get help about this list, send a mail with 'help' as the only string in
+it's body to majordomo@baghira.han.de. If you have problems with this list,
+send a mail to netboot-owner@baghira.han.de.
+
diff --git a/contrib/initrd/ChangeLog b/contrib/initrd/ChangeLog
new file mode 100644 (file)
index 0000000..94f8f6a
--- /dev/null
@@ -0,0 +1,46 @@
+mkinitrd-net ChangeLog
+
+Last Modified: Fri Jul 26 23:08:28 2002
+
+$Log$
+Revision 1.1  2005/05/17 16:45:02  mcb30
+Initial revision
+
+Revision 1.1  2002/11/06 06:31:06  ken_yap
+Contributed by Michael Brown.
+
+Revision 1.10  2002/07/26 23:09:13  mcb30
+Support for new binary etherboot.nic-dev-id structure
+Added --kernel option patch from Stew Benedict at MandrakeSoft
+Only try to use sudo if we are not already root
+
+Revision 1.9  2002/06/05 13:31:50  mcb30
+Modifications to allow DHCP, TFTP and NFS servers to be separate machines.
+
+Revision 1.8  2002/05/30 11:41:18  mcb30
+/tftpboot symlinked to /var/lib/tftpboot
+Has ability to be quiet if "quiet" specified on kernel cmdline
+
+Revision 1.7  2002/05/26 11:15:04  mcb30
+PCI-ID auto-mapping via dhcpd.conf.etherboot-pcimap.include
+
+Revision 1.6  2002/05/24 02:05:11  mcb30
+Bugfixes, migrated /tftpboot to /var/lib/tftpboot
+
+Revision 1.5  2002/05/23 21:29:58  mcb30
+Now includes dhcpd.conf.etherboot.include
+Automatically scans for all network modules in the pcimap file
+
+Revision 1.4  2002/05/08 09:04:31  mcb30
+Bugfixes: tmpdir selection, linuxrc typos, ifconfig peculiarities
+
+Revision 1.3  2002/05/04 21:44:13  mcb30
+During %make, LIBDIR must be set for mknbi
+Added %post scriptlet since %trigger seems not to be being triggered...
+
+Revision 1.2  2002/05/04 21:20:32  mcb30
+Added extra sources instead of requiring "make" to download them
+
+Revision 1.1  2002/05/04 13:19:40  mcb30
+First attempt at an RPM package
+
diff --git a/contrib/initrd/Makefile b/contrib/initrd/Makefile
new file mode 100644 (file)
index 0000000..f18b73f
--- /dev/null
@@ -0,0 +1,187 @@
+UCLIBC_VERSION = 0.9.11
+UCLIBC = uClibc-$(UCLIBC_VERSION)
+$(UCLIBC)_SOURCE = http://www.uclibc.org/downloads/$(UCLIBC).tar.bz2
+UCLIBC_INSTALL = $(CURDIR)/uClibc
+
+UDHCP_VERSION = 0.9.7
+UDHCP = udhcp-$(UDHCP_VERSION)
+$(UDHCP)_SOURCE = http://udhcp.busybox.net/source/$(UDHCP).tar.gz
+
+BUSYBOX_VERSION = 0.60.3
+BUSYBOX = busybox-$(BUSYBOX_VERSION)
+$(BUSYBOX)_SOURCE = http://www.busybox.net/downloads/$(BUSYBOX).tar.bz2
+
+LINUX_WLAN_VERSION = 0.1.13
+LINUX_WLAN = linux-wlan-ng-$(LINUX_WLAN_VERSION)
+$(LINUX_WLAN)_SOURCE = ftp://ftp.linux-wlan.org/pub/linux-wlan-ng/$(LINUX_WLAN).tar.gz
+
+MKNBI_VERSION = 1.2
+MKNBI = mknbi-$(MKNBI_VERSION)
+$(MKNBI)_SOURCE = http://belnet.dl.sourceforge.net/sourceforge/etherboot/$(MKNBI).tar.gz
+
+export PATH := $(UCLIBC_INSTALL)/bin:$(PATH)
+
+all : utils initrd-skel mknbi mknbi-linux
+       # Run "make tftpboot/initrd-kernel_module.img" to generate a suitable initrd
+       # Run "make tftpboot/boot-kernel_module.nbi" to generate a suitable NBI
+       # Run "make all-nbi" to generate a complete set of NBIs
+
+%.tar.bz2 :
+       [ -d $* ] || wget $($*_SOURCE)
+       [ -f $*.t*gz ] && ( gunzip $*.t*gz ; bzip2 -9 $*.tar ) || true
+
+UTILS = udhcpc busybox wlanctl
+
+utils : $(UTILS)
+
+clean : partlyclean
+       rm -rf uClibc
+       rm -rf $(UCLIBC)
+       rm -rf tftpboot/*
+
+partlyclean :
+       rm -rf $(UDHCP)
+       rm -rf $(BUSYBOX)
+       rm -rf $(LINUX_WLAN)
+       rm -rf $(MKNBI)
+       rm -rf initrd-skel
+       rm -f *.img *.ird *.nbi insert-modules
+       rm -f $(UTILS) mknbi-linux
+       rm -f *.uClibc *.busybox *.udhcpc *.wlanctl
+
+.PHONY : all utils clean partlyclean
+
+uClibc : $(UCLIBC)
+       rm -rf $@
+       $(MAKE) -C $(UCLIBC) install
+
+$(UCLIBC) : $(UCLIBC).tar.bz2
+       [ -d $@ ] || tar xvjf $<
+       [ -f $(UCLIBC)/Config ] || perl -pe 's/^(INCLUDE_RPC).*/$$1 = true/ ;' \
+               -e 's{^(DEVEL_PREFIX).*}{$$1 = $(UCLIBC_INSTALL)} ;' \
+               -e 's{^(SHARED_LIB_LOADER_PATH).*}{$$1 = /lib} ;' \
+               $(UCLIBC)/extra/Configs/Config.i386 > $(UCLIBC)/Config
+       # Stripping out spurious CVS directories (screws up local cvs update)
+       rm -rf `find $(UCLIBC) -name CVS`
+       $(MAKE) -C $(UCLIBC)
+       install -m 644 $(UCLIBC)/COPYING.LIB COPYING.uClibc
+
+udhcpc : $(UDHCP)
+       install -m 755 -s $(UDHCP)/$@ $@
+
+$(UDHCP) : $(UDHCP).tar.bz2 uClibc
+       [ -d $@ ] || tar xvjf $<
+       if [ ! -f $@/.script.c.patch ]; then \
+               patch -d $@ -b -z .orig < script.c.patch ; \
+               touch $@/.script.c.patch ; \
+       fi
+       $(MAKE) LDFLAGS+=-static -C $(UDHCP)
+       install -m 644 $(UDHCP)/AUTHORS AUTHORS.udhcpc
+       install -m 644 $(UDHCP)/COPYING COPYING.udhcpc
+
+busybox : $(BUSYBOX)
+       install -m 755 -s $(BUSYBOX)/$@ $@
+
+$(BUSYBOX) : $(BUSYBOX).tar.bz2 uClibc
+       [ -d $@ ] || tar xvjf $<
+       perl -pi.orig -e \
+         's/^.*(#define BB_(FEATURE_NFSMOUNT|INSMOD|PIVOT_ROOT|IFCONFIG|ROUTE)).*/$$1/' \
+         $(BUSYBOX)/Config.h
+       perl -pi.orig -e \
+         's/^(DOSTATIC).*$$/$$1 = true/' \
+         $(BUSYBOX)/Makefile
+       $(MAKE) -C $(BUSYBOX)
+       install -m 644 $(BUSYBOX)/AUTHORS AUTHORS.busybox
+       install -m 644 $(BUSYBOX)/LICENSE LICENSE.busybox
+
+wlanctl : $(LINUX_WLAN)
+       install -m 755 -s $(LINUX_WLAN)/src/wlanctl/$@ $@
+
+$(LINUX_WLAN) : $(LINUX_WLAN).tar.bz2 uClibc linux-wlan.cfg
+       [ -d $@ ] || tar xvjf $<
+       cd $(LINUX_WLAN) ; ./Configure -d ../linux-wlan.cfg
+       perl -pi.orig -e \
+         's/(-o wlanctl)/-static $$1/' \
+         $(LINUX_WLAN)/src/wlanctl/Makefile
+       $(MAKE) -C $(LINUX_WLAN)/src/wlanctl
+       install -m 644 $(LINUX_WLAN)/COPYING COPYING.wlanctl
+       install -m 644 $(LINUX_WLAN)/LICENSE LICENSE.wlanctl
+       install -m 644 $(LINUX_WLAN)/THANKS THANKS.wlanctl
+
+mknbi-linux : $(MKNBI)
+
+mknbi : $(MKNBI)
+
+$(MKNBI) : $(MKNBI).tar.bz2
+       [ -d $@ ] || tar xvjf $<
+       if [ ! -f $@/.mknbi-encap.patch ]; then \
+               patch -d $@ -b -z .orig < mknbi-encap.patch ; \
+               touch $@/.mknbi-encap.patch ; \
+       fi
+       make -C $(MKNBI) LIBDIR=`pwd`/$(MKNBI) mknbi
+       install -m 755 $(MKNBI)/mknbi mknbi-linux
+       make -C $(MKNBI) clean
+       make -C $(MKNBI)
+
+initrd-skel : $(UTILS) linuxrc udhcpc-post include-modules
+       rm -rf $@
+       mkdir -p $@
+       mkdir -p $@/dev
+       mkdir -p $@/etc
+       mkdir -p $@/bin
+       mkdir -p $@/lib
+       mkdir -p $@/lib/modules
+       mkdir -p $@/proc
+       mkdir -p $@/sysroot
+       ln -s bin $@/sbin
+       install -m 755 busybox $@/bin/
+       install -m 755 udhcpc $@/bin/
+       install -m 755 wlanctl $@/bin/
+       ln -s busybox $@/bin/sh
+       ln -s busybox $@/bin/echo
+       ln -s busybox $@/bin/mknod
+       ln -s busybox $@/bin/chmod
+       ln -s busybox $@/bin/insmod
+       ln -s busybox $@/bin/ifconfig
+       ln -s busybox $@/bin/route
+       ln -s busybox $@/bin/mount
+       ln -s busybox $@/bin/pivot_root
+       ln -s busybox $@/bin/umount
+       ln -s busybox $@/bin/[
+       ln -s busybox $@/bin/sleep
+       ln -s busybox $@/bin/grep
+
+       install -m 755 linuxrc $@/linuxrc
+       install -m 755 udhcpc-post $@/bin/udhcpc-post
+
+tftpboot/initrd-%.img : initrd-skel
+       ./mkinitrd-net -l `echo $* | tr . " "`
+
+tftpboot/boot-%.nbi : tftpboot/initrd-%.img mknbi-linux
+       ./mknbi-linux --format=nbi --target=linux /boot/vmlinuz $< > $@
+       sudo cp $@ $(tftpbootdir)
+
+all-nbi : all
+       ./mknbi-set -l -v
+       ls tftpboot
+
+prefix = /usr
+sysconfdir = /etc
+bindir = $(prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/share/man
+docdir = $(prefix)/share/doc
+tftpbootdir = /var/lib/tftpboot
+initrdskeldir = $(prefix)/lib/mkinitrd-net/initrd-skel
+
+install :
+       mkdir -p $(libdir)/mknbi
+       mkdir -p $(bindir)
+       mkdir -p $(sysconfdir)
+       mkdir -p $(tftpbootdir)
+       mkdir -p $(initrdskeldir)
+       install -m 755 mkinitrd-net include-modules mknbi-set $(bindir)/
+       cp -a initrd-skel/* $(initrdskeldir)/
+       install -m 644 mknbi-set.conf dhcpd.conf.etherboot.include $(sysconfdir)
+       make -C $(MKNBI) INSTPREFIX=$(prefix) MANDIR=$(mandir)/man1 \
+               DOCDIR=$(docdir)/$(MKNBI) install
diff --git a/contrib/initrd/Manifest b/contrib/initrd/Manifest
new file mode 100644 (file)
index 0000000..b41e725
--- /dev/null
@@ -0,0 +1,15 @@
+initrd/ChangeLog
+initrd/Makefile
+initrd/Manifest
+initrd/README
+initrd/dhcpd.conf.etherboot.include
+initrd/include-modules
+initrd/linux-wlan.cfg
+initrd/linuxrc
+initrd/mkinitrd-net
+initrd/mkinitrd-net.spec
+initrd/mknbi-encap.patch
+initrd/mknbi-set
+initrd/mknbi-set.conf
+initrd/script.c.patch
+initrd/udhcpc-post
diff --git a/contrib/initrd/README b/contrib/initrd/README
new file mode 100644 (file)
index 0000000..5152425
--- /dev/null
@@ -0,0 +1,37 @@
+README for mkinitrd-net
+
+mkinitrd-net enables you to use your distribution's stock kernel for
+diskless workstations, without having to compile in support for the
+relevant network card(s).  It creates an initial ramdisk image containing
+the required network-card kernel modules and bootstrap scripts to load the
+module, obtain an IP address via DHCP and mount the root filesystem via
+NFS.
+
+mkinitrd-net also generates a dhcpd.conf file fragment that can be used to
+automate the process of mapping NBI files to clients, based on the PCI IDs
+of their network cards.  Etherboot will send the PCI ID of the network
+card to the DHCP server in the etherboot-encapsulated-options field
+(Etherboot 5.0.7 and newer) and the DHCP server can use this to identify
+the correct NBI to point the client towards.
+
+The end result is that:
+
+a) You can avoid the hassle of compiling custom kernels for diskless
+   workstations.
+
+b) Diskless workstations will automatically download the correct
+   kernel+initrd.
+
+c) You have an easier life! :-)
+
+
+
+mkinitrd-net is Copyright Fen Systems Ltd. 2001.  mkinitrd-net itself is
+licensed under the GNU GPL.  It incorporates code from the uClibc,
+busybox, udhcpc and Etherboot projects, each of which has its own licence
+terms.  Standard disclaimers apply.
+
+The copy of mkinitrd-net in the Etherboot contribs is not the
+authoritative copy of mkinitrd-net; please do not make modifications to
+this copy.  Patches should be sent to Michael Brown
+<mbrown@fensystems.co.uk>.
diff --git a/contrib/initrd/dhcpd.conf.etherboot.include b/contrib/initrd/dhcpd.conf.etherboot.include
new file mode 100644 (file)
index 0000000..9cec1dc
--- /dev/null
@@ -0,0 +1,207 @@
+# dhcpd.conf include file for Etherboot
+#
+# Include this file from your /etc/dhcpd.conf
+# $Id$
+
+# Definition of Etherboot options
+# (taken from vendortags.html)
+
+# We use an encapsulated option space to avoid polluting the site-local DHCP option space
+#
+option space etherboot;
+option etherboot-encapsulated-options code 150 = encapsulate etherboot;
+
+# Definition of option codes within the etherboot-encapsulated-options space
+#
+option etherboot.extensions-path code 18 = string;
+option etherboot.magic         code 128 = string;
+option etherboot.kernel-cmdline        code 129 = string;
+option etherboot.menu-opts     code 160 = string;
+option etherboot.nic-dev-id    code 175 = string;
+option etherboot.menu-selection        code 176 = unsigned integer 8;
+option etherboot.motd-1                code 184 = string;
+option etherboot.motd-2                code 185 = string;
+option etherboot.motd-3                code 186 = string;
+option etherboot.motd-4                code 187 = string;
+option etherboot.motd-5                code 188 = string;
+option etherboot.motd-6                code 189 = string;
+option etherboot.motd-7                code 190 = string;
+option etherboot.motd-8                code 191 = string;
+option etherboot.image-1       code 192 = string;
+option etherboot.image-2       code 193 = string;
+option etherboot.image-3       code 194 = string;
+option etherboot.image-4       code 195 = string;
+option etherboot.image-5       code 196 = string;
+option etherboot.image-6       code 197 = string;
+option etherboot.image-7       code 198 = string;
+option etherboot.image-8       code 199 = string;
+option etherboot.image-9       code 200 = string;
+option etherboot.image-10      code 201 = string;
+option etherboot.image-11      code 202 = string;
+option etherboot.image-12      code 203 = string;
+option etherboot.image-13      code 204 = string;
+option etherboot.image-14      code 205 = string;
+option etherboot.image-15      code 206 = string;
+option etherboot.image-16      code 207 = string;
+option etherboot.kmod          code 254 = string;
+
+# Legacy support for Etherboot options as site-local options (i.e. non-encapsulated)
+# Note: options defined after the switch to encapsulated options should not be defined here
+#
+option legacy-etherboot-magic          code 128 = string;
+option legacy-etherboot-kernel-cmdline code 129 = string;
+option legacy-etherboot-menu-opts      code 160 = string;
+option legacy-etherboot-menu-selection code 176 = unsigned integer 8;
+option legacy-etherboot-motd-1         code 184 = string;
+option legacy-etherboot-motd-2         code 185 = string;
+option legacy-etherboot-motd-3         code 186 = string;
+option legacy-etherboot-motd-4         code 187 = string;
+option legacy-etherboot-motd-5         code 188 = string;
+option legacy-etherboot-motd-6         code 189 = string;
+option legacy-etherboot-motd-7         code 190 = string;
+option legacy-etherboot-motd-8         code 191 = string;
+option legacy-etherboot-image-1                code 192 = string;
+option legacy-etherboot-image-2                code 193 = string;
+option legacy-etherboot-image-3                code 194 = string;
+option legacy-etherboot-image-4                code 195 = string;
+option legacy-etherboot-image-5                code 196 = string;
+option legacy-etherboot-image-6                code 197 = string;
+option legacy-etherboot-image-7                code 198 = string;
+option legacy-etherboot-image-8                code 199 = string;
+option legacy-etherboot-image-9        code 200 = string;
+option legacy-etherboot-image-10       code 201 = string;
+option legacy-etherboot-image-11       code 202 = string;
+option legacy-etherboot-image-12       code 203 = string;
+option legacy-etherboot-image-13       code 204 = string;
+option legacy-etherboot-image-14       code 205 = string;
+option legacy-etherboot-image-15       code 206 = string;
+option legacy-etherboot-image-16       code 207 = string;
+
+# Apply Etherboot options only for Etherboot clients
+#
+if substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" {
+
+  # We must specify this value for etherboot-magic, or Etherboot will
+  # ignore all other options.
+  #
+  option etherboot.magic E4:45:74:68:00:00;
+
+  # Bootfile name: derive from etherboot.kmod (calculated below)
+  # Use boot.nbi if no NIC_DEV_ID option present
+  # (i.e. if etherboot.kmod doesn't get set)
+  # Also pass filename back in filename field
+  #
+  option bootfile-name = pick-first-value ( concat ( "boot-",
+                                                    config-option etherboot.kmod,
+                                                    ".nbi" ),
+                                           "boot.nbi" ) ;
+  filename = config-option bootfile-name;
+
+  # "Sensible" default values for some options
+
+  # Mount devfs (will probably be needed for a network-boot)
+  option etherboot.kernel-cmdline " devfs=mount";
+
+  # Info message (includes client IP address, MAC address, hardware ID string,
+  # server IP address and name of boot file)
+  option etherboot.motd-4 = concat ( "Using Etherboot to boot ",
+                                    binary-to-ascii ( 10, 8, ".", leased-address ),
+                                    " [",
+                                    binary-to-ascii ( 16, 8, ":", suffix ( hardware, 6 ) ),
+                                    "] [",
+                                    pick-first-value ( option etherboot.nic-dev-id, "unknown card" ),
+                                    "]", 0d:0a, "  from ",
+                                    binary-to-ascii ( 10, 8, ".", option dhcp-server-identifier ),
+                                    " with file ",
+                                    config-option tftp-server-name,
+                                    ":",
+                                    config-option bootfile-name,
+                                    " [",
+                                    pick-first-value ( config-option etherboot.kmod, "unknown module" ),
+                                    "]", 0d:0a );
+
+  # Legacy site-local option support
+  # If client does not include an etherboot-encapsulated-options field in its DHCPREQUEST, then
+  # it will not understand etherboot-encapsulated-options in the DHCPACK and so we must send
+  # back the options as site-local options (i.e. not encapsulated).
+  # Note: we need do this only for options that existed prior to the switch to encapsulation.
+  #
+  if not exists etherboot-encapsulated-options {
+    option legacy-etherboot-magic      = config-option etherboot.magic;
+    option legacy-etherboot-kernel-cmdline = config-option etherboot.kernel-cmdline;
+    option legacy-etherboot-menu-opts  = config-option etherboot.menu-opts;
+    option legacy-etherboot-menu-selection = config-option etherboot.menu-selection;
+    option legacy-etherboot-motd-1     = config-option etherboot.motd-1;
+    option legacy-etherboot-motd-2     = config-option etherboot.motd-2;
+    option legacy-etherboot-motd-3     = config-option etherboot.motd-3;
+    option legacy-etherboot-motd-4     = config-option etherboot.motd-4;
+    option legacy-etherboot-motd-5     = config-option etherboot.motd-5;
+    option legacy-etherboot-motd-6     = config-option etherboot.motd-6;
+    option legacy-etherboot-motd-7     = config-option etherboot.motd-7;
+    option legacy-etherboot-motd-8     = config-option etherboot.motd-8;
+    option legacy-etherboot-image-1    = config-option etherboot.image-1;
+    option legacy-etherboot-image-2    = config-option etherboot.image-2;
+    option legacy-etherboot-image-3    = config-option etherboot.image-3;
+    option legacy-etherboot-image-4    = config-option etherboot.image-4;
+    option legacy-etherboot-image-5    = config-option etherboot.image-5;
+    option legacy-etherboot-image-6    = config-option etherboot.image-6;
+    option legacy-etherboot-image-7    = config-option etherboot.image-7;
+    option legacy-etherboot-image-8    = config-option etherboot.image-8;
+    option legacy-etherboot-image-9    = config-option etherboot.image-9;
+    option legacy-etherboot-image-10   = config-option etherboot.image-10;
+    option legacy-etherboot-image-11   = config-option etherboot.image-11;
+    option legacy-etherboot-image-12   = config-option etherboot.image-12;
+    option legacy-etherboot-image-13   = config-option etherboot.image-13;
+    option legacy-etherboot-image-14   = config-option etherboot.image-14;
+    option legacy-etherboot-image-15   = config-option etherboot.image-15;
+    option legacy-etherboot-image-16   = config-option etherboot.image-16;
+  }
+}
+
+# Some options should be set for both Etherboot and the udhcpc client
+#
+if ( ( substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" ) 
+     or ( substring ( option vendor-class-identifier, 0, 5 ) = "udhcp" ) ) {
+
+  # TFTP server defaults to DHCP server and is specified in both
+  # next-server field and tftp-server-name option field
+  #
+  option tftp-server-name = binary-to-ascii ( 10, 8, ".", config-option dhcp-server-identifier );
+  server-name = config-option tftp-server-name;
+  next-server = config-option dhcp-server-identifier;
+
+  # Root path defaults to root of TFTP server
+  option root-path = concat ( config-option tftp-server-name, ":/" );
+
+  # A fallback hostname, generated from the IP address
+  option host-name = concat ( "client_", binary-to-ascii ( 10, 8, "_", leased-address ) );
+}
+
+# Force some items onto parameter request list for udhcp
+#
+if substring ( option vendor-class-identifier, 0, 5 ) = "udhcp" {
+  # Forcibly add root-path to list
+  option dhcp-parameter-request-list = concat ( option dhcp-parameter-request-list, 11 );
+}
+
+# Etherboot sends a string to identify the NIC in etherboot.nic-dev-id.
+# For PCI NICs, this string is of the form "PCI:vvvv:dddd" where vvvv is the 
+# vendor identifier and dddd the device identifier, in lower-case ASCII hex.
+# For ISA NICs, the format of the string is "ISA:..." where ... is not yet
+# decided upon.
+#
+# We use the identifier to select the NBI image that will be specified via
+# the "bootfile-name" option.
+#
+# PCI NICs - use PCI vendor and device IDs
+# Listed in file generated by mknbi-set
+#
+include "/etc/dhcpd.conf.etherboot-pcimap.include";
+
+# ISA NICs
+#
+if substring ( option vendor-class-identifier, 0, 9 ) = "Etherboot" {
+  if exists etherboot.nic-dev-id {
+
+  }
+}
diff --git a/contrib/initrd/include-modules b/contrib/initrd/include-modules
new file mode 100755 (executable)
index 0000000..60e76fc
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/perl -w
+#
+# Retrieve modules required for an initrd image
+# $Id$
+
+unless ( @ARGV ) {
+  die "Syntax: $0 [ -d target_directory ] module_1 module_2 module_3\n"
+}
+
+# Parse command line arguments
+my @requested_modules = ();
+my $target_dir = "";
+my $kernel_ver;
+my $quiet;
+chomp ( my $current_kernel_ver = `uname -r` );
+while ( $_ = shift ) {
+  if    ( /-d/ ) { $target_dir = shift }
+  elsif ( /-k/ ) { $kernel_ver = shift }
+  elsif ( /-q/ ) { $quiet = 1 }
+  else           { push @requested_modules, $_ };
+}
+
+# Create target directory if required
+if ( $target_dir ) {
+  print STDERR "Target directory is $target_dir\n" unless $quiet;
+  system ( "mkdir -p $target_dir" );
+  chdir $target_dir;
+}
+
+# Use modprobe -nav to retrieve locations of modules and their dependencies
+print STDERR "Requested modules ". join (' ', @requested_modules)."\n" unless $quiet;
+my @modules_dups;
+foreach my $module ( @requested_modules ) {
+  my @module_list = map { /^\S+\s+(.*)$/ ; $1 } `/sbin/modprobe -nva $module`;
+  die "Cannot find any modules matching $module\n" unless @module_list;
+  push @modules_dups, @module_list;
+}
+
+# Remove duplicates from list
+my %module_basenames = ();
+my @modules = ();
+foreach my $module ( @modules_dups ) {
+  # Ugly hack : assume that dependencies are independent of kernel version
+  # This seems to be necessary because we can't run modprobe and specify
+  # an alternate modules.dep file; it refuses to understand lines of the 
+  # form "depfile=XXX" as documented in modules.conf(5)
+  $module =~ s/$current_kernel_ver/$kernel_ver/ if $kernel_ver;
+  push @modules, $module unless $module_basenames{$module};
+  ( my $basename ) = ( $module =~ /([^\/]+)\.o/ ); 
+  $module_basenames{$module} = $basename;
+}
+
+# Process module list
+print "#!/bin/sh\n";
+foreach my $module ( @modules ) {
+  my $basename = $module_basenames{$module};
+  # Report via stdout
+  print STDERR "Using module $basename from $module\n" unless $quiet;
+  # Copy uncompressed module to current directory
+  system ("gunzip -c $module > $basename.o");
+  # Print insmod line to stdout
+  print "insmod $basename\n";
+}
diff --git a/contrib/initrd/linux-wlan.cfg b/contrib/initrd/linux-wlan.cfg
new file mode 100644 (file)
index 0000000..7df4a05
--- /dev/null
@@ -0,0 +1,7 @@
+# Dummy config file for building only wlanctl
+# $Id$
+
+PRISM2_PLX=n
+PRISM2_PCMCIA=n
+PRISM2_PCI=n
+PRISM2_USB=n
diff --git a/contrib/initrd/linuxrc b/contrib/initrd/linuxrc
new file mode 100644 (file)
index 0000000..24bdb0d
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/sh
+# $Id$
+
+PATH=/sbin:/bin
+
+echo Busybox /linuxrc starting
+
+echo Mounting /proc filesystem
+mount -t proc none /proc
+
+echo=echo
+if grep '\bquiet\b' /proc/cmdline > /dev/null; then
+  echo=true
+  quiet=1
+fi
+
+$echo Creating root device
+mknod /dev/root b 1 0 2>/dev/null
+chmod 700 /dev/root
+echo 0x100 > /proc/sys/kernel/real-root-dev
+
+$echo Inserting modules
+if [ -z "$quiet" ]; then
+  /bin/insert-modules
+else
+  /bin/insert-modules >/dev/null
+fi
+
+$echo Bringing up loopback interface
+ifconfig lo 127.0.0.1 up
+route add -net 127.0.0.0 netmask 255.0.0.0 lo
+
+# Hack required for prism2 cards
+# It is not yet possible to use iwconfig to configure these cards,
+# so we need wlanctl.
+if ifconfig wlan0 down 2> /dev/null; then
+  $echo Setting up wireless link
+  wlanctl wlan0 lnxreq_ifstate ifstate=enable
+  wlanctl wlan0 lnxreq_autojoin ssid= authtype=opensystem
+fi
+
+$echo Obtaining IP address via DHCP
+$echo Trying to obtain IP address via wired link [eth0]
+if udhcpc -i eth0 -f -n -q -s /bin/udhcpc-post; then
+  $echo Successfully obtained IP address via wired link [eth0]
+else
+  $echo Failed to obtain IP address via wired link [eth0]
+  $echo Trying to obtain IP address via wireless link [wlan0]
+  udhcpc -i wlan0 -f -n -q -s /bin/udhcpc-post
+fi
+
+if [ -d /sysroot/initrd ]; then
+  $echo Unmounting /proc prior to pivot_root
+  umount /proc
+
+  $echo Pivoting root to /sysroot
+  pivot_root /sysroot /sysroot/initrd
+  cd /
+
+  $echo Remounting devfs at correct place
+  mount -t devfs none /dev
+
+  $echo Releasing locks on old devfs
+  exec 0</dev/null
+  exec 1>/dev/console
+  exec 2>/dev/console
+
+  $echo Unmounting old devfs
+  umount /initrd/dev
+else
+  # Failed to mount root: report error and hang
+  echo FATAL ERROR: Failed to mount root filesystem
+  echo Press Alt-SysRq-B or hit the reset switch to reboot
+  while : ; do sleep 6000 ; done
+fi
+
diff --git a/contrib/initrd/mkinitrd-net b/contrib/initrd/mkinitrd-net
new file mode 100755 (executable)
index 0000000..0c95ebd
--- /dev/null
@@ -0,0 +1,165 @@
+#!/bin/sh
+#
+# $Id$
+# initrd builder for network booting
+
+# Utility function to determine whether or not a filesystem is usable for
+# loopback mounts.  Lifted verbatim from Erik Troan's mkinitrd script.
+#
+is_good_fs() {
+    local parttype= tmpname=
+    local dir=$1
+    [[ -d $dir ]] || return 1
+    [[ -w $dir ]] || return 1
+    [[ $dir == */ ]] && dir=${dir%/}
+    parttype=$(awk "{if (\$2 == \""$dir"\") print \$3 }" /proc/mounts)
+    while tmpname=${dir%/*} && [[ -z $parttype ]];do
+        [[ -z $tmpname ]] && tmpname=/
+        parttype=$(awk "{if (\$2 == \""$tmpname"\") print \$3 }" /proc/mounts)
+        dir=$tmpname
+    done
+    case $parttype in
+        nfs|tmpfs) return 1;;
+        *) return 0;
+    esac
+}
+
+# Find a suitable temporary directory (i.e. not tmpfs or nfs)
+if is_good_fs $TMPDIR; then
+  tmpdir=$TMPDIR
+elif is_good_fs /tmp; then
+  tmpdir=/tmp
+elif is_good_fs /var/tmp; then
+  tmpdir=/var/tmp
+elif is_good_fs /root/tmp; then
+  tmpdir=/root/tmp
+else
+  echo "Cannot use a tmp directory" >&2
+  exit 1
+fi
+
+# Default settings (some can be overridden by command-line options)
+include_modules=include-modules
+initrd_skel=/usr/lib/mkinitrd-net/initrd-skel
+kernel_ver=`uname -r`
+use_sudo=y
+keep=n
+output_dir=/var/lib/tftpboot
+make_link=y
+quiet=
+
+# No need to use sudo if we are root
+if [ $UID -eq 0 ]; then
+  use_sudo=n
+fi
+
+USAGE="Usage: $0 [-k|--kernel <kernel_ver>] [-n|--nolink] [-q|--quiet] [-l|--local] [--nosudo] [--keep] [--help] module_list ..."
+
+# Parse command-line options
+while [ $# -gt 0 ]; do
+  case "$1" in
+    -l|--local)
+               shift
+               use_local=y ;;
+    -k|--kernel)
+               shift
+               kernel_ver=$1
+               shift ;;
+    --nosudo)   shift ; use_sudo=n ;;
+    --keep)     shift ; keep=y ;;
+    --n|--nolink)
+               shift ; make_link=n ;;
+    -q|--quiet) shift ; quiet=-q ;;
+    --help)    shift ; do_help=y ;;
+    --)                shift ; break ;;
+    -*)                echo "${0}: ${1}: invalid option" >&2
+               echo $USAGE >& 2
+               exit 2 ;;
+    *)         break ;;
+  esac
+done
+
+# Build list of requested modules
+modules="$*"
+requested_modules="$modules"
+modules="$modules nfs" # Always require nfs for nfs mount
+modules="$modules af_packet" # Always require af_packet for udhcpc
+
+# --help => Print help message
+if [ "$do_help" == "y" ]; then
+  echo $USAGE
+  echo "  -k, --kernel   Specify kernel version"
+  echo "  -n, --nolink   Do not create a matching symbolic link"
+  echo "  -l, --local    Run locally from CVS (for developers only)"
+  echo "  --nosudo       Do not use sudo (i.e. must run as root instead)"
+  echo "  --keep         Keep temporary files instead of deleting them"
+  exit 0;
+fi
+
+# --local => we are running directly from CVS, rather than
+# from an installed copy, so use local files and directories
+if [ "$use_local" == "y" ]; then
+  include_modules=./include-modules
+  initrd_skel=initrd-skel
+  output_dir=tftpboot
+fi
+
+# If use_sudo is set, check that sudo exists
+sudo=/usr/bin/sudo
+if [ "$use_sudo" == "y" ]; then
+  if [ ! -x $sudo ]; then
+    use_sudo=n
+    echo "WARNING: --nosudo not specified but $sudo not found"
+  fi
+fi
+if [ "$use_sudo" == "n" ]; then
+  sudo=
+fi
+
+# Create temporary working files
+initrd=`mktemp -d ${tmpdir}/initrd.XXXXXX`
+initrdimg=`mktemp ${tmpdir}/initrd.img.XXXXXX`
+initrdmnt=`mktemp -d ${tmpdir}/initrd.mnt.XXXXXX`
+
+# Copy skeleton into temporary area
+cp -a $initrd_skel/* $initrd/
+mkdir -p $initrd/lib/modules/$kernel_ver
+$include_modules $quiet -k $kernel_ver -d $initrd/lib/modules/$kernel_ver $modules > $initrd/bin/insert-modules || exit 1
+chmod 755 $initrd/bin/insert-modules
+
+# Create empty ext2fs image file
+dd if=/dev/zero bs=1k of=$initrdimg count=$((`du -sk $initrd | cut -f1` * 7 / 6)) 2> /dev/null
+/sbin/mke2fs -q -F $initrdimg 2> /dev/null
+
+# Mount image file, copy files on, create /dev entries, display free space, umount
+$sudo mount -o loop $initrdimg $initrdmnt
+cp -a $initrd/* $initrdmnt/
+$sudo mknod $initrdmnt/dev/console c 5 1
+$sudo mknod $initrdmnt/dev/null c 1 3
+$sudo mknod $initrdmnt/dev/ram b 1 1
+$sudo mknod $initrdmnt/dev/systty c 4 0
+for i in 1 2 3 4; do $sudo mknod $initrdmnt/dev/tty$i c 4 $i; done
+if [ "$quiet" == "n" ]; then
+  df -h $initrdmnt
+fi
+$sudo umount $initrdmnt
+
+# Create output file
+initrd_suffix=`echo $requested_modules | tr " " .`
+gzip -9 -n -c $initrdimg > $output_dir/initrd-$initrd_suffix.$kernel_ver.img
+
+# Create symlink
+if [ "$make_link" == "y" ]; then
+  link=$output_dir/initrd-$initrd_suffix.img
+  [ -L $link ] && rm -f $link
+  ln -s initrd-$initrd_suffix.$kernel_ver.img $link
+fi
+
+# Remove temporary files
+if [ "$keep" == "n" ]; then
+  rm -rf $initrd
+  rm -f $initrdimg
+  rmdir $initrdmnt
+fi
diff --git a/contrib/initrd/mkinitrd-net.spec b/contrib/initrd/mkinitrd-net.spec
new file mode 100644 (file)
index 0000000..94f5d9d
--- /dev/null
@@ -0,0 +1,112 @@
+%define name mkinitrd-net
+%define version 1.10
+%define release 1fs
+
+Summary: Network-booting initrd builder 
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Source0: %{name}-%{version}.tar.bz2
+Source1: http://belnet.dl.sourceforge.net/sourceforge/etherboot/mknbi-1.2.tar.bz2
+Source2: http://www.busybox.net/downloads/busybox-0.60.3.tar.bz2
+Source3: http://www.uclibc.org/downloads/uClibc-0.9.11.tar.bz2
+Source4: ftp://ftp.linux-wlan.org/pub/linux-wlan-ng/linux-wlan-ng-0.1.13.tar.bz2
+Source5: http://udhcp.busybox.net/source/udhcp-0.9.7.tar.bz2
+Copyright: GPL/LGPL/MPL
+Group: System/Kernel and hardware
+BuildRoot: %{_tmppath}/%{name}-buildroot
+Prefix: %{_prefix}
+Requires: tftp-server
+
+%description
+mkinitrd-net allows you to build initial ramdisk images (initrds) suitable
+for use with Etherboot and other network-booting software.  This package
+contains two main utilities: mkinitrd-net (to build an initrd containing a
+specified set of network-card modules) and mknbi (to generate
+Etherboot-usable NBI images from a given kernel and initrd).  It also
+contains a helper script mknbi-set which will maintain sets of initrds to
+match all your currently-installed kernels.
+
+mkinitrd-net uses code from the uClibc, busybox, udhcp and Etherboot
+projects.
+
+%prep
+%setup -n initrd -a1 -a2 -a3 -a4 -a5
+
+%build
+%make LIBDIR=%{_libdir}/mknbi
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%makeinstall tftpbootdir=$RPM_BUILD_ROOT%{_localstatedir}/tftpboot
+touch $RPM_BUILD_ROOT%{_sysconfdir}/dhcpd.conf.etherboot-pcimap.include
+ln -s %{_localstatedir}/tftpboot $RPM_BUILD_ROOT/tftpboot
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+%{_bindir}/mknbi-set
+
+%triggerin -- kernel kernel-smp kernel-secure kernel-enterprise
+%{_bindir}/mknbi-set
+
+%files
+%defattr(-,root,root)
+%config(noreplace) %{_sysconfdir}/mknbi-set.conf
+%config(noreplace) %{_sysconfdir}/dhcpd.conf.etherboot.include
+%ghost %{_sysconfdir}/dhcpd.conf.etherboot-pcimap.include
+%{_bindir}/mknbi-*
+%{_bindir}/mkelf-*
+%{_bindir}/dis*
+%{_bindir}/mkinitrd-net
+%{_bindir}/include-modules
+%{_libdir}/mknbi
+%{_libdir}/mkinitrd-net
+%{_mandir}/man*/*
+/tftpboot
+%{_localstatedir}/tftpboot
+%doc README
+%doc AUTHORS.busybox LICENSE.busybox
+%doc AUTHORS.udhcpc COPYING.udhcpc
+%doc COPYING.wlanctl LICENSE.wlanctl THANKS.wlanctl
+%doc COPYING.uClibc
+%docdir %{_docdir}/mknbi*
+%{_docdir}/mknbi*
+
+%changelog
+* Fri Jul 26 2002 Michael Brown <mbrown@fensystems.co.uk> 1.10-1fs
+- Support for new binary etherboot.nic-dev-id structure
+- Added --kernel option patch from Stew Benedict at MandrakeSoft
+- Only try to use sudo if we are not already root
+
+* Wed Jun 05 2002 Michael Brown <mbrown@fensystems.co.uk> 1.9-1fs
+- Modifications to allow DHCP, TFTP and NFS servers to be separate machines.
+
+* Thu May 30 2002 Michael Brown <mbrown@fensystems.co.uk> 1.8-1fs
+- /tftpboot symlinked to /var/lib/tftpboot
+- Has ability to be quiet if "quiet" specified on kernel cmdline
+
+* Sun May 26 2002 Michael Brown <mbrown@fensystems.co.uk> 1.7-1fs
+- PCI-ID auto-mapping via dhcpd.conf.etherboot-pcimap.include
+
+* Fri May 24 2002 Michael Brown <mbrown@fensystems.co.uk> 1.6-1fs
+- Bugfixes, migrated /tftpboot to /var/lib/tftpboot
+
+* Thu May 23 2002 Michael Brown <mbrown@fensystems.co.uk> 1.5-1fs
+- Now includes dhcpd.conf.etherboot.include
+- Automatically scans for all network modules in the pcimap file
+
+* Wed May 08 2002 Michael Brown <mbrown@fensystems.co.uk> 1.4-1fs
+- Bugfixes: tmpdir selection, linuxrc typos, ifconfig peculiarities
+
+* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.3-1fs
+- During %make, LIBDIR must be set for mknbi
+- Added %post scriptlet since %trigger seems not to be being triggered...
+
+* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.2-1fs
+- Added extra sources instead of requiring "make" to download them
+
+* Sat May 04 2002 Michael Brown <mbrown@fensystems.co.uk> 1.1-1fs
+- First attempt at an RPM package
+
diff --git a/contrib/initrd/mknbi-set b/contrib/initrd/mknbi-set
new file mode 100755 (executable)
index 0000000..e61acac
--- /dev/null
@@ -0,0 +1,200 @@
+#!/usr/bin/perl -w
+#
+# $Id$
+# Maintains set of NBIs based on currently-installed kernels
+# Network card module sets are taken from /etc/mknbi-set.conf
+
+use strict;
+use vars qw($verbosity);
+
+use constant EB_PCI_DEVICE => 1;
+
+# Utility function: calculate output id given a kernel file name and
+# space-separated list of modules
+sub calc_output_id ($$) {
+  my $kernel = shift;
+  my $moduleset = shift;
+  my $kernel_ver = "";
+  ( $kernel_ver ) = ( $kernel =~ /vmlinuz-(.*)$/ );
+  ( my $output_id = "$moduleset".( $kernel_ver ? ".$kernel_ver" : "" ) ) =~ tr/,/./;
+  return ( $kernel_ver, $output_id );
+}
+
+# Utility function: read modules.pcimap-style file
+# Add modules to modulesets hash, write out dhcpd.conf fragment
+sub read_config_file ($$$$) {
+  my $configfile = shift;
+  my $modulesets = shift;
+  my $dhcpfh = shift;
+  my $alwaysuse = shift;
+
+  print "Scanning through $configfile for network modules...\n" if $verbosity >= 1;
+  open CF, $configfile or die "Could not open $configfile: $!\n";
+  chomp ( my $tempmodule = `mktemp /tmp/mknbi-set.XXXXXX` );
+  chomp ( my $cwd = `pwd` ); chdir '/'; # Modprobe searches the current directory...
+  print $dhcpfh "    \# Generated from $configfile\n";
+  while (<CF>) {
+    chomp;
+    next if /^[\#;]/ or /^\s*$/;
+    ( my $module, undef, my $vendor, my $device ) = /^(\S+)(\s+(\S+)\s+(\S+))?/ ;
+    $modulesets->{$module} = 1 if $alwaysuse;
+    if ( ! exists $modulesets->{$module} ) {
+      # Check to see if module is a network module
+      # Only do this the first time we encounter a module
+      my @modulepaths = `/sbin/modprobe -l $module.o*` ;
+      chomp ( my $modulepath = $modulepaths[0] );
+      if ( $modulepath ) {
+       if ( $modulepath =~ /.o.gz$/ ) {
+         system ( "zcat $modulepath > $tempmodule" );
+       } else {
+         system ( "cp $modulepath $tempmodule" );
+       }
+       $modulesets->{$module} = 0;
+       foreach ( `nm $tempmodule` ) {
+         chomp;
+         $modulesets->{$module} = 1 if /(ether|wlan)/ ;
+       }
+       unlink $tempmodule;
+      } else {
+       print STDERR "Cannot locate module $module specified in $configfile\n";
+      }
+    }
+    if ( $modulesets->{$module} ) {
+      if ( $vendor ) {
+       print "$module ($vendor,$device) listed in $configfile\n" if $verbosity >= 2;
+       printf $dhcpfh ( "    if option etherboot.nic-dev-id = %02x:%02x:%02x:%02x:%02x { option etherboot.kmod \"%s\"; }\n",
+                        EB_PCI_DEVICE,
+                        ( hex($vendor) >> 8 ) & 0xff, hex($vendor) & 0xff,
+                        ( hex($device) >> 8 ) & 0xff, hex($device) & 0xff,
+                        $module );
+      } else {
+       print "$module (without PCI IDs) listed in $configfile\n" if $verbosity >= 2;
+      }
+    }
+  }
+  close CF;
+  print $dhcpfh "\n";
+  chdir $cwd;
+}
+
+my $conffile = '/etc/mknbi-set.conf';
+my $mkinitrd_net = 'mkinitrd-net';
+my $mknbi = 'mknbi-linux';
+my $output_dir = '/var/lib/tftpboot';
+my $dhcpfile = '/etc/dhcpd.conf.etherboot-pcimap.include';
+my $use_local;
+our $verbosity = 1;
+my $modulesets = {};
+my $kernel = '';
+my @kernels = ();
+
+my $usage="Usage: $0 [-l|--local] [-q] [-v] [-r|--refresh module[,module...]] [--help]";
+
+# Parse command-line options
+while ( $_ = shift ) {
+  if ( /-l|--local/ ) {
+    $conffile = 'mknbi-set.conf';
+    $mkinitrd_net = './mkinitrd-net';
+    $mknbi = './mknbi-linux --format=nbi --target=linux';
+    $output_dir = 'tftpboot';
+    $dhcpfile = 'tftpboot/dhcpd.conf.etherboot-pcimap.include';
+    $use_local = 1;
+  } elsif ( /-r|--refresh/ ) {
+    my $moduleset = shift;
+    $modulesets->{$moduleset} = 1;
+  } elsif ( /-k|--kernel/ ) {
+    $kernel = shift;
+  } elsif ( /-v|--verbose/ ) {
+    $verbosity++;
+  } elsif ( /-q|--quiet/ ) {
+    $verbosity--;
+  } elsif ( /--help/ ) {
+    die "$usage\n".
+       "  -k, --kernel   Build NBIs for a particular kernel\n".
+        "  -l, --local    Run locally from CVS (for developers only)\n".
+       "  -r, --refresh  Refresh NBI for a particular module\n".
+       "  -v, --verbose  Be more verbose\n".
+       "  -q, --quiet    Be less verbose\n";
+  } else {
+    die "$usage\n";
+  }
+}
+
+# Get set of current kernels
+if ($kernel) {
+  @kernels = ( $kernel );
+} else {
+  @kernels = glob('/boot/vmlinuz*');
+}
+die "Could not find any kernels in /boot\n" unless @kernels;
+
+# If modules have been specified via --refresh, do not scan for modules or rewrite the
+# dhcpd.conf fragment file
+unless ( %$modulesets ) {
+  # Write dhcpd.conf fragment file
+  open my $dhcpfh, ">$dhcpfile" or die "Could not open $dhcpfile for writing: $!\n";
+  print $dhcpfh "# Etherboot PCI ID -> Linux kernel module mapping file\n";
+  print $dhcpfh "# Generated by mknbi-set on ".(scalar localtime)."\n";
+  print $dhcpfh "#\n";
+  print $dhcpfh "if substring ( option vendor-class-identifier, 0, 9 ) = \"Etherboot\" {\n";
+  print $dhcpfh "  if exists etherboot.nic-dev-id {\n";
+  print $dhcpfh "    \# Legacy nic-dev-id mechanism: there are some DLink DFE538 cards in circulation that\n";
+  print $dhcpfh "    \# predated the change to the new nic-dev-id binary structure\n";
+  print $dhcpfh "    if option etherboot.nic-dev-id = \"PCI:1186:1300\" { option etherboot.kmod \"8139too\"; }\n";
+  print $dhcpfh "\n";
+
+  # Get set of network modules to build NBIs for
+  # Read explicitly-specified module sets from $conffile
+  read_config_file($conffile, $modulesets, $dhcpfh, 1);
+  # Obtain list of all network modules from pcimap file
+  my $pcimap;
+  foreach ( `/sbin/modprobe -c` ) {
+    $pcimap = $1 if /^pcimap.*?=(.*)$/;
+  }
+  if ( $pcimap ) {
+    read_config_file($pcimap, $modulesets, $dhcpfh, 0);
+  } else {
+    print STDERR "Could not identify pcimap file\n";
+  }
+  # Finish off dhcpd.conf fragment file
+  print $dhcpfh "  }\n}\n";
+  close $dhcpfh;
+}
+
+# Build initrd and nbi for each kernel-moduleset combination
+foreach my $moduleset ( sort keys %$modulesets ) {
+  next unless $modulesets->{$moduleset}; # Ignore if value is 0
+  print "Building NBIs for module set $moduleset\n" if $verbosity >= 1;
+  foreach my $kernel ( @kernels ) {
+    ( my $kernel_ver, my $output_id ) = calc_output_id ( $kernel, $moduleset );
+    if ( -l $kernel ) {
+      # Symbolic link; create matching symlink
+      my $real_kernel = readlink ( $kernel );
+      ( my $real_kernel_ver, my $real_output_id ) = calc_output_id ( $real_kernel, $moduleset );
+      print "Symlinking $output_id to $real_output_id\n" if $verbosity >= 2;
+      my $initrd_file = "$output_dir/initrd-$output_id.img";
+      unlink ( $initrd_file ) if -l $initrd_file;
+      system ( "ln -s initrd-$real_output_id.img $initrd_file" ) == 0 or print STDERR "Could not symlink $initrd_file to initrd-$real_output_id.img: $!\n";
+      my $nbi_file = "$output_dir/boot-$output_id.nbi";
+      unlink ( $nbi_file ) if -l $nbi_file;
+      system ( "ln -s boot-$real_output_id.nbi $nbi_file" ) == 0 or print STDERR "Could not symlink $nbi_file to boot-$real_output_id.nbi: $!\n";
+    } else {
+      # Real file: create initrd and nbi
+      print "Creating initrd and nbi for $output_id\n" if $verbosity >= 2;
+      ( my $moduleset_spaces = $moduleset ) =~ tr/,/ /;
+      my $initrd_cmd = "$mkinitrd_net --nolink ".
+         ( $use_local ? "--local " : "" ).
+             ( $kernel_ver ? "--kernel $kernel_ver " : "" ).
+                 ( $verbosity >= 2 ? "" : "-q " ).
+                     $moduleset_spaces;
+      print "$initrd_cmd\n" if $verbosity >= 3;
+      if ( system ( $initrd_cmd ) == 0 ) {
+       my $mknbi_cmd = "$mknbi $kernel $output_dir/initrd-$output_id.img > $output_dir/boot-$output_id.nbi";
+       print "$mknbi_cmd\n" if $verbosity >= 3;
+       system ( $mknbi_cmd ) == 0 or print STDERR "mknbi failed: $!\n";
+      } else {
+       print STDERR "$initrd_cmd failed: $!\n";
+      }
+    }
+  }
+}
diff --git a/contrib/initrd/mknbi-set.conf b/contrib/initrd/mknbi-set.conf
new file mode 100644 (file)
index 0000000..f24846c
--- /dev/null
@@ -0,0 +1,27 @@
+# This file specifies the network cards for which NBI images should be built
+# Each line contains a list of kernel modules to be used, separated by commas
+# You can optionally specify PCI vendor and device IDs that should be automatically
+# mapped to this module.
+#
+# The format is similar to modutils' modules.pcimap file.
+#
+# Examples:
+#   RTL8139-based ethernet card
+; 8139too
+#   RTL8139-based ethernet card with PCI IDs vendor=0x1186, device=0x1300
+; 8139too      0x1186  0x1300
+#   RTL8139 and Prism2_pci in same image
+; 8139too,prism2_pci
+
+# Some modules do not include the MODULE_DEVICE_TABLE macro, and so end up not
+# being listed in the pcimap file.  These modules are included here to force
+# the creation of corresponding initrds.
+prism2_pci     0x1260  0x3873
+prism2_plx     0x1638  0x1100
+prism2_plx     0x16ab  0x1101
+prism2_plx     0x16ab  0x1102
+prism2_plx     0x1385  0x4100
+prism2_plx     0x15e8  0x0130
+prism2_plx     0x16ec  0x3685
+prism2_plx     0x16ab  0x1102
+prism2_plx     0x15e8  0x0131
diff --git a/contrib/initrd/script.c.patch b/contrib/initrd/script.c.patch
new file mode 100644 (file)
index 0000000..127b881
--- /dev/null
@@ -0,0 +1,11 @@
+--- script.c.orig      Tue Apr  2 23:49:33 2002
++++ script.c   Wed Jun  5 14:17:22 2002
+@@ -179,7 +179,7 @@
+       }
+       if (packet->siaddr) {
+               envp[j] = malloc(sizeof("siaddr=255.255.255.255"));
+-              sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->yiaddr);
++              sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->siaddr);
+       }
+       if (!(over & FILE_FIELD) && packet->file[0]) {
+               /* watch out for invalid packets */
diff --git a/contrib/initrd/udhcpc-post b/contrib/initrd/udhcpc-post
new file mode 100644 (file)
index 0000000..395d6c5
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+# $Id$
+
+if [ "$1" = "deconfig" ]; then
+  ifconfig $interface 0.0.0.0 up
+else if [ "$1" = "bound" ] ; then
+    echo UDHCPC: I am $ip [$hostname], booting from $serverid
+    [ -n "$hostname" ] && echo $hostname > /proc/sys/kernel/hostname
+    [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
+    [ -n "$subnet" ] && NETMASK="netmask $subnet" 
+    ifconfig $interface $ip $BROADCAST $NETMASK
+    route add default gw $router dev $interface
+    echo -n > /etc/resolv.conf
+    for i in $dns; do
+      echo nameserver $i >> /etc/resolv.conf
+    done
+    [ -n "$siaddr" ] || siaddr=$serverid
+    [ -n "$rootpath" ] || rootpath=$siaddr:/
+    echo Mounting root filesystem $rootpath at /sysroot
+    echo If this appears to hang, check that the server of $rootpath is able to
+    echo reverse-map my IP address $ip to obtain my hostname $hostname
+    mount -t nfs -o nolock,rsize=8192,wsize=8192 $rootpath /sysroot
+  fi
+fi
+
diff --git a/contrib/linux-2.0-transname.lsm b/contrib/linux-2.0-transname.lsm
new file mode 100644 (file)
index 0000000..4a59096
--- /dev/null
@@ -0,0 +1,93 @@
+Xref: news.nsw.CSIRO.AU comp.os.linux.announce:2827
+Path: news.nsw.CSIRO.AU!metro!metro!munnari.OZ.AU!news.ecn.uoknor.edu!news.wildstar.net!news.ececs.uc.edu!newsrelay.netins.net!newsfeed.dacom.co.kr!arclight.uoregon.edu!feed1.news.erols.com!howland.erols.net!newsfeed.internetmci.com!in3.uu.net!liw.clinet.fi!usenet
+From: schoebel@informatik.uni-stuttgart.de (Thomas Schoebel-Theuer)
+Newsgroups: comp.os.linux.announce
+Subject: linux-2.0.21-transname - Patch for easier pool administration
+Followup-To: comp.os.linux.misc
+Date: 30 Oct 1996 10:53:38 GMT
+Organization: Informatik, Uni Stuttgart, Germany
+Lines: 76
+Approved: linux-announce@news.ornl.gov (Lars Wirzenius)
+Message-ID: <pgpmoose.199610301253.4416@liw>
+NNTP-Posting-Host: liw
+X-Auth: PGPMoose V1.1 PGP comp.os.linux.announce
+       iQBVAwUBMnczrjiesvPHtqnBAQEO6gH/WRtFpTPyVtwi0cFVPZ1Xhn8cvfb6i3mk
+       LQY2kgpAPquP2TeXYWb5Ta3HxqK15pR1AgaEy5BmPS6+66ixZFvKRQ==
+       =hhea
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+linux-2.0.21-transname.patch enables diskless clients, X-terminals etc to
+mount the *root filesystem* of the server. This makes administration of
+large pools *a lot* easier.
+
+Currently different diskless clients must have their root "/" on different
+directories on the server, beause each client has _some_ different
+configuration files. However, most administration files (typically about 99%)
+have the same contents on the clients and on the server, but have to be
+(and maintained separately) just because of the 1% differences.
+
+This duplication causes very large efforts in practice, since at least
+the /etc directory has to be duplicated for every client. Even in /etc
+many files are identical, for example sendmail.cf, initrc scripts and
+others. Maintaining a large pool means to ensure coherence amoung the
+duplicates. Classical methods like symlinks are unconvenient
+for this task because they have to be valid in the view of mounted
+filesystems at the client, not at the server.
+
+linux-2.0-transname.patch overcomes this problem by allowing filenames
+to be context-dependend. For example, if you have a file "/etc/config"
+that should differ on the hosts "myserver" and "myclient", you just
+create two different files named "/etc/config#host=myserver#" and
+"/etc/config#host=myclient#". On host "myserver", the file
+"/etc/config#host=myserver#" will appear as if it were hardlinked to
+file "/etc/config" (without the #...=...# suffix). On host "myclient",
+the corresponding other file will appear as "/etc/config". So you
+can access the right file contents under the same name, depending
+on which host you are.
+
+As a result, you may use different contexts for e.g. /etc/fstab, but
+have one shared /etc/passwd for all pool machines. So you don't need
+yp or NYS any more.
+
+The kernel patch was developped for and is used at our Linux pool at the
+University of Stuttgart with good results. Maintainance of the pool is
+at a minimum, and adding new clients is a child's play. No worry with
+keeping up mail configurations, newly installed tools, changed /etc/services,
+/etc/shells, /etc/resolv.conf and many, many others. In contrast to a
+sophisticated symlink solution, adding a new file to the /etc directory
+is seen immediately by all clients. I never had less trouble with
+administration before.
+
+I just uploaded the patch to
+  ftp://ftp.lmh.ox.ac.uk
+         where it should appear in /pub/linux-kernel-patch-archive/
+and also to
+  ftp://sunsite.unc.edu/pub/Linux/Incoming/
+         where it should be moved to /pub/Linux/kernel/patches/misc/ soon.
+
+More details can be found in the README there, and also in the
+configure-help.
+
+Enjoy,
+
+- -- Thomas
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.3i
+Charset: noconv
+
+iQCVAwUBMnczhYQRll5MupLRAQHzuwP9HGYa4I3bZpt22Y3oQIwEKZGfvnaS5AaD
+fVG8wOQ/T7Nrant9JtTktsTVlxGVlYVnziRY4c0ew2qExapK9FqY/ItN0NJXy5aT
+a4eSkn86rp6Un7m90RK1xVY5AyVAq49Rdw2StGxr7uj+davnmg3Np+U0MiAILq91
+52jKGaR3fvc=
+=LSD6
+-----END PGP SIGNATURE-----
+
+-- 
+This article has been digitally signed by the moderator, using PGP.
+http://www.iki.fi/liw/lars-public-key.asc has PGP key for validating signature.
+Send submissions for comp.os.linux.announce to: linux-announce@news.ornl.gov
+PLEASE remember a short description of the software and the LOCATION.
+This group is archived at http://www.iki.fi/liw/linux/cola.html
diff --git a/contrib/linux-3c503-patch/3c503.patch b/contrib/linux-3c503-patch/3c503.patch
new file mode 100644 (file)
index 0000000..b27ff1f
--- /dev/null
@@ -0,0 +1,24 @@
+diff -Naur linux.orig/drivers/net/3c503.c linux/drivers/net/3c503.c
+--- linux.orig/drivers/net/3c503.c     Thu Feb 19 23:14:04 1998
++++ linux/drivers/net/3c503.c  Thu Feb 19 23:16:24 1998
+@@ -179,7 +179,8 @@
+        for both the old and new 3Com prefix */
+     outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
+     vendor_id = inb(ioaddr)*0x10000 + inb(ioaddr + 1)*0x100 + inb(ioaddr + 2);
+-    if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) {
++    if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID) &&
++      (vendor_id != BULL_3COM_ID)) {
+       /* Restore the register we frobbed. */
+       outb(saved_406, ioaddr + 0x406);
+       return ENODEV;
+diff -Naur linux.orig/drivers/net/3c503.h linux/drivers/net/3c503.h
+--- linux.orig/drivers/net/3c503.h     Thu Feb 19 23:14:05 1998
++++ linux/drivers/net/3c503.h  Mon Feb 16 11:41:56 1998
+@@ -11,6 +11,7 @@
+ #define OLD_3COM_ID   0x02608c
+ #define NEW_3COM_ID   0x0020af
++#define BULL_3COM_ID  0x000062
+ /* Shared memory management parameters. NB: The 8 bit cards have only
+    one bank (MB1) which serves both Tx and Rx packet space. The 16bit
diff --git a/contrib/linux-3c503-patch/README b/contrib/linux-3c503-patch/README
new file mode 100644 (file)
index 0000000..109094f
--- /dev/null
@@ -0,0 +1,7 @@
+As part of determining whether a 3c503 is present, the Linux driver
+examines the first 3 bytes of the ethernet address (the vendor ID)
+to see if it corresponds to a known 3Com vendor ID.
+
+The Bull discless 386 workstation I have (don't laugh) has an
+unknown vendor ID 0x000062. This trivial patch adds it to those
+known to the driver.
diff --git a/contrib/mini-slamd/COPYING b/contrib/mini-slamd/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/mini-slamd/Makefile b/contrib/mini-slamd/Makefile
new file mode 100644 (file)
index 0000000..05f1a36
--- /dev/null
@@ -0,0 +1,8 @@
+CC=gcc
+CFLAGS=-Wall -O2
+
+mini-slamd: mini-slamd.c
+       $(CC) $(CFLAGS) -o $@ $<
+
+clean:
+       rm -f mini-slamd
\ No newline at end of file
diff --git a/contrib/mini-slamd/mini-slamd.c b/contrib/mini-slamd/mini-slamd.c
new file mode 100644 (file)
index 0000000..7c33e22
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * mini-slamd
+ * (c) 2002 Eric Biederman
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/ip.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+/*
+ * To specify the default interface for multicast packets use:
+ * route add -net 224.0.0.0 netmask 240.0.0.0 dev eth1
+ * This server is stupid and does not override the default.
+ */
+
+/* Sever states.
+ *
+ * Waiting for clients.
+ * Sending data to clients.
+ * Pinging clients for data.
+ *
+ */
+#define SLAM_PORT 10000
+#define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
+#define SLAM_MULTICAST_PORT 10000
+#define SLAM_MULTICAST_TTL 1
+#define SLAM_MULTICAST_LOOPBACK 1
+#define SLAM_MAX_CLIENTS 10
+
+#define SLAM_PING_TIMEOUT      100 /* ms */
+
+/*** Packets Formats ***
+ * Data Packet:
+ *   transaction
+ *   total bytes
+ *   block size
+ *   packet #
+ *   data
+ *
+ * Status Request Packet
+ *   transaction
+ *   total bytes
+ *   block packets
+ *
+ * Status Packet
+ *   received packets
+ *   requested packets
+ *   received packets
+ *   requested packets
+ *   ...
+ *   received packets
+ *   requested packtes
+ *   0
+ */
+
+#define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
+#define MIN_HDR (1 + 1 + 1) /* transaction, total size, block size */
+
+#define MAX_DATA_HDR (MAX_HDR + 7) /* header, packet # */
+#define MIN_DATA_HDR (MAX_HDR + 1) /* header, packet # */
+
+/* ETH_MAX_MTU 1500 - sizeof(iphdr) 20  - sizeof(udphdr) 8 = 1472 */
+#define SLAM_MAX_NACK          (1500 - (20 + 8))
+/* ETH_MAX_MTU 1500 - sizeof(iphdr) 20  - sizeof(udphdr) 8 - MAX_HDR = 1451 */
+#define SLAM_BLOCK_SIZE                (1500 - (20 + 8 + MAX_HDR))
+
+
+/* Define how many debug messages you want 
+ * 1 - sparse but useful
+ * 2 - everything
+ */
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+static int slam_encode(
+       unsigned char **ptr, unsigned char *end, unsigned long value)
+{
+       unsigned char *data = *ptr;
+       int bytes;
+       bytes = sizeof(value);
+       while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) {
+               bytes--;
+       }
+       if (bytes <= 0) {
+               bytes = 1;
+       }
+       if (data + bytes >= end) {
+               return -1;
+       }
+       if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) {
+               /* packed together */
+               *data = (bytes << 5) | (value >> ((bytes -1)<<3));
+       } else {
+               bytes++;
+               *data = (bytes << 5);
+       }
+       bytes--;
+       data++;
+       while(bytes) {
+               *(data++) = 0xff & (value >> ((bytes -1)<<3));
+               bytes--;
+       }
+       *ptr = data;
+       return 0;
+}
+
+static unsigned long slam_decode(unsigned char **ptr, unsigned char *end, int *err)
+{
+       unsigned long value;
+       unsigned bytes;
+       if (*ptr >= end) {
+               *err = -1;
+       }
+       bytes = ((**ptr) >> 5) & 7;
+       if ((bytes == 0) || (bytes > sizeof(unsigned long))) {
+               *err = -1;
+               return 0;
+       }
+       if ((*ptr) + bytes >= end) {
+               *err =  -1;
+       }
+       value = (**ptr) & 0x1f;
+       bytes--;
+       (*ptr)++;
+       while(bytes) {
+               value <<= 8;
+               value |= **ptr;
+               (*ptr)++;
+               bytes--;
+       }
+       return value;
+}
+
+
+static struct sockaddr_in client[SLAM_MAX_CLIENTS];
+static int clients;
+
+
+void del_client(struct sockaddr_in *old)
+{
+       int i;
+       for(i = 0; i < clients; i++) {
+               if ((client[i].sin_family == old->sin_family) &&
+                       (client[i].sin_addr.s_addr == old->sin_addr.s_addr) &&
+                       (client[i].sin_port == old->sin_port)) {
+                       memmove(&client[i], &client[i+1],
+                               (clients - (i+1))*sizeof(client[0]));
+                       clients--;
+               }
+       }
+}
+
+void add_client(struct sockaddr_in *new)
+{
+       del_client(new);
+       if (clients >= SLAM_MAX_CLIENTS)
+               return;
+       memcpy(&client[clients], new, sizeof(*new));
+       clients++;
+}
+
+void push_client(struct sockaddr_in *new)
+{
+       del_client(new);
+       if (clients >= SLAM_MAX_CLIENTS) {
+               clients--;
+       }
+       memmove(&client[1], &client[0], clients*sizeof(*new));
+       memcpy(&client[0], new, sizeof(*new));
+       clients++;
+}
+
+
+void next_client(struct sockaddr_in *next)
+{
+       /* Find the next client we want to ping next */
+       if (!clients) {
+               next->sin_family = AF_UNSPEC;
+               return;
+       }
+       /* Return the first client */
+       memcpy(next, &client[0], sizeof(*next));
+}
+
+int main(int argc, char **argv)
+{
+       char *filename;
+       uint8_t nack_packet[SLAM_MAX_NACK];
+       int nack_len;
+       uint8_t request_packet[MAX_HDR];
+       int request_len;
+       uint8_t data_packet[MAX_DATA_HDR +  SLAM_BLOCK_SIZE];
+       int data_len;
+       uint8_t *ptr, *end;
+       struct sockaddr_in master_client;
+       struct sockaddr_in sa_src;
+       struct sockaddr_in sa_mcast;
+       uint8_t mcast_ttl;
+       uint8_t mcast_loop;
+       int sockfd, filefd;
+       int result;
+       struct pollfd fds[1];
+       int state;
+#define STATE_PINGING      1
+#define STATE_WAITING      2
+#define STATE_RECEIVING    3
+#define STATE_TRANSMITTING 4
+       off_t size;
+       struct stat st;
+       uint64_t transaction;
+       unsigned long packet;
+       unsigned long packet_count;
+       unsigned slam_port, slam_multicast_port;
+       struct in_addr slam_multicast_ip;
+
+       slam_port = SLAM_PORT;
+       slam_multicast_port = SLAM_MULTICAST_PORT;
+       slam_multicast_ip.s_addr = htonl(SLAM_MULTICAST_IP);
+       
+       if (argc != 2) {
+               fprintf(stderr, "Bad argument count\n");
+               fprintf(stderr, "Usage: mini-slamd filename\n");
+               exit(EXIT_FAILURE);
+       }
+       filename = argv[1];
+       filefd = -1;
+       size = 0;
+       transaction = 0;
+
+       /* Setup the udp socket */
+       sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0) {
+               fprintf(stderr, "Cannot create socket\n");
+               exit(EXIT_FAILURE);
+       }
+       memset(&sa_src, 0, sizeof(sa_src));
+       sa_src.sin_family = AF_INET;
+       sa_src.sin_port = htons(slam_port);
+       sa_src.sin_addr.s_addr = INADDR_ANY;
+
+       result = bind(sockfd, &sa_src, sizeof(sa_src));
+       if (result < 0) { 
+               fprintf(stderr, "Cannot bind socket to port %d\n", 
+                       ntohs(sa_src.sin_port));
+               exit(EXIT_FAILURE);
+       }
+
+       /* Setup the multicast transmission address */
+       memset(&sa_mcast, 0, sizeof(sa_mcast));
+       sa_mcast.sin_family = AF_INET;
+       sa_mcast.sin_port = htons(slam_multicast_port);
+       sa_mcast.sin_addr.s_addr = slam_multicast_ip.s_addr;
+       if (!IN_MULTICAST(ntohl(sa_mcast.sin_addr.s_addr))) {
+               fprintf(stderr, "Not a multicast ip\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Set the multicast ttl */
+       mcast_ttl = SLAM_MULTICAST_TTL;
+       setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
+               &mcast_ttl, sizeof(mcast_ttl));
+
+       /* Set the multicast loopback status */
+       mcast_loop = SLAM_MULTICAST_LOOPBACK;
+       setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &mcast_loop, sizeof(mcast_loop));
+
+
+       state = STATE_WAITING;
+       packet = 0;
+       packet_count = 0;
+       fds[0].fd = sockfd;
+       fds[0].events = POLLIN;
+       fds[0].revents = 0;
+       for(;;) {
+               switch(state) {
+               case STATE_PINGING:
+                       state = STATE_WAITING;
+                       next_client(&master_client);
+                       if (master_client.sin_family == AF_UNSPEC) {
+                               break;
+                       }
+#if DEBUG
+                       printf("Pinging %s:%d\n", 
+                               inet_ntoa(master_client.sin_addr),
+                               ntohs(master_client.sin_port));
+                       fflush(stdout);
+#endif
+
+                       /* Prepare the request packet, it is all header */
+                       ptr = request_packet;
+                       end = &request_packet[sizeof(request_packet) -1];
+                       slam_encode(&ptr, end, transaction);
+                       slam_encode(&ptr, end, size);
+                       slam_encode(&ptr, end, SLAM_BLOCK_SIZE);
+                       request_len = ptr - request_packet;
+
+                       result = sendto(sockfd, request_packet, request_len, 0,
+                               &master_client, sizeof(master_client));
+                       /* Forget the client I just asked, when the reply
+                        * comes in we will remember it again.
+                        */
+                       del_client(&master_client);
+                       break;
+               case STATE_WAITING:
+               {
+                       int timeout;
+                       int from_len;
+                       timeout = -1;
+                       if (master_client.sin_family != AF_UNSPEC) {
+                               timeout = SLAM_PING_TIMEOUT;
+                       }
+                       result = poll(fds, sizeof(fds)/sizeof(fds[0]), timeout);
+                       if (result == 0) {
+                               /* On a timeout try the next client */
+                               state = STATE_PINGING;
+                               break;
+                       }
+                       if (result > 0) {
+                               from_len = sizeof(master_client);
+                               result = recvfrom(sockfd, 
+                                       nack_packet,    sizeof(nack_packet), 0,
+                                       &master_client, &from_len);
+                               if (result < 0)
+                                       break;
+                               nack_len = result;
+#if DEBUG
+                               printf("Received Nack from %s:%d\n",
+                                       inet_ntoa(master_client.sin_addr),
+                                       ntohs(master_client.sin_port));
+                               fflush(stdout);
+#endif
+#if DEBUG
+                               {
+                                       ptr = nack_packet;
+                                       end = ptr + result;
+                                       packet = 0;
+                                       result = 0;
+                                       while(ptr < end) {
+                                               packet += slam_decode(&ptr, end, &result);
+                                               if (result < 0) break;
+                                               packet_count = slam_decode(&ptr, end, &result);
+                                               if (result < 0) break;
+                                               printf("%d-%d ",
+                                                       packet, packet + packet_count -1);
+                                       }
+                                       printf("\n");
+                                       fflush(stdout);
+                               }
+#endif
+                               /* Forget this client temporarily.
+                                * If the packet appears good they will be
+                                * readded.
+                                */
+                               del_client(&master_client);
+                               ptr = nack_packet;
+                               end = ptr + nack_len;
+                               result = 0;
+                               packet = slam_decode(&ptr, end, &result);
+                               if (result < 0)
+                                       break;
+                               packet_count = slam_decode(&ptr, end, &result);
+                               if (result < 0)
+                                       break;
+                               /* We appear to have a good packet, keep
+                                * this client.
+                                */
+                               push_client(&master_client);
+
+                               /* Reopen the file to transmit */
+                               if (filefd != -1) {
+                                       close(filefd);
+                               }
+                               filefd = open(filename, O_RDONLY);
+                               if (filefd < 0) {
+                                       fprintf(stderr, "Cannot open %s: %s\n",
+                                               filename, strerror(errno));
+                                       break;
+                               }
+                               size = lseek(filefd, 0, SEEK_END);
+                               if (size < 0) {
+                                       fprintf(stderr, "Seek failed on %s: %s\n",
+                                               filename, strerror(errno));
+                                       break;
+                               }
+                               result = fstat(filefd, &st);
+                               if (result < 0) {
+                                       fprintf(stderr, "Stat failed on %s: %s\n",
+                                               filename, strerror(errno));
+                                       break;
+                               }
+                               transaction = st.st_mtime;
+                               
+                               state = STATE_TRANSMITTING;
+                               break;
+                       }
+                       break;
+               }
+               case STATE_RECEIVING:
+                       /* Now clear the queue of received packets */
+               {
+                       struct sockaddr_in from;
+                       int from_len;
+                       uint8_t dummy_packet[SLAM_MAX_NACK];
+                       state = STATE_TRANSMITTING;
+                       result = poll(fds, sizeof(fds)/sizeof(fds[0]), 0);
+                       if (result < 1)
+                               break;
+                       from_len = sizeof(from);
+                       result = recvfrom(sockfd, 
+                               dummy_packet, sizeof(dummy_packet), 0,
+                               &from, &from_len);
+                       if (result <= 0)
+                               break;
+#if DEBUG                              
+                       printf("Received Nack from %s:%d\n",
+                               inet_ntoa(from.sin_addr),
+                               ntohs(from.sin_port));
+                       fflush(stdout);
+#endif
+                       /* Receive packets until I don't get any more */
+                       state = STATE_RECEIVING;
+                       /* Process a  packet */
+                       if (dummy_packet[0] == '\0') {
+                               /* If the first byte is null it is a disconnect
+                                * packet.  
+                                */
+                               del_client(&from);
+                       }
+                       else {
+                               /* Otherwise attempt to add the client. */
+                               add_client(&from);
+                       }
+                       break;
+               }
+               case STATE_TRANSMITTING:
+               {
+                       off_t off;
+                       off_t offset;
+                       ssize_t bytes;
+                       uint8_t *ptr2, *end2;
+
+                       /* After I transmit a packet check for packets to receive. */
+                       state = STATE_RECEIVING;
+
+                       /* Find the packet to transmit */
+                       offset = packet * SLAM_BLOCK_SIZE;
+
+                       /* Seek to the desired packet */
+                       off = lseek(filefd, offset, SEEK_SET);
+                       if ((off < 0) || (off != offset)) {
+                               fprintf(stderr, "Seek failed on %s:%s\n",
+                                       filename, strerror(errno));
+                               break;
+                       }
+                       /* Encode the packet header */
+                       ptr2 = data_packet;
+                       end2 = data_packet + sizeof(data_packet);
+                       slam_encode(&ptr2, end2, transaction);
+                       slam_encode(&ptr2, end2, size);
+                       slam_encode(&ptr2, end2, SLAM_BLOCK_SIZE);
+                       slam_encode(&ptr2, end2, packet);
+                       data_len = ptr2 - data_packet;
+                       
+                       /* Read in the data */
+                       bytes = read(filefd, &data_packet[data_len], 
+                               SLAM_BLOCK_SIZE);
+                       if (bytes <= 0) {
+                               fprintf(stderr, "Read failed on %s:%s\n",
+                                       filename, strerror(errno));
+                               break;
+                       }
+                       data_len += bytes;
+                       /* Write out the data */
+                       result = sendto(sockfd, data_packet, data_len, 0,
+                               &sa_mcast, sizeof(sa_mcast));
+                       if (result != data_len) {
+                               fprintf(stderr, "Send failed %s\n",
+                                       strerror(errno));
+                               break;
+                       }
+#if DEBUG > 1
+                       printf("Transmitted: %d\n", packet);
+                       fflush(stdout);
+#endif
+                       /* Compute the next packet */
+                       packet++;
+                       packet_count--;
+                       if (packet_count == 0) {
+                               packet += slam_decode(&ptr, end, &result);
+                               if (result >= 0)
+                                       packet_count = slam_decode(&ptr, end, &result);
+                               if (result < 0) {
+                                       /* When a transmission is done close the file,
+                                        * so it may be updated.  And then ping then start
+                                        * pinging clients to get the transmission started
+                                        * again.
+                                        */
+                                       state = STATE_PINGING;
+                                       close(filefd);
+                                       filefd = -1;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+               }
+       }
+       return EXIT_SUCCESS;
+}
diff --git a/contrib/mkQNXnbi/Makefile b/contrib/mkQNXnbi/Makefile
new file mode 100644 (file)
index 0000000..4f6c0f2
--- /dev/null
@@ -0,0 +1,10 @@
+# Makefile for the mkQNXnbi filter
+
+all:           mkQNXnbi
+
+mkQNXnbi:      mkQNXnbi.o
+
+mkQNXnbi.o:    mkQNXnbi.c
+
+clean:
+       rm -f mkQNXnbi *.o 
diff --git a/contrib/mkQNXnbi/README b/contrib/mkQNXnbi/README
new file mode 100644 (file)
index 0000000..1522df3
--- /dev/null
@@ -0,0 +1,36 @@
+mkQNXnbi is a quick hack to generate tagged images from QNX boot images.
+
+To boot a QNX client with Etherboot you have to consider the following:
+1. You MUST have another QNX box running in the network to provide the
+   root filesystem and the license info to the client. QNX cannot use
+   e.g. NFS for its root filesystem, as it needs to load a valid license
+   from a file on the root fs before being able to start TCP/IP. This
+   would lead to a chicken-and-egg problem.
+2. The Net task normally determines the size of its internal tables from
+   the actual number of licensed nodes. Since this information is not
+   available at boot time when booting from the network, you will have
+   to set the max. number of nodes as well as a valid netmap entry for
+   the node providing the root filesystem as an option to Net in the
+   build file.
+   See examples/ws.etherboot and fill in the <blanks>.
+3. The client does not need a TCP/IP license in order to boot.
+4. You can use the boot-server OS of your choice. If you choose to use
+   QNX as boot server, the server of course needs a TCP/IP run-time
+   license.  In this case you have the option of creating the boot image
+   on-the-fly and use the macro $(netmap) instead of a hard-coded MAC
+   address.
+   See examples/ws.etherboot.on-the-fly and fill in the <blanks>.
+   A template bootptab for the QNX bootp server is placed in the
+   examples directory.
+5. mkQNXnbi expects the QNX image to be supplied on stdin and generates
+   the tagged image to stdout. This can be overridden on the command line
+   using the options -i <input-file> and -o <output-file>.
+
+mkQNXnbi can be compiled using e.g. Linux/gcc or on QNX using Watcom C
+(or gcc, if you have it - see http://w3c.teaser.fr/~jcmichot/)
+
+Bug-reports to <al@alarsen.net>
+
+2002-01-25
+Anders Larsen
+<al@alarsen.net>
diff --git a/contrib/mkQNXnbi/examples/bootptab b/contrib/mkQNXnbi/examples/bootptab
new file mode 100644 (file)
index 0000000..2077fa9
--- /dev/null
@@ -0,0 +1,29 @@
+# /etc/bootptab: database for QNX bootp server (/etc/bootpd)
+
+# First, we define a global entry which specifies the stuff every host uses.
+global:\
+  :hd=/boot:\
+  :ht=ethernet:\
+  :sm=<your netmask here>:\
+  :bf=|cd /boot; buildqnx -b 0x10000 build/<your build-file here> | mkQNXnbi:\
+  :hn:
+
+# node 2 uses the default build-file
+node2:\
+  :tc=global:\
+  :ha=<your MAC here>:\
+  :ip=<your IP address here>:
+
+# node 3 uses its own build-file
+node3:\
+  :tc=global:\
+  :ha=<your MAC here>:\
+  :ip=<your IP address here>:\
+  :bf=|cd /boot; buildqnx -b 0x10000 build/<your build-file here> | mkQNXnbi:
+
+# node 4 uses a pre-built boot image
+node3:\
+  :tc=global:\
+  :ha=<your MAC here>:\
+  :ip=<your IP address here>:\
+  :bf=images/<your image-file here>:
diff --git a/contrib/mkQNXnbi/examples/ws.etherboot b/contrib/mkQNXnbi/examples/ws.etherboot
new file mode 100644 (file)
index 0000000..d8120bc
--- /dev/null
@@ -0,0 +1,22 @@
+# /boot/build/ws.etherboot
+
+sys/boot
+$ boot -v
+
+sys/Proc32
+$ Proc32 -l <target node number>
+
+sys/Slib32
+$ Slib32
+
+sys/Slib16
+$ Slib16
+
+/bin/Net
+$ Net -n <highest QNX node number in network> -m "<node number of boot server> 1 <MAC of boot server node here>"
+
+/bin/Net.<network driver>
+$ Net.<network driver>
+
+/bin/sinit
+$ sinit -r //<node number of boot server>/ TERM=<your terminal emulation {QNX|qansi}>
diff --git a/contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly b/contrib/mkQNXnbi/examples/ws.etherboot.on-the-fly
new file mode 100644 (file)
index 0000000..3058c45
--- /dev/null
@@ -0,0 +1,22 @@
+# /boot/build/ws.etherboot.on-the-fly
+
+sys/boot
+$ boot -v
+
+sys/Proc32
+$ Proc32 -l $(lnode)
+
+sys/Slib32
+$ Slib32
+
+sys/Slib16
+$ Slib16
+
+/bin/Net
+$ Net -n <highest QNX node number in network> -m $(netmap)
+
+/bin/Net.<network driver>
+$ Net.<network driver>
+
+/bin/sinit
+$ sinit -r //$(bnode)/ TERM=<your terminal emulation {QNX|qansi}>
diff --git a/contrib/mkQNXnbi/mkQNXnbi.c b/contrib/mkQNXnbi/mkQNXnbi.c
new file mode 100644 (file)
index 0000000..2ec2dc4
--- /dev/null
@@ -0,0 +1,196 @@
+//*****************************************************************************
+//
+//      Purpose:        Make a boot-image for EtherBoot
+//
+//
+//      Compiler:       This source can be compiled with gcc and Watcom C
+//
+//
+//      Note:           The QNX boot image can be build with any reasonable
+//                      start address, e.g. 0x1000 (default) or 0x10000
+//                      (widespread Boot-Rom address)
+//
+//
+//      Author:         Anders Larsen
+//
+//
+//      Copyright:      (C) 1999 by
+//
+//                      Anders Larsen
+//                      systems engineer
+//                      Gutleuthausstr. 3
+//                      D-69469 Weinheim
+//                      Germany
+//                      phone:  +49-6201-961717
+//                      fax:    +49-6201-961718
+//                      e-mail: al@alarsen.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+//-----------------------------------------------------------------------------
+//
+//      Change Log:
+//        V0.2: Sun 1999-12-13 Anders Larsen <al@alarsen.net>
+//*****************************************************************************
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+// max. size of QNX OS boot image is 512K
+#define MAXSIZE (512*1024)
+
+typedef unsigned short ushort_t;
+typedef unsigned long  ulong_t;
+
+
+// global header of tagged image:
+struct initial_t
+{
+  ulong_t magic;
+  ulong_t length;
+  ulong_t location;
+  ulong_t start;
+};
+
+
+// header of each image:
+struct header_t
+{
+  ulong_t flags;
+  ulong_t loadaddr;
+  ulong_t imgsize;
+  ulong_t memsize;
+};
+
+
+// global header of the QNX EtherBoot image:
+struct qnx_loader_t
+{
+  struct initial_t setup;
+  struct header_t  qnx;
+};
+
+
+// global header:
+union
+{
+  struct qnx_loader_t h;
+  char                filler[512];
+} header;
+
+
+char buffer[MAXSIZE];
+
+
+int usage( char* const* argv )
+{
+  fprintf( stderr, "%s - make a tagged boot image for EtherBoot\n", *argv );
+  fprintf( stderr, "\nuse:\n" );
+  fprintf( stderr, "%s [ -<option> ]*\n", *argv );
+  fprintf( stderr, "\noptions:\n" );
+  fprintf( stderr, "  i <input file>  : QNX boot file     (default: stdin)\n" );
+  fprintf( stderr, "  o <output file> : tagged image file (default: stdout)\n" );
+  fprintf( stderr, "  v               : be verbose\n" );
+  return EXIT_FAILURE;
+}
+
+#ifdef __USAGE
+%C - make a tagged boot image for EtherBoot
+
+use:
+%C [ -<option> ]* 
+
+options:
+  i <input file>  : QNX boot file     (default: stdin)
+  o <output file> : tagged image file (default: stdout)
+  v               : be verbose
+#endif
+
+
+int main( int argc, char* const* argv )
+{
+  int ch, l;
+  int verbose = 0;
+
+  while ( ( ch = getopt( argc, argv, "hi:o:v" ) ) != EOF )
+    switch ( ch )
+    {
+      case 'i':
+        if ( !freopen( optarg, "r", stdin ) )
+        {
+          perror( "can't open input file" );
+          return EXIT_FAILURE;
+        }
+        break;
+
+      case 'o':
+        if ( !freopen( optarg, "w", stdout ) )
+        {
+          perror( "can't create output file" );
+          return EXIT_FAILURE;
+        }
+        break;
+
+      case 'v':
+        verbose++;
+        break;
+
+      case 'h':
+      default:
+        return usage( argv );
+    }
+  if ( optind != argc )
+    return usage( argv );
+
+  memset( &header, 0, sizeof header );
+  header.h.setup.magic     = 0x1b031336;    // magic number
+  header.h.setup.length    =          4;
+  header.h.setup.location  = 0x93e00000;    // just below the EtherBoot rom
+  header.h.setup.start     =          0;    // filled in dynamically
+  header.h.qnx.flags       = 0x04000004;    // single image only
+  header.h.qnx.loadaddr    =          0;    // filled in dynamically
+  header.h.qnx.imgsize     =          0;    // filled in dynamically
+  header.h.qnx.memsize     =          0;    // filled in dynamically
+
+  // read the QNX image from stdin:
+  for ( ; ( l = fread( buffer + header.h.qnx.imgsize, 1, 1024, stdin ) ) > 0;
+        header.h.qnx.imgsize += l
+      )
+    ;
+  header.h.qnx.memsize = header.h.qnx.imgsize;
+
+  // fill in the real load-address of the QNX boot image:
+  header.h.setup.start  = *(ushort_t*)&buffer[10] << 16;
+  header.h.qnx.loadaddr = *(ushort_t*)&buffer[10] <<  4;
+
+  // write the tagged image file to stdout:
+  fwrite( &header, 1, 512, stdout );
+  fwrite( buffer, 1, header.h.qnx.imgsize, stdout );
+
+  if ( verbose )
+  {
+    // print diagnostic information:
+    fprintf( stderr, "QNX image size: %d bytes (%dK), load addr: 0x%05X\n",
+             header.h.qnx.imgsize,
+             header.h.qnx.imgsize / 1024,
+             header.h.qnx.loadaddr
+           );
+  }
+  return EXIT_SUCCESS;
+}
diff --git a/contrib/mkffwnb/2.0.10/linuxrc b/contrib/mkffwnb/2.0.10/linuxrc
new file mode 100755 (executable)
index 0000000..351679c
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# floppyfw initfile
+#
+# nicked from:
+# hal91's initfile (/linuxrc), the bootup script of the system
+#
+
+VERSION=2.1.6
+
+load_fsmod () {
+       case $1 in
+       /dev/hd*)
+               insmod ide-cd
+               insmod cdrom
+               ;;
+       esac
+       case $2 in
+       vfat)
+               echo vfat support is builtin
+               ;;
+       iso9660)
+               insmod isofs
+               ;;
+       esac
+}
+
+#
+/bin/busybox echo "Booting floppyfw" 
+
+PATH="/bin:/sbin:/usr/bin:/usr/sbin"
+#PATH="/bin"
+TERM=linux
+ignoreeof=10
+no_exit_on_failed_exec=yes
+export PATH TERM ignoreeof
+umask 022
+
+/bin/busybox echo "mounting: proc"
+/bin/busybox mount -t proc /proc /proc
+
+/bin/busybox echo "Generating links. (Thanks to busybox.lineo.com)"
+/bin/busybox --install -s
+
+echo "Generated"
+
+# Modified by Gem, based on coyote distro, changes by Ken Yap
+ROOTDEV=`sed -e 's/$/ /' -e 's/.*root=\([^ ]*\) .*/\1/' -e 's/,/ /g' -e 's:/dev/nfs:/dev/fd0:' /proc/cmdline`
+set -- $ROOTDEV
+# Backward compatibility with a single device argument
+if [ $# -eq 1 ]
+then
+       set -- $1 vfat
+fi
+while [ "$1" -a "$2" ]
+do
+       echo "attempting to mount $1 ($2)"
+       load_fsmod $1 $2
+       if mount -t $2 $1 /mnt/tmp
+       then
+               echo "mounted $1 on /mnt/tmp"
+               break
+       fi
+       shift; shift
+done
+
+[ -f /mnt/tmp/floppyfw/floppyfw.ini ] && cat /mnt/tmp/floppyfw/floppyfw.ini \
+| tr -d '\015' >/floppyfw.ini
+
+[ -f /floppyfw.ini ] && chmod 777 /floppyfw.ini
+[ -f /floppyfw.ini ] && exec /floppyfw.ini
+
+echo
+echo "** floppyfw.ini failed.. starting a shell"
+echo
+exec sh
diff --git a/contrib/mkffwnb/Extendinitrd.pm b/contrib/mkffwnb/Extendinitrd.pm
new file mode 100644 (file)
index 0000000..3b919ad
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/perl -w
+
+sub status_system ($$) {
+       my ($command, $message) = @_;
+
+       $status = system($command);
+       $status <<= 8;
+       if ($status < 0) {
+               print STDERR "$!\n";
+       }
+       if ($status != 0) {
+               print STDERR "$message\n";
+       }
+}
+
+sub extendinitrd ($$) {
+       my ($initrd, $nblocks) = @_;
+
+       if ($nblocks <= 1440) {
+               print STDERR "nblocks must be >= 1440\n";
+               return (1);
+       }
+       (undef, $type, undef, $fnlen, undef)  = split(' ', `file $initrd`, 5);
+       print "$type $fnlen\n";
+       if ($type ne 'Minix' || $fnlen != 30) {
+               die "Can only handle Minix initrds with 30 char filenames\n";
+               return (1);
+       }
+       status_system("dd if=/dev/zero of=newinitrd bs=1k count=$nblocks", "Cannot create new initrd\n");
+       status_system("mkfs.minix -n 30 newinitrd $nblocks", "Cannot mkfs.minix new initrd\n");
+       mkdir("initrd.from") || print STDERR "Cannot make temp mount point initrd.from\n";
+       mkdir("initrd.to") || print STDERR "Cannot make temp mount point initrd.to\n";
+       status_system("mount -o ro,loop $initrd initrd.from", "Cannot mount $initrd on initrd.from");
+       status_system("mount -o loop newinitrd initrd.to", "Cannot mount newinitrd on initrd.to");
+       status_system("cp -a initrd.from/* initrd.to/", "Cannot copy initrd to newinitrd");
+       status_system("umount initrd.from", "Cannot umount initrd.from");
+       status_system("umount initrd.to", "Cannot umount initrd.to");
+       rmdir("initrd.from") || print STDERR "Cannot remove temp mount point initrd.from\n";
+       rmdir("initrd.to") || print STDERR "Cannot remove temp mount point initrd.to\n";
+       return (0);
+}
+
+1;
diff --git a/contrib/mkffwnb/README b/contrib/mkffwnb/README
new file mode 100644 (file)
index 0000000..38df476
--- /dev/null
@@ -0,0 +1,69 @@
+This is a quick and dirty script to convert a floppyfw floppy
+(http://www.zelow.no/floppyfw/) to a tagged image for booting with
+Etherboot (http://etherboot.sourceforge.net/). The advantages of network
+booting include: it's much faster loading from the network than from a
+floppy disk, you can boot from any size floppy, and you are not limited
+to the maximum of 1.44 MB of the physical floppy. If you have enough RAM
+and use a virtual floppy to build the initial boot image, you can put as
+much on it as will fit the ramdisk.
+
+See further down under -nonet if you want to boot from HD or CDROM.
+
+This program requires mtools, tar, bzip2, loopback mount in the kernel,
+and root privileges to execute. Hope you have them.
+
+This script works for any of the releases for which a subdirectory of
+that name is provided, but it should not be too hard to make it work for
+other releases, all that is done here is to substitute some scripts for
+the distributed ones.
+
+First of all you should make the floppy work the way you want before
+converting it to a tagged image. This involves editing the various
+config files on the floppy. Instructions on this are distributed from
+the floppyfw web page mentioned above.
+
+Edit the $tftpdir assignment for the directory where you put your tagged
+images.  Edit the $libdir assignment and the use lib directive near the
+top if you decide to put this package somewhere other than
+/usr/local/lib/mkffwnb/. Adjust the instructions below as necessary.
+
+Copy everything to $libdir.
+
+       mkdir -p /usr/local/lib/mkffwnb/
+       cp -a . /usr/local/lib/mkffwnb/
+
+Make a link from /usr/local/lib/mkffwnb/mkffwnb.pl to
+/usr/local/bin/mkffwnb so that it's in your path.
+
+       ln -s /usr/local/lib/mkffwnb/mkffwnb.pl /usr/local/bin/mkffwnb
+
+Then run it as:
+
+       mkffwnb
+
+You can also provide a floppy drive as an argument, e.g.
+
+       mkffwnb x:
+
+where x: could be mapped to a disk file. This allows you to build an
+image without a real floppy drive. Remember that for virtual drives root
+must have the mapping for the drive in question in ~root/.mtoolsrc.
+
+You can use the option --localtime=/etc/localtime to specify that the
+file /etc/localtime is to be copied to /etc/localtime on the initrd.
+Instead of /etc/localtime, you can use any of the timezone files under
+/usr/share/zoneinfo/, it's just that /etc/localtime will usually be the
+correct one for your timezone.
+
+If you use the option -nonet, it leaves the intermediate files in
+$tempdir, /tmp/mkffwnb by default. This is useful if you want the
+vmlinuz and initrd.gz files for use with LILO or isolinux to boot from
+HD or CDROM. Actually you can also use these with a floppy, it loads
+faster if you fold all the scripts and modules into the initrd ahead
+of time.
+
+mkffwnb has to be run as root because it uses loopback mounts and also
+because the files inside the initrd are owned by root.
+
+Ken Yap
+2003-04-20
diff --git a/contrib/mkffwnb/mkffwnb.pl b/contrib/mkffwnb/mkffwnb.pl
new file mode 100755 (executable)
index 0000000..555ec3c
--- /dev/null
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+#
+# Perl script to make a bootable image from a floppyfw floppy
+# The basic idea is to unpack and replace or convert all
+# the necessary config files into the initrd
+# and then make a bootable image out of it
+#
+# The --format= option overrides the default of nbi or elf hardcoded
+# in the source. Valid arguments are nbi or elf.
+#
+# The --output= options specifies an output file instead of stdout
+# The --nonet option specifies that a netbootable image is not to
+# be built but the vmlinuz and initrd.gz files left behind in $tempdir
+# The --localtime=f option specifies a timezone file that's to be
+# copied to /etc/localtime in the initrd, allowing a different timezone.
+# The --ffw29 option is intended for 2.9.x and above and extends
+# the size of the initrd by making a bigger one and copying the original over.
+#
+# The first non-option argument is taken to be the letter of a floppy to
+# convert, e.g. a:, b: or even x: where x: is mapped to a file using
+# mtools mapping in $HOME/.mtoolsrc. See the mtools documentation.
+# Thus you can work on a floppy image in a disk file and only write
+# to a floppy with dd or cp when you need to test the image.
+
+use Getopt::Long;
+
+use lib '/usr/local/lib/mkffwnb/';
+use Extendinitrd;
+
+use strict;
+
+use vars qw($testing $verbose $localtime $nonet $format $ffw29 $imagefile
+       $floppy $libdir $tftpdir $output $tempdir $tempmount);
+
+sub findversion () {
+       my ($version) = grep(/FloppyFW/, `mtype $imagefile ${floppy}floppyfw.msg`);
+       return '' unless defined($version) and $version ne '';
+       chomp($version);
+       $version =~ s/.*FloppyFW (\d+\.\d+\.\d+(\.\d+)?).*/$1/;
+       return ($version);
+}
+
+sub getappendargs () {
+       my ($append) = join(' ', grep(/^\s*(append\s|console=)/, `mtype $imagefile ${floppy}syslinux.cfg`));
+       chomp ($append);
+       my @args = split(/\s+/, $append);
+       my @result = ();
+       foreach $_ (@args) {
+               next if (/^$/ or /^append/ or /^initrd=/);
+               next if (!$ffw29 and /^root=/);
+               push (@result, $_);
+       }
+       return (join(' ', @result));
+}
+
+# Copy whole floppy to the current directory
+# m preserves timestamps, n overwrites without warning and / means recursive
+sub mcopy ($) {
+       my ($tempdir) = @_;
+
+       print "mcopy $imagefile -mn/ ${floppy}* $tempdir\n";
+       my $status = system("mcopy -mn/ $imagefile ${floppy}* $tempdir");
+       return ($status / 256);
+}
+
+# Gunzip file, -f forces overwriting of uncompressed file
+sub gunzip ($) {
+       my ($file) = @_;
+
+       print "Gunzipping $file\n" if ($verbose);
+       my $status = system('gunzip', '-f', $file);
+       return ($status / 256);
+}
+
+# Gzip file, -f forces overwriting of compressed file
+sub gzip ($) {
+       my ($file) = @_;
+
+       print "Gzipping $file\n" if ($verbose);
+       my $status = system('gzip', '-9', '-f', $file);
+       return ($status / 256);
+}
+
+sub loopbackmount ($$) {
+       my ($file, $point) = @_;
+
+       print "Mounting $file on $point loopback\n" if ($verbose);
+       my $status = system('mount', '-o', 'loop', $file, $point);
+       return ($testing ? 0 : $status / 256);
+}
+
+sub loopbackumount ($) {
+       my ($point) = @_;
+
+       print "Umounting $point\n" if ($verbose);
+       my $status = system('umount', $point);
+       return ($testing ? 0 : $status / 256);
+}
+
+# Convert DOS CR-NL to Unix NL. $dst has implied prefix of $tempmount
+# Use @output for temporary storage in case we write back to the same file
+sub dostounix ($$) {
+       my ($src, $dst) = @_;
+       my @output = ();
+
+       $dst = "$tempmount/$dst";
+       print "Converting $src to $dst\n" if ($verbose);
+       unless (open(S, $src)) {
+               print "$src: $!\n";
+               return (0);
+       }
+       while (<S>) {
+               chomp;
+               tr /\015//d;
+               push(@output, $_);
+       }
+       close(S);
+       open(D, ">$dst") or return;
+       for $_ (@output) {
+               print D "$_\n";
+       }
+       close(D);
+       chmod(0755, $dst);
+       return (1);
+}
+
+sub bunzip2untar ($$) {
+       my ($file, $dir) = @_;
+
+       print "Unpacking $file into $dir\n" if ($verbose);
+       system("bunzip2 < $file | (cd $dir; tar xf -)");
+}
+
+$testing = $< != 0;
+$verbose = 1;
+$format = '';
+$imagefile = '';
+GetOptions('output=s' => \$output,
+       'nonet!' => \$nonet,
+       'localtime=s' => \$localtime,
+       'format=s' => \$format,
+       'ffw29!' => \$ffw29,
+       'ffw30!' => \$ffw29,
+       'i=s' => \$imagefile);
+if (defined($output) and $output !~ m(^/)) {
+       my $d = `pwd`;
+       chomp($d);
+       $output = "$d/$output";
+}
+if ($imagefile) {
+       $imagefile = "-i $imagefile";
+}
+$libdir = '/usr/local/lib/mkffwnb';
+$tftpdir = '/usr/local/var/tftpboot';
+# default can also be 'elf'
+$format = 'nbi' if ($format ne 'elf' and $format ne 'nbi');
+$floppy = $#ARGV >= 0 ? $ARGV[0] : 'a:';
+print <<EOF;
+This program requires mtools, tar, bzip2, loopback mount in the kernel,
+and root privileges to execute. Hope you have them.
+EOF
+my $version = &findversion();
+$version ne '' or die "Cannot determine version\n";
+print "Version $version\n";
+my $append = &getappendargs();
+$append = "--append='$append'" if $append ne '';
+print "$append\n";
+$libdir .= '/' . $version;
+-d $libdir or die "Cannot find files for $version\n";
+$tempdir = $nonet ? '/tmp/mkffwnb' : "/tmp/mkffwnb$$";
+$tempmount = 'tmpmount';
+mkdir($tempdir, 0755);
+print "Copying files off floppy, please be patient...\n";
+&mcopy($tempdir) == 0 or die "Mcopy failed, diskette problem?\n";
+chdir($tempdir);
+&gunzip('initrd.gz') == 0 or die "Gunzip of initrd.gz failed\n";
+if ($ffw29) {
+       extendinitrd("initrd", 5760);
+       system("mv newinitrd initrd");
+}
+mkdir($tempmount, 0755);
+&loopbackmount('initrd', $tempmount) == 0 or die "Loopback mount failed\n";
+&dostounix("$libdir/linuxrc", "linuxrc") if (-r "$libdir/linuxrc");
+unless (&dostounix("$libdir/floppyfw.ini", "floppyfw.ini")) {
+       &dostounix("floppyfw/floppyfw.ini", $ffw29 ? "etc/floppyfw.ini" : "floppyfw.ini");
+}
+&dostounix("config", $ffw29 ? "etc/config.prelogin" : "etc/config");
+for my $i (glob('*.bz2 floppyfw/add.bz2 modules/*.bz2 packages/*.bz2')) {
+       &bunzip2untar($i, $tempmount);
+}
+for my $i (glob('packages/*.ini')) {
+       my $file = $i;
+       $file =~ s:packages/::;
+       &dostounix($i, "etc/$file");
+}
+&dostounix("hosts", "etc/hosts");
+&dostounix("modules.lst", "etc/modules.lst");
+&dostounix("network.ini", "etc/network.init");
+&dostounix("firewall.ini", "etc/firewall.init");
+&dostounix("syslog.cfg", "etc/syslog.conf");
+&dostounix("packages/timeinfo", "etc/localtime");
+system("cp -p licenses/* $tempmount/licenses/");
+# This conditional code is for 1.1.2 and below
+unless (glob('modules/*.bz2')) {
+       print "Copying additional modules\n" if ($verbose);
+       system("cp -p modules/* $tempmount/lib/modules/");
+}
+# If a timezone file has been specified, copy that onto initrd
+if (defined($localtime)) {
+       if (-r $localtime) {
+               print "Copying $localtime to $tempmount/etc/localtime\n";
+               system("cp -p $localtime $tempmount/etc/localtime");
+       } else {
+               print "$localtime: $!\n";
+       }
+}
+&loopbackumount($tempmount) == 0 or die "Loopback umount failed\n";
+&gzip('initrd') == 0 or die "Gzip of initrd failed\n";
+if ($nonet) {
+       print "Floppyfw directory in $tempdir\n";
+} else {
+       print "Calling mk$format-linux to make the netbootable image\n" if ($verbose);
+       $output = "$tftpdir/floppyfw-$version.nb" if (!defined($output));
+       system("mk$format-linux $append --output=$output vmlinuz initrd.gz");
+       system("rm -fr $tempdir");
+}
diff --git a/contrib/mklrpnb/README.txt b/contrib/mklrpnb/README.txt
new file mode 100644 (file)
index 0000000..c99c55c
--- /dev/null
@@ -0,0 +1,4 @@
+This is a quick and dirty Perl program to make a netbootable
+image from a Linux Router floppy. It was tested with a Coyote Linux
+(http://www.coyotelinux.com) floppy which is based on LRP.  You need tar,
+mtools, mknbi-1.0, and of course, perl, to run this script.
diff --git a/contrib/mklrpnb/extractdach.pl b/contrib/mklrpnb/extractdach.pl
new file mode 100644 (file)
index 0000000..6c81da3
--- /dev/null
@@ -0,0 +1,191 @@
+#!/usr/bin/perl -w
+#
+# A program to make a netbootable image from a LRP firewall floppy
+#
+# Tested on a Dachstein Linux floppy image available from
+# http://lrp1.steinkuehler.net/ or via http://leaf.sourceforge.net/
+
+# The most recent version of this script and a companion HowTo is available at
+# http://members.optushome.com.au/graybeard/linux/netboot.html
+#
+# Modified from the mklrpnb file found in the contrib/mklrpnb directory of the
+# Etherboot source at http://etherboot.sourceforge.net/
+#
+# Modifications by Glenn McK <graybeard@users.sourceforge.net> 
+# $Id$
+##################################### 
+
+# this entry will need changing
+$image = "/home/graybeard/etherboot/dachstein-v1.0.2-1680.bin";
+
+# these can remain, but change them if desired
+#
+# the next argument defaults to firewall if no other name is passed via the
+# command line, this will be the directory where distribution will be expanded
+# under $base and also the directory in /tftpboot for lrp.nb
+
+my $uniqdir = shift || 'firewall';
+
+$mntdir   = "/mnt/floppy";          # where the above image file can be mounted
+$tftpbase = "/tftpboot";
+$tftpboot = "$tftpbase/$uniqdir";   # where the netboot images will be available
+$base     = "/usr/src/LRP";
+$dachorg = "$base/dach-org-$uniqdir"; # a copy required to make the distribution
+$dachnew = "$base/lrp-$uniqdir";      # the base files for the new distribution
+$packages = "$dachnew/var/lib/lrpkg"; # list to allow lrcfg to display Packages
+
+# everything below should be okay
+######################################
+
+if ( !-e $image ) {
+    print
+"\n\tA valid LRP file and directory are required\n\tdownload one then edit $0\n\n";
+    exit 1;
+}
+if ( !-d $base ) {
+    mkdir( $base, 0700 );
+}
+
+if ( !-d $dachorg ) {
+    mkdir( $dachorg, 0700 );
+}
+
+if ( !-d $dachnew ) {
+    mkdir( $dachnew, 0700 );
+    `umount $mntdir`;
+    `mount -o ro,loop $image $mntdir`;
+
+    `cp -vr $mntdir/* $dachorg/`;
+
+    @cfg = `cat $mntdir/syslinux.cfg`;
+
+    unless ( defined(@cfg) ) {
+        print "Cannot find syslinux.cfg on $mntdir\n";
+        exit 1;
+    }
+    print "cfg = @cfg\n";
+    ($append) = grep( /append/, @cfg );    # find the append= line
+    print "append = \n$append\n";
+    chomp($append);                        # remove trailing newline
+    $append =~ s/append=//;                # remove the append= at beginning
+    print "strip append = \n$append\n\n";
+    @args = split ( / /, $append );        # split into arguments at whitespace
+    ($root) = grep( /^initrd=/, @args );   # find the initrd= argument
+    $root =~ s/^initrd=//;                 # remove the initrd= at beginning
+    $root =~ s/\.lrp$//;                   # cleanup for paclages list
+    print "strip initrd = \n$root\n\n";
+    ($lrp) = grep( /^LRP=/, @args );       # find the LRP= argument
+    $lrp =~ s/^LRP=//;                     # remove the LRP= at beginning
+    print "strip LRP =\n$lrp\n\n";
+    @lrp = split ( /,/, $lrp );            # split into filenames at ,
+    unshift ( @lrp, $root );               # prepend the root LRP filename
+    @pack = @lrp;
+    print "LRP =\n@lrp\n\n";
+    $append = '';
+
+    foreach $i (@args) {                   # rebuild the append string
+        next if ( $i =~ /^initrd=/ );      # minus the unneeded parameters
+        next if ( $i =~ /^LRP=/ );
+        next if ( $i =~ /^boot=/ );
+        next if ( $i =~ /^PKGPATH=/ );
+        print "$i = i\n";
+        $append .= "$i ";
+    }
+
+    print "final append = \n$append\n";
+
+    chdir($dachnew) or die "$dachnew: $!\n";
+    foreach $i (@lrp) {
+        $i .= '.lrp' if $i !~ /\.lrp$/;
+        print "\n\n\nUnpacking $i\n";
+        system("ln -svf $dachorg/$i ${dachorg}/${i}.tar.gz");
+        chmod 0600, "$dachorg/$i";
+        system("cat $mntdir/$i | tar zxvf -");
+    }
+
+    # create file for lrcfg to display packages
+    open( PACKAGES, ">$packages/packages" )
+      || print "unable to modify $packages:$!\n";
+    foreach $line (@pack) {
+        print PACKAGES "$line\n";
+    }
+    close PACKAGES;
+
+    # prevent previous file from being overwritten during installation
+    # and also mess with some values in /linuxrc to hide non errors
+    open( LINUXRC, "$packages/root.linuxrc" );
+    @text = <LINUXRC>;
+    close LINUXRC;
+    open( LINUXRC, ">$packages/root.linuxrc" );
+    foreach $line (@text) {
+        $line =~ s/PFX\/packages/PFX\/packages-old \
+\t\t\t\t# packages changed to packages-old for netboot setup/;
+        $line =~
+s/^rc=1/# rc=1 changed to rc=0 to suppress error messages for netboot setup \
+rc=0/;
+        $line =~
+s/echo -n \" \(nf\!\)\"/#echo -n \" \(nf\!\)\" changed to reflect ToDo list \
+\t\t\techo -n \" netboot setup - No backups possible from this machine - ToFix ?"/;
+        print LINUXRC $line;
+    }
+    close LINUXRC;
+
+    # swap interfaces around in network config file
+    # eth1 is the new external eth0 is OUR internal server access
+    open( NETWORK, "$dachnew/etc/network.conf" )
+      || print "Unable to modify NETWORK:$!\n";
+    @text = <NETWORK>;
+    close NETWORK;
+    open( NETWORK, ">$dachnew/etc/network.conf" )
+      || print "Unable to modify NETWORK:$!\n";
+    foreach $line (@text) {
+        $line =~ s/eth0/eth00/;
+        $line =~ s/eth1/eth0/;
+        $line =~ s/eth00/eth1/;
+        print NETWORK $line;
+    }
+    close NETWORK;
+
+    `echo $append > $dachorg/appendstr`;
+
+    `umount /mnt/floppy`;
+    print "\nThe files have been extracted to $dachnew\n";
+    system("ls -al $dachnew");
+}
+else {
+    print "\n\n\t$image \n \thas already been extracted to $dachnew \
+\tNow skipping to the next step where the netboot file\
+\twill be created.\n";
+
+    $append = `cat $dachorg/appendstr`;
+    print "\nThe new append string will be...\n$append\n";
+
+    chdir($dachnew);
+    if ( !-d $tftpbase ) {
+        mkdir( $tftpbase, 0710 );
+        system("chgrp nobody $tftpbase");
+    }
+
+    unlink($tftpboot);
+
+    # these permissions really need changing to something secure
+    mkdir( $tftpboot, 0710 );
+    system("chgrp nobody $tftpboot");
+    print "\tRepacking to $tftpboot/lrp.lrp\n";
+    system("tar zcf $tftpboot/lrp.lrp *");
+    print "\tExtracting kernel image from $dachorg\n";
+    system("cat $dachorg/linux > $tftpboot/lrp.ker");
+    print "\tCreating netboot image $tftpboot/lrp.nb\n";
+    system(
+"mknbi-linux --append='$append' --output=$tftpboot/lrp.nb $tftpboot/lrp.ker $tftpboot/lrp.lrp"
+    );
+    chmod 0604, "$tftpboot/lrp.nb", "$tftpboot/lrp.ker", "$tftpboot/lrp.lrp";
+    print "\nThese netboot files are in $tftpboot\n";
+    system("ls -al $tftpboot");
+    print "\n   The owner and permissions for $tftpboot \
+ and files should be checked for security. The above\
+permissions assume that tftp is running chroot (nobody)
+      drwx--r---   root:nobody   /tftpboot\n\n";
+}
+
+exit 0;
diff --git a/contrib/mklrpnb/mklrpnb b/contrib/mklrpnb/mklrpnb
new file mode 100755 (executable)
index 0000000..47590f7
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/perl -w
+#
+# A program to make a netbootable image from a LRP firewall floppy
+# Tested on a Coyote Linux floppy
+#
+@cfg = `mtype a:syslinux.cfg`;
+unless (defined(@cfg)) {
+       print "Cannot find syslinux.cfg on floppy\n";
+       exit 1;
+}
+($append) = grep(/^append/, @cfg);     # find the append= line
+chomp($append);                                # remove trailing newline
+$append =~ s/append=//;                        # remove the append= at beginning
+@args = split(/ /, $append);           # split into arguments at whitespace
+($root) = grep(/^initrd=/, @args);     # find the initrd= argument
+$root =~ s/^initrd=//;                 # remove the initrd= at beginning
+($lrp) = grep(/^LRP=/, @args);         # find the LRP= argument
+$lrp =~ s/^LRP=//;                     # remove the LRP= at beginning
+@lrp = split(/,/, $lrp);               # split into filenames at ,
+unshift(@lrp, $root);                  # prepend the root LRP filename
+$append = '';
+foreach $i (@args) {                   # rebuild the append string
+       next if ($i =~ /^initrd=/);     # minus the unneeded parameters
+       next if ($i =~ /^LRP=/);
+       next if ($i =~ /^boot=/);
+       $append .= "$i ";
+}
+# print "$append\n";
+$tempdir = "/tmp/lrp$$";
+mkdir($tempdir, 0777) or die "$tempdir: $!\n";
+chdir($tempdir) or die "$tempdir: $!\n";
+foreach $i (@lrp) {
+       $i .= '.lrp' if $i !~ /\.lrp$/;
+       print "Unpacking $i\n";
+       system("mtype a:$i | tar zxvf -");
+}
+print "Repacking to /tmp/lrp.lrp\n";
+system("tar zcf /tmp/lrp.lrp *");
+chdir('/tmp') or die "/tmp: $!\n";
+system("rm -fr $tempdir");
+print "Extracting kernel image from floppy\n";
+system("mtype a:linux > /tmp/lrp.ker");
+print "Creating netboot image in /tmp/lrp.nb\n";
+system("mkelf-linux --append='$append' --output=/tmp/lrp.nb /tmp/lrp.ker /tmp/lrp.lrp");
+exit 0;
diff --git a/contrib/mntnbi/mntnbi.pl b/contrib/mntnbi/mntnbi.pl
new file mode 100755 (executable)
index 0000000..55b8148
--- /dev/null
@@ -0,0 +1,97 @@
+#!/usr/bin/perl -w
+#
+# Quick Perl program to decode and display details about 
+# tagged images created by mknbi, and then mount the contained
+# DOS filesystem using a loop-back mount
+#
+# Martin Atkins, November 1998
+# by hacking disnbi by
+# Ken Yap, September 1998
+#
+#
+
+sub getvendordata {
+       my ($flags) = @_;
+
+       my $vendordata = '';
+       my $vendorlen = ($flags & 0xff) >> 4;
+       if ($vendorlen > 0) {
+               $vendorlen *= 4;
+               $vendordata = unpack("A$vendorlen", substr($imageheader, $curoffset));
+               $curoffset += $vendorlen;
+       }
+       return ($vendordata);
+}
+
+sub decodesegmentflags {
+       my ($flags) = @_;
+
+       $flags >>= 24;
+       $flags &= 0x3;
+       ($flags == 0) and $type = "Absolute";
+       ($flags == 1) and $type = "Follows last segment";
+       ($flags == 2) and $type = "Below end of memory";
+       ($flags == 3) and $type = "Below last segment loaded";
+       return ($type);
+}
+
+sub onesegment
+{
+       my ($segnum) = @_;
+       my ($type, $vendordata);
+
+       my ($flags, $loadaddr, $imagelen, $memlength) = unpack("V4", substr($imageheader, $curoffset));
+       $curoffset += 16;
+       print "Segment number $segnum\n";
+       printf "Load address:\t\t%08x\n", $loadaddr;
+       printf "Image length:\t\t%d\n", $imagelen;
+       printf "Memory length:\t\t%d\n", $memlength;
+       $type = &decodesegmentflags($flags);
+       printf "Position:\t\t$type\n";
+       printf "Vendor tag:\t\t%d\n", ($flags >> 8) & 0xff;
+       if (($vendordata = &getvendordata($flags)) ne '') {
+               print "Vendor data:\t\t", $vendordata, "\n";
+       }
+       print "\n";
+       push (@seglengths, $imagelen);
+       return (($flags >> 26) & 1);
+}
+
+@seglengths = ();
+$#ARGV == 1 or die "Usage: mntnbi tagged-image-file dir\n";
+$imagefile= $ARGV[0];
+open(I, $ARGV[0]) or die "$imagefile: $!\n";
+(defined($status = sysread(I, $imageheader, 512)) and $status == 512)
+       or die "$imagefile: Cannot read header\n";
+$headerrecord = substr($imageheader, 0, 16);
+($magic, $flags, $bx, $ds, $ip, $cs) = unpack("a4Vv4", $headerrecord);
+$magic eq "\x36\x13\x03\x1B" or die "$imagefile: Not a tagged image file\n";
+$curoffset = 16;
+
+# Now decode the header
+
+printf "Header location:\t%04x:%04x\n", $ds, $bx;
+printf "Start address:\t\t%04x:%04x\n", $cs, $ip;
+printf "Flags:\n";
+       print "Return to loader after execution (extension)\n" if (($flags >> 8) &  1);
+if (($vendordata = &getvendordata($flags)) ne '') {
+       print "Vendor data:\t\t", $vendordata, "\n";
+}
+print "\n";
+
+# Now decode each segment record
+
+$segnum = 1;
+do {
+       $lastrecord = &onesegment($segnum);
+       ++$segnum;
+} while (!$lastrecord);
+
+if ($#seglengths != 1) {
+       die "This is not a DOS image $#seglengths\n";
+}
+$offset = 512 + $seglengths[0];
+print "mounting filesystem at offset $offset in $ARGV[0] on $ARGV[1]\n";
+$rc = system "mount $ARGV[0] $ARGV[1] -t msdos -o loop,offset=$offset";
+print "Done\n" if ($rc == 0);
+exit(0);
diff --git a/contrib/nfs-swap/README b/contrib/nfs-swap/README
new file mode 100644 (file)
index 0000000..b95e5d7
--- /dev/null
@@ -0,0 +1,2 @@
+For more information please check
+http://nfs-swap.dot-heine.de
diff --git a/contrib/p910nd-0.8/Makefile b/contrib/p910nd-0.8/Makefile
new file mode 100644 (file)
index 0000000..c2827d2
--- /dev/null
@@ -0,0 +1,10 @@
+# Comment out the second command and uncomment the first command
+# below if you don't want to use libwrap (hosts.{allow,deny} access control)
+
+# If you don't have it in /var/log/subsys, uncomment and define
+#CFLAGS+=-DLOCKFILE_DIR=\"/var/log\"
+LIBWRAP=-lwrap
+
+p910nd:        p910nd.c
+#      $(CC) -Wall $(CFLAGS) -o $@ p910nd.c
+       $(CC) -Wall $(CFLAGS) -DUSE_LIBWRAP -o $@ p910nd.c $(LIBWRAP)
diff --git a/contrib/p910nd-0.8/banner.pl b/contrib/p910nd-0.8/banner.pl
new file mode 100755 (executable)
index 0000000..5a238c8
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+while (1)
+{
+       exit 0 if read(STDIN,$c,1) == 0;
+       last if ($cl eq "\031" && $c eq "\001");
+       $cl = $c;
+}
+kill 'STOP',$$;
+exit 0
diff --git a/contrib/p910nd-0.8/client.pl b/contrib/p910nd-0.8/client.pl
new file mode 100755 (executable)
index 0000000..0b0e4c3
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+
+# edit this to the printer hostname
+$them = 'ken';
+$port = 9101;
+
+open(STDIN, "$ARGV[0]") if $#ARGV >= 0;
+
+use Socket;
+#use Sys::Hostname;
+
+#$hostname = hostname;
+
+($name, $aliases, $proto) = getprotobyname('tcp');
+($name, $aliases, $port) = getservbyname($port, 'tcp')
+       unless $port =~ /^\d+$/;
+
+#$thisaddr = inet_aton($hostname);
+#defined($thisaddr) or &errexit("inet_aton: cannot resolve $hostname\n");
+
+$thataddr = inet_aton($them);
+defined($thataddr) or &errexit("inet_aton: cannot resolve $them\n");
+
+socket(S, PF_INET, SOCK_STREAM, $proto) or &errexit("socket: $!\n");
+
+#$this = sockaddr_in(0, $thisaddr);
+#bind(S, $this) || &errexit("bind: $!\n");
+
+$that = sockaddr_in($port, $thataddr);
+connect(S, $that) || &errexit("connect: $!\n");
+
+select(S); $| = 1; select(STDOUT);
+
+$buffer = '';
+while (1)
+{
+       $rin = '';
+       vec($rin, fileno(S), 1) = 1;
+       $nfound = select($rout=$rin, $wout=$rin, undef, undef);
+       if (vec($rout, fileno(S), 1)) {
+               print STDERR "$buffer\n" if
+                       defined($nread = sysread(S, $buffer, 8192));
+       }
+       if (vec($wout, fileno(S), 1)) {
+               $nread = read(STDIN, $buffer, 8192);
+               last if $nread == 0;
+               &errexit("write: $!\n") unless
+                       defined($written = syswrite(S,$buffer,$nread));
+       }
+}
+close(S);
+exit 0;
+
+sub errexit
+{
+       print STDERR @_;
+       exit 2;
+}
diff --git a/contrib/p910nd-0.8/p910nd.8 b/contrib/p910nd-0.8/p910nd.8
new file mode 100644 (file)
index 0000000..24572c4
--- /dev/null
@@ -0,0 +1,93 @@
+.TH P910ND 8 "1 August 2004"
+.SH NAME
+p910nd \- port 9100+n printer daemon
+.SH SYNOPSIS
+.B p910nd
+[\fB-f device\fR]
+[\fB-i bindaddr\fR]
+[\fB-bv\fR]
+[\fB0|1|2\fR]
+.SH DESCRIPTION
+.I p910nd
+is a small daemon that copies any data received on the port
+it is listening on to the corresponding printer port.
+It is primarily intended for diskless Linux hosts running as printer drivers
+but there is no reason why it could not be used on diskful hosts.
+Port 9100 is copied to /dev/lp0, 9101 to /dev/lp1 and 9102 to /dev/lp2.
+The default is port 9100 to /dev/lp0.
+.LP
+The \fB-f\fR option can be used to specify a different printer device,
+e.g. /dev/usblp0.
+.LP
+The \fB-i\fR option can be used to specify binding to one address instead
+of all interfaces which is the default.
+.LP
+The \fB-b\fR option turns on bidirectional copying.
+.LP
+The \fB-v\fR option shows the version number.
+.SH INSTALLATION
+.I p910nd
+can be run as a standalone daemon or from inetd.
+It will automatically detect if it is running under inetd.
+.LP
+A sample SysVinit script,
+.IR p910nd.sh ,
+is provided for operation as a daemon.
+.I p910nd
+will change its name under ps to match the printer port, i.e.
+.I p9100d, p9101d
+and
+.IR p9102d .
+.LP
+When running under inetd, the
+.I /etc/inetd.conf
+entry should look something like this (with tcpwrappers protection):
+.sp
+.nf
+p9101 stream tcp nowait root /usr/sbin/tcpd /sbin/p910nd
+.fi
+.sp
+Don't forget to add an entry in
+.I /etc/services
+for the corresponding port.
+.LP
+If operating with lprng, use the host%port syntax for the
+printer device to send jobs to it.
+.LP
+If operating with CUPS, this is supported as the AppSocket
+protocol, also known as the JetDirect (probably TM) protocol.
+.LP
+If operating with classic Berkeley lpd, a sample client,
+.IR client.pl ,
+is provided.
+This should be installed as the ifilter (if=) in /etc/printcap.
+.I banner.pl
+should be installed as the ofilter (of=) in /etc/printcap.
+It may be necessary to create a dummy spool file for lpd (lp=).
+This file will be opened but not written to.
+The corresponding C versions are left as an exercise for the reader.
+.LP
+When running under inetd, more than one instance could be started.
+To avoid problems with multiple instances attempting to access the
+printer at the same time, make sure that only one client is active
+at any one time. This can be done by designating one host as the
+spooler and sending all jobs to this host. You will probably
+need to set up an intermediate queue anyway to provide print job filtering.
+.LP
+If compiled with USE_LIBWRAP and linked with -lwrap, it uses the libwrap
+library (tcpwrappers). Access control can be done with /etc/hosts.allow
+and /etc/hosts.deny. The service name is p910nd.
+.SH DIAGNOSTICS
+.I p910nd
+logs error messages to syslog.
+.SH "SEE ALSO"
+printcap(5), hosts_access(5)
+.SH FILES
+/var/run/p9100d.pid, /var/lock/subsys/p9100d, /etc/hosts.allow, /etc/hosts.deny
+.SH COPYRIGHT
+.I p910nd
+is under the GNU Public License
+.SH AUTHOR
+Ken Yap (ken_yap@users.sourceforge.net)
+.SH DATE
+Version 0.8 October 2004
diff --git a/contrib/p910nd-0.8/p910nd.c b/contrib/p910nd-0.8/p910nd.c
new file mode 100644 (file)
index 0000000..c2473d8
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ *     Port 9100+n daemon
+ *     Accepts a connection from port 9100+n and copy stream to
+ *     /dev/lpn, where n = 0,1,2.
+ *
+ *     Run standalone as: p910nd [0|1|2]
+ *
+ *     Run under inetd as:
+ *     p910n stream tcp nowait root /usr/sbin/tcpd p910nd [0|1|2]
+ *      where p910n is an /etc/services entry for
+ *      port 9100, 9101 or 9102 as the case may be.
+ *      root can be replaced by any uid with rw permission on /dev/lpn
+ *
+ *     Port 9100+n will then be passively opened
+ *     n defaults to 0
+ *
+ *     Version 0.8
+ *     Allow specifying address to bind to
+ *
+ *     Version 0.7
+ *     Bidirectional data transfer
+ *
+ *     Version 0.6
+ *     Arne Bernin fixed some cast warnings, corrected the version number
+ *     and added a -v option to print the version.
+ *
+ *     Version 0.5
+ *     -DUSE_LIBWRAP and -lwrap enables hosts_access (tcpwrappers) checking.
+ *
+ *     Version 0.4
+ *     Ken Yap (ken_yap@users.sourceforge.net), April 2001
+ *     Placed under GPL.
+ *
+ *     Added -f switch to specify device which overrides /dev/lpn.
+ *     But number is still required get distinct ports and locks.
+ *
+ *     Added locking so that two invocations of the daemon under inetd
+ *     don't try to open the printer at the same time. This can happen
+ *     even if there is one host running clients because the previous
+ *     client can exit after it has sent all data but the printer has not
+ *     finished printing and inetd starts up a new daemon when the next
+ *     request comes in too soon.
+ *
+ *     Various things could be Linux specific. I don't
+ *     think there is much demand for this program outside of PCs,
+ *     but if you port it to other distributions or platforms,
+ *     I'd be happy to receive your patches.
+ */
+
+#include       <unistd.h>
+#include       <stdlib.h>
+#include       <stdio.h>
+#include       <getopt.h>
+#include       <ctype.h>
+#include       <string.h>
+#include       <fcntl.h>
+#include       <netdb.h>
+#include       <syslog.h>
+#include       <errno.h>
+#include       <sys/types.h>
+#include       <sys/time.h>
+#include       <sys/resource.h>
+#include       <sys/stat.h>
+#include       <sys/socket.h>
+#include       <netinet/in.h>
+#include       <arpa/inet.h>
+
+#ifdef USE_LIBWRAP
+#include       "tcpd.h"
+int            allow_severity, deny_severity;
+extern         int hosts_ctl(char *daemon, char *client_name,
+               char *client_addr, char *client_user);
+#endif
+
+#define                BASEPORT        9100
+#define                PIDFILE         "/var/run/p910%cd.pid"
+#ifdef         LOCKFILE_DIR
+#define                LOCKFILE        LOCKFILE_DIR "/p910%cd"
+#else
+#define                LOCKFILE        "/var/lock/subsys/p910%cd"
+#endif
+#define                PRINTERFILE     "/dev/lp%c"
+#define                LOGOPTS         LOG_ERR
+
+static char    *progname;
+static char    version[] = "p910nd Version 0.8";
+static int     lockfd = -1;
+static char    *device = 0;
+static int     bidir = 0;
+static char    *bindaddr = 0;
+
+void usage(void)
+{
+       fprintf(stderr, "Usage: %s [-f device] [-i bindaddr] [-bv] [0|1|2]\n", progname);
+       exit(1);
+}
+
+void show_version (void)
+{
+       fprintf(stdout, "%s \n", version);
+}
+
+FILE *open_printer(int lpnumber)
+{
+       FILE            *f;
+       char            lpname[sizeof(PRINTERFILE)];
+
+#ifdef TESTING
+       (void)snprintf(lpname, sizeof(lpname), "/dev/tty");
+#else
+       (void)snprintf(lpname, sizeof(lpname), PRINTERFILE, lpnumber);
+#endif
+       if (device == 0)
+               device = lpname;
+       if ((f = fopen(device, bidir ? "w+" : "w")) == NULL)
+       {
+               syslog(LOGOPTS, "%s: %m\n", device);
+               exit(1);
+       }
+       return (f);
+}
+
+int get_lock(int lpnumber)
+{
+       char            lockname[sizeof(LOCKFILE)];
+       struct flock    lplock;
+
+       (void)snprintf(lockname, sizeof(lockname), LOCKFILE, lpnumber);
+       if ((lockfd = open(lockname, O_CREAT|O_RDWR)) < 0)
+       {
+               syslog(LOGOPTS, "%s: %m\n", lockname);
+               return (0);
+       }
+       memset(&lplock, 0, sizeof(lplock));
+       lplock.l_type = F_WRLCK;
+       lplock.l_pid = getpid();
+       if (fcntl(lockfd, F_SETLKW, &lplock) < 0)
+       {
+               syslog(LOGOPTS, "%s: %m\n", lockname);
+               return (0);
+       }
+       return (1);
+}
+
+void free_lock(void)
+{
+       if (lockfd >= 0)
+               (void)close(lockfd);
+}
+
+/* Copy network socket to FILE f until EOS */
+int copy_stream(int fd, FILE *f)
+{
+       int             nread;
+       char            buffer[8192];
+
+       if (bidir) {
+               FILE    *nf;
+
+               if ((nf = fdopen(fd, "w")) == NULL) {
+                       syslog(LOGOPTS, "fdopen: %m\n");
+               }
+               for (;;) {
+                       fd_set  readfds;
+                       int result;
+                       int maxfd = fileno(f) > fd ? fileno(f) : fd;
+                       FD_ZERO(&readfds);
+                       FD_SET(fileno(f), &readfds);
+                       FD_SET(fd, &readfds);
+                       result = select(maxfd + 1, &readfds, 0, 0, 0);
+                       if (result < 0)
+                               return (result);
+                       if (result == 0)
+                               continue;
+                       if (FD_ISSET(fd, &readfds)) {
+                               nread = read(fd, buffer, sizeof(buffer));
+                               if (nread <= 0)
+                                       break;
+                               (void)fwrite(buffer, sizeof(char), nread, f);
+                       }
+                       if (FD_ISSET(fileno(f), &readfds)) {
+                               nread = read(fileno(f), buffer, sizeof(buffer));
+                               if (nread > 0 && nf != NULL) {
+                                       (void)fwrite(buffer, sizeof(char), nread, nf);
+                                       (void)fflush(nf);
+                               }
+                       }
+               }
+               (void)fflush(f);
+               (void)fclose(nf);
+               return (0);
+       } else {
+               while ((nread = read(fd, buffer, sizeof(buffer))) > 0)
+                       (void)fwrite(buffer, sizeof(char), nread, f);
+               (void)fflush(f);
+               return (nread);
+       }
+}
+
+void one_job(int lpnumber)
+{
+       FILE            *f;
+       struct sockaddr_in      client;
+       socklen_t       clientlen = sizeof(client);
+
+       if (getpeername(0, (struct sockaddr*) &client, &clientlen) >= 0)
+               syslog(LOGOPTS, "Connection from %s port %hu\n",
+                       inet_ntoa(client.sin_addr),
+                       ntohs(client.sin_port));
+       if (get_lock(lpnumber) == 0)
+               return;
+       f = open_printer(lpnumber);
+       if (copy_stream(0, f) < 0)
+               syslog(LOGOPTS, "copy_stream: %m\n");
+       fclose(f);
+       free_lock();
+}
+
+void server(int lpnumber)
+{
+       struct rlimit   resourcelimit;
+#ifdef USE_GETPROTOBYNAME
+       struct protoent *proto;
+#endif
+       int             netfd, fd, one = 1;
+       socklen_t       clientlen;
+       struct sockaddr_in      netaddr, client;
+       char            pidfilename[sizeof(PIDFILE)];
+       FILE            *f;
+       int             ipret;
+
+#ifndef        TESTING
+       switch (fork())
+       {
+       case -1:
+               syslog(LOGOPTS, "fork: %m\n");
+               exit (1);
+       case 0:         /* child */
+               break;
+       default:        /* parent */
+               exit(0);
+       }
+       /* Now in child process */
+       resourcelimit.rlim_max = 0;
+       if (getrlimit(RLIMIT_NOFILE, &resourcelimit) < 0)
+       {
+               syslog(LOGOPTS, "getrlimit: %m\n");
+               exit(1);
+       }
+       for (fd = 0; fd < resourcelimit.rlim_max; ++fd)
+               (void)close(fd);
+       if (setsid() < 0)
+       {
+               syslog(LOGOPTS, "setsid: %m\n");
+               exit(1);
+       }
+       (void)chdir("/");
+       (void)umask(022);
+       fd = open("/dev/null", O_RDWR); /* stdin */
+       (void)dup(fd);                  /* stdout */
+       (void)dup(fd);                  /* stderr */
+       (void)snprintf(pidfilename, sizeof(pidfilename), PIDFILE, lpnumber);
+       if ((f = fopen(pidfilename, "w")) == NULL)
+       {
+               syslog(LOGOPTS, "%s: %m\n", pidfilename);
+               exit(1);
+       }
+       (void)fprintf(f, "%d\n", getpid());
+       (void)fclose(f);
+       if (get_lock(lpnumber) == 0)
+               exit(1);
+#endif
+       f = open_printer(lpnumber);
+#ifdef USE_GETPROTOBYNAME
+       if ((proto = getprotobyname("tcp")) == NULL)
+       {
+               syslog(LOGOPTS, "Cannot find protocol for TCP!\n");
+               exit(1);
+       }
+       if ((netfd = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0)
+#else
+       if ((netfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
+#endif
+       {
+               syslog(LOGOPTS, "socket: %m\n");
+               exit(1);
+       }
+       if (setsockopt(netfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
+       {
+               syslog(LOGOPTS, "setsocketopt: %m\n");
+               exit(1);
+       }
+       netaddr.sin_port = htons(BASEPORT + lpnumber - '0');
+       if (bindaddr == 0) {
+               netaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+       } else {
+               ipret = inet_pton(AF_INET, bindaddr, &netaddr.sin_addr.s_addr);
+               if (ipret < 0) {
+                       syslog(LOGOPTS, "inet_pton: %m\n");
+                       exit(1);
+               } else if (ipret == 0) {
+                       syslog(LOGOPTS, "inet_pton: invalid bind IP address\n");
+                       exit(1);
+               }
+       }
+       memset(netaddr.sin_zero, 0, sizeof(netaddr.sin_zero));
+       if (bind(netfd, (struct sockaddr*) &netaddr, sizeof(netaddr)) < 0)
+       {
+               syslog(LOGOPTS, "bind: %m\n");
+               exit(1);
+       }
+       if (listen(netfd, 5) < 0)
+       {
+               syslog(LOGOPTS, "listen: %m\n");
+               exit(1);
+       }
+       clientlen = sizeof(client);
+       memset(&client, 0, sizeof(client));
+       while ((fd = accept(netfd, (struct sockaddr*) &client, &clientlen)) >= 0)
+       {
+#ifdef USE_LIBWRAP
+               if (hosts_ctl("p910nd", STRING_UNKNOWN,
+                       inet_ntoa(client.sin_addr), STRING_UNKNOWN) == 0) {
+                       syslog(LOGOPTS, "Connection from %s port %hd rejected\n",
+                               inet_ntoa(client.sin_addr),
+                               ntohs(client.sin_port));
+                       close(fd);
+                       continue;
+               }
+#endif
+               syslog(LOGOPTS, "Connection from %s port %hd accepted\n",
+                       inet_ntoa(client.sin_addr),
+                       ntohs(client.sin_port));
+               /*write(fd, "Printing", 8);*/
+               if (copy_stream(fd, f) < 0)
+                       syslog(LOGOPTS, "copy_stream: %m\n");
+               (void)close(fd);
+       }
+       syslog(LOGOPTS, "accept: %m\n");
+       free_lock();
+       exit(1);
+}
+
+int is_standalone(void)
+{
+       struct sockaddr_in      bind_addr;
+       socklen_t               ba_len;
+
+       /*
+        * Check to see if a socket was passed to us from inetd.
+        *
+        * Use getsockname() to determine if descriptor 0 is indeed a socket
+        * (and thus we are probably a child of inetd) or if it is instead
+        * something else and we are running standalone.
+        */
+       ba_len = sizeof(bind_addr);
+       if (getsockname(0, (struct sockaddr*) &bind_addr, &ba_len) == 0)
+               return (0);             /* under inetd */
+       if (errno != ENOTSOCK)          /* strange... */
+               syslog(LOGOPTS, "getsockname: %m\n");
+       return (1);
+}
+
+int main(int argc, char *argv[])
+{
+       int             c, lpnumber;
+       char            *p;
+
+       if (argc <= 0)          /* in case not provided in inetd.conf */
+               progname = "p910nd";
+       else
+       {
+               progname = argv[0];
+               if ((p = strrchr(progname, '/')) != 0)
+                       progname = p + 1;
+       }
+       lpnumber = '0';
+       while ((c = getopt(argc, argv, "bi:f:v")) != EOF)
+       {
+               switch (c)
+               {
+               case 'b':
+                       bidir = 1;
+                       break;
+               case 'f':
+                       device = optarg;
+                       break;
+               case 'i':
+                       bindaddr = optarg;
+                       break;
+               case 'v':
+                       show_version();
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if (argc > 0)
+       {
+               if (isdigit(argv[0][0]))
+                       lpnumber = argv[0][0];
+       }
+       /* change the n in argv[0] to match the port so ps will show that */
+       if ((p = strstr(progname, "p910n")) != NULL)
+               p[4] = lpnumber;
+       
+       /* We used to pass (LOG_PERROR|LOG_PID|LOG_LPR|LOG_ERR) to syslog, but
+        * syslog ignored the LOG_PID and LOG_PERROR option.  I.e. the intention
+        * was to add both options but the effect was to have neither.
+        * I disagree with the intention to add PERROR.  --Stef  */
+       openlog (p, LOG_PID, LOG_LPR);
+       if (is_standalone())
+               server(lpnumber);
+       else
+               one_job(lpnumber);
+       return (0);
+}
diff --git a/contrib/p910nd-0.8/p910nd.sh b/contrib/p910nd-0.8/p910nd.sh
new file mode 100755 (executable)
index 0000000..291a836
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# p910nd.sh    This shell script takes care of starting and stopping
+#               p910nd (port 9100+n printer daemon)
+#              This script only controls the one on port 9101.
+#              You can start others if you wish.
+#
+
+# Todo: Make it fully LSB
+
+# See how we were called.
+case "$1" in
+  start)
+       # Start daemons.
+       echo -n "Starting p910nd: "
+       # default port is 1 so it will appear as p9101d on a ps
+       start_daemon p910nd
+       echo
+       ;;
+  stop)
+       # Stop daemons.
+       echo -n "Shutting down p910nd: "
+       killproc p9101d
+       echo
+       rm -f /var/run/p9101.pid
+        ;;
+  status)
+       status p9101d
+       ;;
+  restart)
+       $0 stop
+       $0 start
+       ;;
+  *)
+       echo "Usage: p910nd {start|stop|restart|status}"
+       exit 1
+esac
+
+exit 0
diff --git a/contrib/ppmtoansi/Makefile b/contrib/ppmtoansi/Makefile
new file mode 100644 (file)
index 0000000..bc0ca0a
--- /dev/null
@@ -0,0 +1,67 @@
+CPPFLAGS    =
+LDLIBS      = 
+CFLAGS      = -pipe -g -O2 -Wall
+LDFLAGS     = -pipe
+CC          = gcc
+LD          = gcc
+# Some "black" magic to determine optimal compiler flags for target
+# architecture
+TARGET_ARCH:= $(shell if [ \! -r .compile-options ] ; then ( \
+                cpu=`grep cpu /proc/cpuinfo 2>&1 |head -1| \
+                     cut -d : -f 2-| sed -e 's/ //g'`; \
+                if [ x"$$cpu" = x"" ] ; then \
+                  echo -fno-strength-reduce; \
+                else if [ "$$cpu" = "386" ] ; then \
+                  echo -m386 -fno-strength-reduce; \
+                else if [ "$$cpu" = "486" ] ; then \
+                  echo -m486 -fno-strength-reduce; \
+                else if [ "$$cpu" = "Alpha" ] ; then \
+                  echo -fno-strength-reduce; \
+                else echo main\(\)\{\} >.compile-options.c; \
+                  if gcc -mpentium -o .compile-options.o -c \
+                         .compile-options.c &>/dev/null; then \
+                     echo -mpentium -fstrength-reduce; \
+                 else if gcc -m486 -malign-functions=2 -malign-jumps=2 \
+                             -malign-loops=2 -o .compile-options.o -c \
+                             .compile-options.c &>/dev/null; then \
+                  echo -n -m486 -malign-functions=2 -malign-jumps=2; \
+                  echo ' '-malign-loops=2 -fno-strength-reduce; \
+                else echo -m486; \
+              fi;fi;fi;fi;fi;fi) > .compile-options; \
+              rm -f .compile-options.c .compile-options.o; \
+              fi; cat .compile-options)
+ASFLAGS     = $(TARGET_ARCH)
+
+OBJS        = ppmtoansi.o
+
+##############################################################################
+
+ifeq (.depend,$(wildcard .depend))
+all: ppmtoansi
+include .depend
+else
+all: depend
+       @$(MAKE) all
+endif
+
+##############################################################################
+
+ppmtoansi: $(OBJS)
+
+##############################################################################
+
+clean:
+       $(RM) *~ *.o *.dvi *.log *.aux *yacc.tab.[ch] *yacc.output *lex.[co] \
+              *.dat .depend .tmp_depend .compile-options*
+       strip ppmtoansi >&/dev/null || true
+
+distclean: clean
+       $(RM) -rf ppmtoansi
+
+##############################################################################
+
+depend:
+       for i in *.c;do $(CPP) $(CPPFLAGS) -MM $$i;done >.tmp_depend
+       mv .tmp_depend .depend
+
+##############################################################################
diff --git a/contrib/ppmtoansi/demo/dos.ansi b/contrib/ppmtoansi/demo/dos.ansi
new file mode 100644 (file)
index 0000000..2ce5cda
--- /dev/null
@@ -0,0 +1 @@
+\e[9;;1- \e[15;;1- \e[18;;5-Ûl\e[9;1;3-$\80\e[13;1;3-$\80\e[17;1;1-À\e[9;2;1- \e[12;2;1- \e[15;2;1- \e[17;2;1-À\e[9;3;1- \e[15;3;1- \e[18;3;5-Ûl\e[9;4;1- \e[15;4;1- \e[23;4;1-À\e[9;5;1- \e[15;5;1- \e[23;5;1-À\e[9;6;1- \e[15;6;1- \e[18;6;5-Ûl\e[8;8;4-I \e[14;8;4-m°\e[19;8;5-¶Ú\e[8;9;1-@\e[12;9;2-L\e[18;9;2-¬\e[8;10;1-@\e[11;10;1-`\e[13;10;1-@\e[18;10;1- \e[20;10;1-`\e[8;11;1-@\e[11;11;1-`\e[13;11;1-@\e[19;11;5-¶Ú\e[8;12;1-@\e[11;12;1-`\e[13;12;1-@\e[20;12;1-`\e[24;12;1- \e[8;13;1-@\e[12;13;2-L\e[18;13;2-l\e[24;13;1- \e[8;14;4-I \e[14;14;4-m°\e[19;14;5-¶Ú
\ No newline at end of file
diff --git a/contrib/ppmtoansi/demo/dos.ppm b/contrib/ppmtoansi/demo/dos.ppm
new file mode 100644 (file)
index 0000000..6efde7f
--- /dev/null
@@ -0,0 +1,51 @@
+P3
+17 16
+65535
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 0 0  0 0 0
+0 0 0  65535 0 0  65535 0 0  65535 0 0  0 0 0  65535 0 0
+65535 0 0  65535 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  65535 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 65535 65535  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 65535 65535  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  0 0 0
+0 65535 0  0 0 0  0 0 0  0 0 0  0 65535 0  65535 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 65535  65535 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 65535 0  0 0 0  0 0 0  65535 65535 0  0 0 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 65535  0 0 0
+65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 65535 0  0 0 0  0 0 0  65535 65535 0  0 0 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  0 0 0
+0 65535 0  0 0 0  0 0 0  65535 65535 0  0 0 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  0 0 0  0 0 0  0 0 0  65535 0 65535
+0 65535 0  0 0 0  0 0 0  0 0 0  0 65535 0  65535 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 0  65535 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 65535
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
diff --git a/contrib/ppmtoansi/demo/dos.xpm b/contrib/ppmtoansi/demo/dos.xpm
new file mode 100644 (file)
index 0000000..471c4ed
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"17 16 6 1",
+/* colors */
+"` c #000000",
+"a c #00FFFF",
+"b c #00FF00",
+"c c #FF00FF",
+"d c #FF0000",
+"e c #FFFF00",
+/* pixels */
+"`d`````d``aaaaa``",
+"`ddd`ddd`a```````",
+"`d``d``d`a```````",
+"`d`````d``aaaaa``",
+"`d`````d```````a`",
+"`d`````d```````a`",
+"`d`````d``aaaaa``",
+"`````````````````",
+"bbbb``eeee`ccccc`",
+"b```be````ce`````",
+"b``e`b````c`e````",
+"b``e`b`````ccccc`",
+"b``e`b``````e```c",
+"b```be````ee````c",
+"bbbb``eeee`ccccc`",
+"`````````````````"
+};
diff --git a/contrib/ppmtoansi/demo/etherboot.ansi b/contrib/ppmtoansi/demo/etherboot.ansi
new file mode 100644 (file)
index 0000000..7975f36
Binary files /dev/null and b/contrib/ppmtoansi/demo/etherboot.ansi differ
diff --git a/contrib/ppmtoansi/demo/etherboot.ppm b/contrib/ppmtoansi/demo/etherboot.ppm
new file mode 100644 (file)
index 0000000..da5b245
--- /dev/null
@@ -0,0 +1,99 @@
+P3
+32 16
+65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 65535 0
+0 0 0  0 65535 0  0 0 0  0 0 0  0 65535 0  0 0 0
+0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 0 0
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0
+0 65535 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 65535 0
+0 0 0  0 65535 0  0 0 0  0 0 0  0 65535 0  0 0 0
+0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 0 0
+0 65535 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+0 0 0  65535 0 0  0 0 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 0 0
+0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 0 0
+0 65535 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+0 0 0  0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+0 0 0  65535 0 0  0 0 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 65535 0  0 0 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 65535 0  0 0 0
+0 0 0  0 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 65535 0  0 65535 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 65535 0  0 0 0
+0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 65535 0
+0 0 0  0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 65535 0  0 0 0
+0 0 0  0 0 0  0 65535 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0  0 65535 65535  0 0 0  0 0 0  0 65535 65535
+0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0
diff --git a/contrib/ppmtoansi/demo/etherboot.xpm b/contrib/ppmtoansi/demo/etherboot.xpm
new file mode 100644 (file)
index 0000000..d421714
--- /dev/null
@@ -0,0 +1,27 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"32 16 4 1",
+/* colors */
+"` c #000000",
+"a c #00FFFF",
+"b c #00FF00",
+"c c #FF0000",
+/* pixels */
+"``a``a``a``a``a``a``a``a``a``a``",
+"``a``a``a``a``a``a``a``a``a``a``",
+"cccccccccccccccccccccccccccccccc",
+"c``bbbb`bbbb`bbbb`bbbbb`bbbb```c",
+"c``bbbb`b``b`b``b```b```bbbb```c",
+"c``b``b`b``b`b``b```b```b``````c",
+"`c`bbbb`bbbb`bbbb```b```b``````c",
+"``c````````````````````````````c",
+"`c`bbbbb`bbbb`bbbbb`bbbb```````c",
+"c````b```b``````b```bbbb```````c",
+"c````b```bbb````b```b``````````c",
+"c````b```b``````b```b``````````c",
+"cccccccccccccccccccccccccccccccc",
+"``a``a``a``a``a``a``a``a``a``a``",
+"``a``a``a``a``a``a``a``a``a``a``",
+"````````````````````````````````"
+};
diff --git a/contrib/ppmtoansi/demo/flash.ansi b/contrib/ppmtoansi/demo/flash.ansi
new file mode 100644 (file)
index 0000000..43837a7
--- /dev/null
@@ -0,0 +1 @@
+\e[11;;2-l\e[11;1;2-l\e[17;1;1-`\e[11;2;2-l\e[16;2;2-l\e[11;3;2-l\e[15;3;3-m\80\e[11;4;2-l\e[14;4;4-m°\e[11;5;2-l\e[14;5;4-m°\e[11;6;4-m°\e[16;6;2-l\e[11;7;4-m°\e[16;7;2-l\e[11;8;3-m\80\e[16;8;2-l\e[11;9;2-l\e[16;9;2-l\e[11;10;1-`\e[16;10;2-l\e[16;11;2-l\e[13;12;2-l\e[16;12;2-l\e[19;12;2-l\e[14;13;6-m¶À\e[15;14;4-m°\e[16;15;2-l
\ No newline at end of file
diff --git a/contrib/ppmtoansi/demo/flash.ppm b/contrib/ppmtoansi/demo/flash.ppm
new file mode 100644 (file)
index 0000000..1464af6
--- /dev/null
@@ -0,0 +1,35 @@
+P3
+10 16
+65535
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  65535 65535 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  0 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  0 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 65535 0  65535 65535 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  65535 65535 0  65535 65535 0
+0 0 0  0 0 0  0 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0
diff --git a/contrib/ppmtoansi/demo/flash.xpm b/contrib/ppmtoansi/demo/flash.xpm
new file mode 100644 (file)
index 0000000..25419d7
--- /dev/null
@@ -0,0 +1,25 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"10 16 2 1",
+/* colors */
+"  c #000000",
+"x c #FFFF00",
+/* pixels */
+"xx        ",
+"xx    x   ",
+"xx   xx   ",
+"xx  xxx   ",
+"xx xxxx   ",
+"xx xxxx   ",
+"xxxx xx   ",
+"xxxx xx   ",
+"xxx  xx   ",
+"xx   xx   ",
+"x    xx   ",
+"     xx   ",
+"  xx xx xx",
+"   xxxxxx ",
+"    xxxx  ",
+"     xx   ",
+};           
diff --git a/contrib/ppmtoansi/demo/floppy.ansi b/contrib/ppmtoansi/demo/floppy.ansi
new file mode 100644 (file)
index 0000000..f4267f4
--- /dev/null
@@ -0,0 +1 @@
+\e[9;;14-%\92Ûm¶@\e[8;1;16-$²[l\92É\e[8;2;17-$²[l\92É \e[8;3;17-$²[l\92É \e[8;4;17-$¶Ûm¶É \e[8;5;17;1+\e[8;6;17;1+\e[8;7;17-$í¶Ûm\89 \e[8;8;17-$ëm¶Û\89 \e[8;9;17-$í¶Ûm\89 \e[8;10;17-$ëm¶Û\89 \e[8;11;17-$í¶Ûm\89 \e[8;12;17-$ëm¶Û\89 \e[8;13;17-2m¶Ûm¤ \e[8;14;17-2km¶Û¤ \e[9;15;15-'m¶ÛlH
\ No newline at end of file
diff --git a/contrib/ppmtoansi/demo/floppy.ppm b/contrib/ppmtoansi/demo/floppy.ppm
new file mode 100644 (file)
index 0000000..2b0b286
--- /dev/null
@@ -0,0 +1,51 @@
+P3
+17 16
+65535
+0 0 0  65535 0 0  65535 0 0  65535 65535 0  65535 0 0  65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 0 0  0 0 0  0 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 65535 0  65535 0 0  65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0  65535 0 0
+65535 0 0  65535 65535 0  65535 0 0  65535 0 0  0 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 65535 0  65535 0 0  65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0  65535 0 0
+65535 0 0  65535 65535 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 65535 0  65535 0 0  65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0  65535 0 0
+65535 0 0  65535 65535 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 65535 65535  65535 0 65535  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535
+65535 0 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 65535 65535  65535 0 65535  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535
+65535 0 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 65535 65535  65535 0 65535  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535
+65535 0 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  0 0 65535  0 0 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 0 65535  0 0 65535  65535 0 0
+65535 0 0  0 0 65535  0 0 65535  0 65535 65535  65535 0 65535  65535 0 65535
+65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535
+65535 0 65535  0 65535 65535  0 0 65535  0 0 65535  65535 0 0
+0 0 0  65535 0 0  65535 0 0  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  65535 0 0  65535 0 0  0 0 0
diff --git a/contrib/ppmtoansi/demo/floppy.xpm b/contrib/ppmtoansi/demo/floppy.xpm
new file mode 100644 (file)
index 0000000..8bb60d2
--- /dev/null
@@ -0,0 +1,29 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"17 16 6 1",
+/* colors */
+"` c #000000",
+"a c #00FFFF",
+"b c #FF00FF",
+"c c #FF0000",
+"d c #FFFF00",
+"e c #0000FF",
+/* pixels */
+"`ccdccddddddddc``",
+"cccdccddddcccdcc`",
+"cccdccddddcccdccc",
+"cccdccddddcccdccc",
+"cccdddddddddddccc",
+"ccccccccccccccccc",
+"ccccccccccccccccc",
+"cccaaaaaaaaaaaccc",
+"cccabbbbbbbbbaccc",
+"cccaaaaaaaaaaaccc",
+"cccabbbbbbbbbaccc",
+"cccaaaaaaaaaaaccc",
+"cccabbbbbbbbbaccc",
+"ceeaaaaaaaaaaaeec",
+"ceeabbbbbbbbbaeec",
+"`ccaaaaaaaaaaacc`"
+};
diff --git a/contrib/ppmtoansi/demo/hd.ansi b/contrib/ppmtoansi/demo/hd.ansi
new file mode 100644 (file)
index 0000000..33bda53
Binary files /dev/null and b/contrib/ppmtoansi/demo/hd.ansi differ
diff --git a/contrib/ppmtoansi/demo/hd.ppm b/contrib/ppmtoansi/demo/hd.ppm
new file mode 100644 (file)
index 0000000..34878bf
--- /dev/null
@@ -0,0 +1,51 @@
+P3
+17 16
+65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+65535 0 0  65535 0 0  65535 0 0  0 0 0  0 0 0
+65535 0 0  0 65535 0  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535
+0 65535 0  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  0 65535 0
+65535 0 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 0
+65535 0 0  0 65535 0  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535
+0 65535 0  65535 0 65535  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+65535 0 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 0
+65535 0 0  0 65535 0  65535 0 65535  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  65535 0 65535  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+65535 0 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 0
+65535 0 0  0 65535 0  65535 0 65535  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  65535 0 65535  65535 0 65535  65535 0 65535  65535 0 65535  0 65535 0
+65535 0 0  65535 65535 0  65535 0 0  0 0 0  0 0 0
+65535 0 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0  0 65535 0
+65535 0 0  65535 0 0  0 0 65535  0 0 65535  0 0 65535
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  0 65535 65535  0 65535 65535  0 0 65535  0 0 65535
+0 0 0  0 0 65535  0 65535 65535  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  0 65535 65535
+0 65535 65535  0 65535 65535  0 0 65535  0 65535 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 65535 65535  0 65535 65535  0 0 65535
+0 0 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 0 65535  0 65535 65535  0 65535 65535  0 0 65535
+0 0 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 65535 65535  0 0 65535  0 65535 65535  0 0 65535  0 0 0
+0 0 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535  0 65535 65535
+0 65535 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
diff --git a/contrib/ppmtoansi/demo/hd.xpm b/contrib/ppmtoansi/demo/hd.xpm
new file mode 100644 (file)
index 0000000..280c7ab
--- /dev/null
@@ -0,0 +1,30 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"17 16 7 1",
+/* colors */
+"` c #000000",
+"a c #00FFFF",
+"b c #00FF00",
+"c c #FF00FF",
+"d c #FF0000",
+"e c #FFFF00",
+"f c #0000FF",
+/* pixels */
+"`````````````````",
+"ddddddddddddd````",
+"dbbbbbbbbbbbddd``",
+"dbccccbccccbdeed`",
+"dbccccbcbbbbdeed`",
+"dbcbbbbcbbbbdeed`",
+"dbcbbbbccccbded``",
+"dbbbbbbbbbbbddfff",
+"dddddddddddddaaff",
+"`faddddddddaaafaf",
+"ffffffffffffffaaf",
+"faaaaaaaaaaaafaaf",
+"faaaaaafffffafaf`",
+"faaaaaaaaaaaaff``",
+"ffffffffffffff```",
+"`````````````````"
+};
diff --git a/contrib/ppmtoansi/demo/ibmmap.ppm b/contrib/ppmtoansi/demo/ibmmap.ppm
new file mode 100644 (file)
index 0000000..648676e
--- /dev/null
@@ -0,0 +1,11 @@
+P3
+8 1
+255
+  0   0   0
+255   0   0
+  0 255   0
+  0   0 255
+255 255   0
+255   0 255
+  0 255 255
+255 255 255
diff --git a/contrib/ppmtoansi/demo/ibmmap.xpm b/contrib/ppmtoansi/demo/ibmmap.xpm
new file mode 100644 (file)
index 0000000..06d4d99
--- /dev/null
@@ -0,0 +1,16 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"8 1 8 1",
+/* colors */
+"` c #000000",
+"a c #00FFFF",
+"b c #00FF00",
+"c c #FF00FF",
+"d c #FF0000",
+"e c #FFFFFF",
+"f c #FFFF00",
+"g c #0000FF",
+/* pixels */
+"`dbgfcae"
+};
diff --git a/contrib/ppmtoansi/demo/linux-logo.ansi b/contrib/ppmtoansi/demo/linux-logo.ansi
new file mode 100644 (file)
index 0000000..165f834
Binary files /dev/null and b/contrib/ppmtoansi/demo/linux-logo.ansi differ
diff --git a/contrib/ppmtoansi/demo/linux-logo.ppm b/contrib/ppmtoansi/demo/linux-logo.ppm
new file mode 100644 (file)
index 0000000..18604b4
--- /dev/null
@@ -0,0 +1,552 @@
+P3
+52 61
+65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+65535 65535 65535  0 0 0  0 0 0  65535 65535 65535  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 65535  0 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 0  65535 65535 65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 65535  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 0 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 0 0  65535 65535 0  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 0 0  65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 0  0 0 0  65535 65535 0  0 0 0  0 0 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  65535 65535 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0
+65535 65535 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0
+65535 65535 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 0 0  65535 0 0  0 0 0  65535 0 0
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 0 0  0 0 65535  0 0 65535
+0 0 65535  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  0 0 0
+0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  0 0 65535
+0 0 65535  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  0 0 0  0 0 0  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  0 0 65535
+65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 0 0  0 0 65535  0 0 65535
+0 0 65535  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  0 0 0  0 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  65535 0 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  65535 0 0  65535 0 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 65535 0  65535 65535 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 0 0
+0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 65535  0 0 65535  0 0 65535  65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  65535 0 0
+65535 0 0  65535 0 0  65535 65535 0  65535 0 0  65535 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  65535 0 0  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 65535
diff --git a/contrib/ppmtoansi/demo/linux-logo.xpm b/contrib/ppmtoansi/demo/linux-logo.xpm
new file mode 100644 (file)
index 0000000..fd2dd67
--- /dev/null
@@ -0,0 +1,73 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"52 61 5 1",
+/* colors */
+"` c #000000",
+"a c #FF0000",
+"b c #FFFFFF",
+"c c #FFFF00",
+"d c #0000FF",
+/* pixels */
+"dddddddddddddddddddddd```````ddddddddddddddddddddddd",
+"dddddddddddddddddddd```````````ddddddddddddddddddddd",
+"ddddddddddddddddddd`````````````dddddddddddddddddddd",
+"dddddddddddddddddd```````````````ddddddddddddddddddd",
+"ddddddddddddddddd`````````````````dddddddddddddddddd",
+"ddddddddddddddddd`````````````````dddddddddddddddddd",
+"ddddddddddddddddd``````````````````ddddddddddddddddd",
+"ddddddddddddddddd``````````````````ddddddddddddddddd",
+"ddddddddddddddddd``````````````````ddddddddddddddddd",
+"ddddddddddddddddd``bb`````bbbb`````ddddddddddddddddd",
+"ddddddddddddddddd``bbb```bbbbb`````ddddddddddddddddd",
+"ddddddddddddddddd`b``b```bb``bb````ddddddddddddddddd",
+"ddddddddddddddddd`b``````b````b````ddddddddddddddddd",
+"ddddddddddddddddd`````cccc````b````ddddddddddddddddd",
+"ddddddddddddddddd``b`cccccca`b``````dddddddddddddddd",
+"ddddddddddddddddd``acccccccccc``````dddddddddddddddd",
+"ddddddddddddddddd``cccccccccccc`````dddddddddddddddd",
+"ddddddddddddddddd``ccccccccccca`````dddddddddddddddd",
+"ddddddddddddddddd```ccccccaccc``````dddddddddddddddd",
+"ddddddddddddddddd``bacccaccccbb``````ddddddddddddddd",
+"ddddddddddddddddd``bbacccacbbbb```````dddddddddddddd",
+"ddddddddddddddddd``bbbaaccbbbbbb``````dddddddddddddd",
+"dddddddddddddddd```bbbbbbbbbbbbb```````ddddddddddddd",
+"ddddddddddddddd```bbbbbbbbbbbbbbb``````ddddddddddddd",
+"dddddddddddddd```bbbbbbbbbbbbbbbb```````dddddddddddd",
+"dddddddddddddd```bbbbbbbbbbbbbbbbb```````ddddddddddd",
+"ddddddddddddd```bbbbbbbbbbbbbbbbbb````````dddddddddd",
+"dddddddddddd````bbbbbbbbbbbbbbbbbb````````dddddddddd",
+"dddddddddddd````bbbbbbbbbbbbbbbbbbb````````ddddddddd",
+"ddddddddddd````bbbbbbbbbbbbbbbbbbbb`````````dddddddd",
+"ddddddddddd````bbbbbbbbbbbbbbbbbbbbb````````dddddddd",
+"ddddddddddd```bbbbbbbbbbbbbbbbbbbbbb````````dddddddd",
+"dddddddddd````bbbbbbbbbbbbbbbbbbbbbbb````````ddddddd",
+"dddddddddd```bbbbbbbbbbbbbbbbbbbbbbbb````````ddddddd",
+"ddddddddd````bbbbbbbbbbbbbbbbbbbbbbbb````````ddddddd",
+"ddddddddd````bbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"ddddddddd```bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"dddddddd````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"ddddddd`````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"ddddddd`````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"ddddddd`````bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"ddddddd``c``bbbbbbbbbbbbbbbbbbbbbbbbb`````````dddddd",
+"dddddddcccc``bbbbbbbbbbbbbbbbbbbbbbcc`````````dddddd",
+"dddddddccccc``bbbbbbbbbbbbbbbbbbbbcccc```````cdddddd",
+"ddddddccccccc``bbbbbbbbbbbbbbbbbbbccca``````ccaddddd",
+"dddddcccccccca``bbbbbbbbbbbbbbbbbbccca`````cccaddddd",
+"dacccccccccccc```bbbbbbbbbbbbbbbbbccccaa`aaccccddddd",
+"acccccccccccccc````bbbbbbbbbbbbbbbcccccccccccccadddd",
+"acccccccccccccc````bbbbbbbbbbbbbbbccccccccccccccdddd",
+"accccccccccccccc````bbbbbbbbbbbbbbaccccccccccccccadd",
+"daccccccccccccccc``bbbbbbbbbbbbbb``ccccccccccccccccd",
+"daccccccccccccccccbbbbbbbbbbbbbb``accccccccccccccccc",
+"acccccccccccccccccbbbbbbbbbbbbb```accccccccccccccccd",
+"acccccccccccccccccabbbbbbbbbb`````accccccccccccccadd",
+"dacccccccccccccccca``bbbb`````````acccccccccccccdddd",
+"dacccccccccccccccca```````````````acccccccccccaddddd",
+"ddaacccccccccccccca```````````````acccccccccaddddddd",
+"ddddddaaaacccccccaddd```````````dddaccccccaddddddddd",
+"ddddddddddaaaaaaaddddddddddddddddddaaacaaddddddddddd",
+"ddddddddddddddadddddddddddddddddddddaaaadddddddddddd",
+"dddddddddddddddddddddddddddddddddddddddddddddddddddd"
+};
diff --git a/contrib/ppmtoansi/demo/make-ansi.sh b/contrib/ppmtoansi/demo/make-ansi.sh
new file mode 100755 (executable)
index 0000000..16d7b98
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+xpmtoppm                                <linux-logo.xpm >linux-logo.ppm
+../ppmtoansi -b 0/0/255 -y 10 -t 0/0/0:4 linux-logo.ppm >linux-logo.ansi
+xpmtoppm                                <etherboot.xpm  >etherboot.ppm
+../ppmtoansi -b 0/0/0                    etherboot.ppm  >etherboot.ansi
+xpmtoppm                                <text.xpm       >text.ppm
+../ppmtoansi -b 0/0/0   -x 10            text.ppm       >text.ansi
+xpmtoppm                                <x.xpm          >x.ppm
+../ppmtoansi -b 0/0/0   -x  8            x.ppm          >x.ansi
+xpmtoppm                                <dos.xpm        >dos.ppm
+../ppmtoansi -b 0/0/0   -x  8            dos.ppm        >dos.ansi
+xpmtoppm                                <hd.xpm         >hd.ppm
+../ppmtoansi -b 0/0/0   -x  8            hd.ppm         >hd.ansi
+xpmtoppm                                <floppy.xpm     >floppy.ppm
+../ppmtoansi -b 0/0/0   -x  8            floppy.ppm     >floppy.ansi
+xpmtoppm                                <flash.xpm      >flash.ppm
+../ppmtoansi -b 0/0/0   -x 11            flash.ppm      >flash.ansi
diff --git a/contrib/ppmtoansi/demo/text.ansi b/contrib/ppmtoansi/demo/text.ansi
new file mode 100644 (file)
index 0000000..bbe7998
Binary files /dev/null and b/contrib/ppmtoansi/demo/text.ansi differ
diff --git a/contrib/ppmtoansi/demo/text.ppm b/contrib/ppmtoansi/demo/text.ppm
new file mode 100644 (file)
index 0000000..c6f8761
--- /dev/null
@@ -0,0 +1,51 @@
+P3
+13 16
+65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535
+0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  0 0 65535
+0 0 65535  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  65535 65535 65535
+0 0 65535  65535 65535 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  65535 65535 0
+65535 65535 0  0 0 65535  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 65535  65535 65535 0
+65535 65535 0  65535 0 0  0 0 65535  0 0 0  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 65535 65535
+65535 65535 65535  65535 65535 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  0 0 65535  0 0 65535  0 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 65535  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 65535  0 0 65535  0 0 65535
+0 0 0
+0 0 0  0 0 0  65535 0 0  65535 65535 65535  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  0 0 65535  0 0 65535  0 0 0
+0 0 0
+0 0 0  65535 65535 0  65535 65535 0  65535 0 0  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 65535  65535 0 0  0 0 65535  65535 65535 0
+0 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 65535  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+65535 0 0
+65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 65535
+65535 65535 65535  65535 65535 65535  65535 65535 0  65535 65535 0  65535 65535 0  65535 65535 0
+0 0 0
+0 0 0  0 0 0  0 0 0  65535 0 0  65535 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  65535 0 0  65535 0 0  0 0 0
+0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0
diff --git a/contrib/ppmtoansi/demo/text.xpm b/contrib/ppmtoansi/demo/text.xpm
new file mode 100644 (file)
index 0000000..5261b96
--- /dev/null
@@ -0,0 +1,28 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"13 16 5 1",
+/* colors */
+"` c #000000",
+"a c #FF0000",
+"b c #FFFFFF",
+"c c #FFFF00",
+"d c #0000FF",
+/* pixels */
+"`````ddd`````",
+"````ddddd````",
+"````dbdbd````",
+"````dccdd````",
+"````dccad````",
+"`````bbbdd```",
+"```dbbbbdd```",
+"```dbbbbbdd``",
+"``dbbbbbbdd``",
+"``dbbbbbbddd`",
+"``abbbbbbdd``",
+"`ccabbbbbadc`",
+"ccccbbbbcccca",
+"cccccbbbcccc`",
+"```aa````aa``",
+"`````````````"
+};
diff --git a/contrib/ppmtoansi/demo/x.ansi b/contrib/ppmtoansi/demo/x.ansi
new file mode 100644 (file)
index 0000000..e2844b3
--- /dev/null
@@ -0,0 +1 @@
+\e[8;1;4-$\90\e[23;1;1- \e[9;2;4-$\90\e[22;2;1- \e[10;3;4-$\90\e[21;3;1- \e[11;4;4-$\90\e[20;4;1- \e[12;5;4-$\90\e[19;5;1- \e[13;6;4-$\90\e[18;6;1- \e[14;7;2-$\e[17;7;2-$\e[14;8;1- \e[16;8;4-$\90\e[13;9;1- \e[17;9;4-$\90\e[12;10;1- \e[18;10;4-$\90\e[11;11;1- \e[19;11;4-$\90\e[10;12;1- \e[20;12;4-$\90\e[9;13;1- \e[21;13;4-$\90
\ No newline at end of file
diff --git a/contrib/ppmtoansi/demo/x.ppm b/contrib/ppmtoansi/demo/x.ppm
new file mode 100644 (file)
index 0000000..53e5bcf
--- /dev/null
@@ -0,0 +1,51 @@
+P3
+17 16
+65535
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  65535 0 0  0 0 0
+0 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  65535 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 0 0  65535 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  65535 0 0  0 0 0  65535 0 0  65535 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  0 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0
+0 0 0  0 0 0  0 0 0  65535 0 0  65535 0 0  65535 0 0
+65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0  65535 0 0
+65535 0 0  65535 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  65535 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  65535 0 0
+65535 0 0  65535 0 0  65535 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+65535 0 0  65535 0 0  65535 0 0  65535 0 0  0 0 0
+0 0 0  65535 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  65535 0 0  65535 0 0  65535 0 0  65535 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
diff --git a/contrib/ppmtoansi/demo/x.xpm b/contrib/ppmtoansi/demo/x.xpm
new file mode 100644 (file)
index 0000000..d069527
--- /dev/null
@@ -0,0 +1,25 @@
+/* XPM */
+static char *noname[] = {
+/* width height ncolors chars_per_pixel */
+"17 16 2 1",
+/* colors */
+"` c #000000",
+"a c #FF0000",
+/* pixels */
+"`````````````````",
+"aaaa```````````a`",
+"`aaaa`````````a``",
+"``aaaa```````a```",
+"```aaaa`````a````",
+"````aaaa```a`````",
+"`````aaaa`a``````",
+"``````aa`aa``````",
+"``````a`aaaa`````",
+"`````a```aaaa````",
+"````a`````aaaa```",
+"```a```````aaaa``",
+"``a`````````aaaa`",
+"`a```````````aaaa",
+"`````````````````",
+"`````````````````"
+};
diff --git a/contrib/ppmtoansi/ppmtoansi.c b/contrib/ppmtoansi/ppmtoansi.c
new file mode 100644 (file)
index 0000000..71d95cb
--- /dev/null
@@ -0,0 +1,235 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int palette[8][3] = {
+/* black,        red,          green,        yellow,      */ 
+  {  0,  0,  0},{255,  0,  0},{  0,255,  0},{255,255,  0},
+  {  0,  0,255},{255,  0,255},{  0,255,255},{255,255,255}};
+/* blue,         magenta,      cyan,         white        */
+
+static struct trans {
+  struct trans *next;
+  int          idx,r,g,b;
+} *trans = NULL;
+
+static int skipcomment(FILE *fp)
+{
+  int ch;
+  
+  for (;;) {
+    ch = getc(fp);
+    if (ch != '#')
+      return(ch);
+    while (ch != '\n' && ch != EOF)
+      ch = getc(fp); }
+}
+
+static int readentry(FILE *fp,int format,int depth)
+{
+  int ch,i = 0;
+  
+  if (format == '3') {
+    while ((ch = getc(fp)) == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
+    if (ch < '0' || ch > '9') {
+    error:
+      fprintf(stderr,"Format error in input file\n");
+      exit(1); }
+    for (; ch >= '0' && ch <= '9'; ch = getc(fp))
+      i = 10*i + ch - '0'; }
+  else {
+    if ((i = getc(fp)) > depth || i < 0)
+      goto error; }
+  return((i*256)/(depth+1));
+}
+
+static void packpixel(char *data,int c)
+{
+  int i = 0, n = 0;
+
+  while (c--) {
+    i = (i << 3) | (*data++ & 0x7);
+    if ((n += 3) >= 8)
+      putchar((i >> (n -= 8)) & 0xFF); }
+  if (n)
+    putchar(i << (8 - n));
+  return;
+}
+
+static int dg(int i)
+{
+  int d;
+
+  for (d = 0; i; d++, i /= 10);
+  return(d);
+}
+
+static char *i2s(char *buf,int i)
+{
+/*  if (!i)
+    *buf = '\000';
+  else*/
+    sprintf(buf,"%d",i);
+  return(buf);
+}
+
+static void flushdata(int x,int y,int c,char *data)
+{
+  char b1[10],b2[10],b3[10],b4[10];
+  int i,j,rle,v;
+
+  for (i = j = v = 0; i < c; ) {
+    for (rle = 0; i+rle < c && data[i] == data[i+rle]; rle++);
+    if (rle > (i != j ? (v ? 4 : 6) : 0) +
+             ((v || (i != j)) ? 4+dg(rle)+dg(data[i])
+                              : 6+dg(x+i)+dg(y)+dg(rle)+dg(data[i]))) {
+      if (i != j) {
+       if (v)
+         printf("\e[%s-",i2s(b1,i-j));
+       else
+         printf("\e[%s;%s;%s-",i2s(b1,x+j),i2s(b2,y),i2s(b3,i-j));
+       packpixel(data+j,i-j); }
+      if (v++ || (i != j))
+       printf("\e[%s;%s+",i2s(b1,rle),i2s(b2,data[i]));
+      else
+       printf("\e[%s;%s;%s;%s+",i2s(b1,x+i),i2s(b2,y),
+              i2s(b3,rle),i2s(b4,data[i]));
+      j = i += rle; }
+    else
+      i++; }
+  if (j != c) {
+    if (v)
+      printf("\e[%s-",i2s(b1,c-j));
+    else
+      printf("\e[%s;%s;%s-",i2s(b1,x+j),i2s(b2,y),i2s(b3,c-j));
+    packpixel(data+j,c-j); }
+  return;
+}
+
+int main(int argc,char *argv[])
+{
+  extern int optind;
+  extern char *optarg;
+  FILE *infile = NULL;
+  int  ch,i,j,dist,idx;
+  int  format,width,height,depth;
+  int  bg = 0,bgred = 0,bggreen = 0,bgblue = 0;
+  int  xoffset = 0,yoffset = 0;
+  int  w,h,r,g,b,c;
+  struct trans *tp;
+  char *buf;
+  
+  while ((i = getopt(argc,argv,"b:t:x:y:")) >= 0) switch(i) {
+  case 'b':
+    bg++;
+    for (i = bgred = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        bgred = 10*bgred + optarg[i++] - '0');
+    if (optarg[i++] != '/')
+      goto usage;
+    for (bggreen = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        bggreen = 10*bggreen + optarg[i++] - '0');
+    if (optarg[i++] != '/')
+      goto usage;
+    for (bgblue = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        bgblue = 10*bgblue + optarg[i++] - '0');
+    if (optarg[i])
+    goto usage;
+    break;
+  case 't':
+    if ((tp = malloc(sizeof(struct trans))) == NULL)
+      goto usage;
+    for (i = tp->r = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        tp->r = 10*tp->r + optarg[i++] - '0');
+    if (optarg[i++] != '/')
+      goto usage;
+    for (tp->g = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        tp->g = 10*tp->g + optarg[i++] - '0');
+    if (optarg[i++] != '/')
+      goto usage;
+    for (tp->b = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        tp->b = 10*tp->b + optarg[i++] - '0');
+    if (optarg[i++] != ':')
+      goto usage;
+    if (optarg[i] == '-') {
+      j = -1; i++; }
+    else j = 1;
+    for (tp->idx = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        tp->idx = 10*tp->idx + optarg[i++] - '0');
+    tp->idx *= j;
+    if (tp->idx < -1 || tp->idx >= 8)
+      goto usage;
+    if (optarg[i]) 
+      goto usage;
+    tp->next = trans;
+    trans    = tp;
+    break;
+  case 'x':
+    for (i = xoffset = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        xoffset = 10*xoffset + optarg[i++] - '0');
+    if (optarg[i])
+      goto usage;
+    break;
+  case 'y':
+    for (i = yoffset = 0; optarg[i] >= '0' && optarg[i] <= '9';
+        yoffset = 10*yoffset + optarg[i++] - '0');
+    if (optarg[i])
+      goto usage;
+    break;
+  default:
+  usage:
+    fprintf(stderr,"Usage: %s [-b r/g/b] [-t r/g/b:idx] "
+           "[-x offset] [-y offset] [ppmfile]\n",argv[0]);
+    exit(1); }
+  if (argc-optind == 0)
+    infile = stdin;
+  else if (argc-optind == 1)
+    infile = fopen(argv[optind],"r");
+  if (!infile)
+    goto usage;
+  if ((ch = skipcomment(infile)) != 'P' ||
+      ((format = getc(infile)) != '3' && format != '6') ||
+      ((ch = getc(infile)) != '\n' && ch != '\r' && getc(infile) != '\n'))
+    goto usage;
+  for (width = 0; (ch = skipcomment(infile)) >= '0' && ch <= '9';
+       width = 10*width + ch - '0');
+  while (ch == ' ') ch = getc(infile);
+  for (height = 0; ch >= '0' && ch <= '9'; ch = getc(infile))
+    height = 10*height + ch - '0'; 
+  if (ch != '\n' && ch != '\r' && getc(infile) != '\n')
+    goto usage;
+  for (depth = 0; (ch = skipcomment(infile)) >= '0' && ch <= '9';
+       depth = 10*depth + ch - '0');
+  if (ch != '\n' && ch != '\r' && getc(infile) != '\n')
+    goto usage;
+  if (!width || !height || !depth /* || depth > 255 */)
+    goto usage;
+  if ((buf = malloc(width)) == NULL)
+    goto usage;
+  for (h = 0; h < height; h++) {
+    for (w = c = 0; w < width; w++) {
+      r = readentry(infile,format,depth);
+      g = readentry(infile,format,depth);
+      b = readentry(infile,format,depth);
+      idx = 255;
+      if (bg && bgred == r &&
+         bggreen == g && bgblue == b)
+       idx = -1;
+      else for (tp = trans; tp; tp = tp->next)
+       if (tp->r == r && tp->g == g && tp->b == b) {
+         idx = tp->idx;
+         break; }
+      if (idx == 255)
+       for (idx = -1, dist = 3*255*255, i = 8; i--;)
+         if ((j = (r-palette[i][0])*(r-palette[i][0]) +
+                  (g-palette[i][1])*(g-palette[i][1]) +
+                  (b-palette[i][2])*(b-palette[i][2])) < dist) {
+           dist = j; idx = i; }
+      if (idx >= 0)
+       buf[c++] = idx;
+      else if (c) {
+       flushdata(w-c+xoffset,h+yoffset,c,buf);
+       c = 0; } }
+    if (c)
+      flushdata(w-c+xoffset,h+yoffset,c,buf); }
+  exit(0);
+}
diff --git a/contrib/ppmtoansi/ppmtoansi.man b/contrib/ppmtoansi/ppmtoansi.man
new file mode 100644 (file)
index 0000000..b19f979
--- /dev/null
@@ -0,0 +1,120 @@
+.TH PPMTOANSI 1 "January 12, 1997"
+.SH NAME
+ppmtoansi \- Graphics Conversion Program For Extended ANSI Escape Codes
+.SH SYNOPSIS
+.B ppmtoansi
+[
+.SM \-b
+r/g/b ] [
+.SM \-t
+r/g/b:idx] [
+.SM \-x
+<xoffset> ] [
+.SM \-y
+<yoffset> ] [
+<filename> ]
+.SH DESCRIPTION
+.I ppmtoansi
+converts input files in
+.IR ppm (5)
+format to escape sequences that are understood by
+.IR etherboot .
+This allows for displaying icons and logos on the BOOT-Prom's splash
+screen.
+.PP
+If no input file is specified, data is read from
+.IR standard
+.IR input .
+All output is send to 
+.IR standard
+.IR output ,
+error messages go to
+.IR standard
+.IR error .
+.I ppmtoansi
+tries to do some compression and minimizes the output filesize.
+.SH OPTIONS
+.TP
+.B \-b
+Specifies the
+.IR red ,
+.IR green , and
+.IR blue
+intensities for the background color. This information is
+used for providing a shape mask. All values are in the range from 0 to
+255.
+.TP
+.B \-t
+Allows for explicitly providing a translation between color values and
+color indices. The indices are in the range 0 to 7 and conform to the
+standard
+.IR ANSI
+.IR colorcodes .
+.RS
+.PP
+0 black       4 blue
+.PP
+1 red         5 magenta
+.PP
+2 green       6 cyan
+.PP
+3 yellow      7 white
+.PP
+If no translations apply,
+.IR ppmtoansi
+will automatically select the color that is closest.
+.RE
+.TP
+.B \-x
+Specify an X offset relative to the current text cursor position.
+.TP
+.B \-y
+Specify an Y offset relative to the current text cursor position.
+.SH FILE FORMAT
+.IR ppmtoansi
+uses these extensions to the standard
+.B ANSI escape
+.BR codes .
+.TP
+.B <esc>[a;b;c;d+<data>
+Draw pixel data.  Use one byte per pixel.  Colors are encoded as shown
+above.  In text mode, graphics is approximated by outputting suitable
+characters.  Parameters differ depending on the number of parameters
+passed:
+.RS
+.TP
+.B cnt
+.IR cnt
+data bytes follow. They will be drawn to the right of the last
+graphics position.
+.TP
+.B rle;col
+The next
+.IR rle
+pixels have the value
+.IR col .
+They will be drawn to the right of the last graphics position. No data
+bytes follow.
+.TP
+.B x;y;cnt
+.IR cnt
+data bytes follow. They will be drawn relative to the top left corner
+of the text cursor with an offset of
+.RI ( x / y ).
+.TP
+.B x;y;rle;col
+the next
+.IR rle
+pixels have the value
+.IR col .
+They will be drawn relative to the top left corner of the text cursor
+with an offset of
+.RI ( x / y ).
+No data bytes follow.
+.RE
+.TP
+.B <esc>[a;b;c;d\-<data>
+same as above, but pack pixels into three bits. The first pixel is
+stored in the three most significant bits of the first data byte.
+.SH "SEE ALSO"
+ppm(5), mknbi-linux(8), mknbi-dos(8).
diff --git a/contrib/rom-scan/Makefile b/contrib/rom-scan/Makefile
new file mode 100644 (file)
index 0000000..637404a
--- /dev/null
@@ -0,0 +1,64 @@
+CPPFLAGS    = 
+LDLIBS      = 
+CFLAGS      = -pipe -g -O2 -Wall
+LDFLAGS     = -pipe
+CC          = gcc
+LD          = gcc
+# Some "black" magic to determine optimal compiler flags for target
+# architecture
+TARGET_ARCH:= $(shell if [ \! -r .compile-options ] ; then ( \
+                cpu=`grep cpu /proc/cpuinfo 2>&1 |head -1| \
+                     cut -d : -f 2-| sed -e 's/ //g'`; \
+                if [ x"$$cpu" = x"" ] ; then \
+                  echo -fno-strength-reduce; \
+                else if [ "$$cpu" = "386" ] ; then \
+                  echo -m386 -fno-strength-reduce; \
+                else if [ "$$cpu" = "486" ] ; then \
+                  echo -m486 -fno-strength-reduce; \
+                else if [ "$$cpu" = "Alpha" ] ; then \
+                  echo -fno-strength-reduce; \
+                else echo main\(\)\{\} >.compile-options.c; \
+                  if gcc -mpentium -o .compile-options.o -c \
+                         .compile-options.c &>/dev/null; then \
+                     echo -mpentium -fstrength-reduce; \
+                 else if gcc -m486 -malign-functions=2 -malign-jumps=2 \
+                             -malign-loops=2 -o .compile-options.o -c \
+                             .compile-options.c &>/dev/null; then \
+                  echo -n -m486 -malign-functions=2 -malign-jumps=2; \
+                  echo ' '-malign-loops=2 -fno-strength-reduce; \
+                else echo -m486; \
+              fi;fi;fi;fi;fi;fi) > .compile-options; \
+              rm -f .compile-options.c .compile-options.o; \
+              fi; cat .compile-options)
+ASFLAGS     = $(TARGET_ARCH)
+
+OBJS        = rom-scan.o
+
+##############################################################################
+
+ifeq (.depend,$(wildcard .depend))
+all: rom-scan
+include .depend
+else
+all: depend
+       @$(MAKE) all
+endif
+
+##############################################################################
+
+rom-scan: $(OBJS)
+
+##############################################################################
+
+clean:
+       $(RM) *~ *.o *.dvi *.log *.aux *yacc.tab.[ch] *yacc.output *lex.[co] \
+              *.dat .depend .tmp_depend .compile-options*
+       strip rom-scan >&/dev/null || true
+
+##############################################################################
+
+depend:
+       for i in *.c;do $(CPP) $(CPPFLAGS) -MM $$i;done >.tmp_depend
+       mv .tmp_depend .depend
+
+
diff --git a/contrib/rom-scan/rom-scan.c b/contrib/rom-scan/rom-scan.c
new file mode 100644 (file)
index 0000000..c5e4829
--- /dev/null
@@ -0,0 +1,115 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifndef        __TURBOC__
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#ifdef __TURBOC__
+#define        HUGE    huge
+#else
+#define        HUGE
+#endif
+
+#define ROMSTART     0xC8000
+#define ROMEND       0xE8000
+#define ROMINCREMENT 0x00800
+#define ROMMASK      0x03FFF
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)(long long)-1)
+#endif
+
+typedef struct Images {
+  struct Images *next;
+  long           start;
+  long           size;
+} Images;
+
+static void rom_scan(const unsigned char HUGE *rom,long offset,long len)
+{
+  static Images *images = NULL;
+  Images *ptr;
+/* The assignments to dummy are to overcome a bug in TurboC */
+  long dummy, size;
+  int chksum;
+  long i;
+  
+  if (rom[offset] != 0x55 || rom[dummy = offset+1] != 0xAA)
+    return;
+  size = (long)rom[dummy = offset+2]*512L;
+  printf("Found ROM header at %04lX:0000; "
+        "announces %ldk image (27C%02d EPROM)\n",
+        offset/16,(size+512)/1024,
+        size <=  1024 ?   8 :
+        size <=  2048 ?  16 :
+        size <=  4096 ?  32 :
+        size <=  8192 ?  64 :
+        size <= 16384 ? 128 :
+        size <= 32768 ? 256 :
+        size <= 65536 ? 512 : 11);
+  if (offset & ROMMASK)
+    printf("  This is a unusual position; not all BIOSs might find it.\n"
+          "   Try to move to a 16kB boundary.\n");
+  if (size > len) {
+    printf("  This image extends beyond %04X:0000. "
+          "It clashes with the system BIOS\n",
+          ROMEND/16);
+    size = len; }
+  for (chksum=0, i = size; i--; chksum += rom[dummy = offset+i]);
+  if (chksum % 256)
+    printf("  Checksum does not match. This image is not active\n");
+  ptr        = malloc(sizeof(Images));
+  ptr->next  = images;
+  ptr->start = offset;
+  ptr->size  = size;
+  images     = ptr;
+  for (ptr = ptr->next; ptr != NULL; ptr = ptr->next) {
+    for (i = 0; i < size && i < ptr->size; i++)
+      if (rom[dummy = ptr->start+i] != rom[dummy = offset+i])
+       break;
+    if (i > 32) {
+      printf("   Image is identical with image at %04lX:0000 "
+            "for the first %ld bytes\n",
+            ptr->start/16,i);
+      if (i >= 1024)
+       if (i == size)
+         printf("    this means that you misconfigured the EPROM size!\n");
+       else
+         printf("    this could suggest that you misconfigured the "
+                "EPROM size\n");
+      else
+       printf("    this is probably harmless. Just ignore it...\n"); } }
+  return;
+}
+
+int main(void)
+{
+  long  i;
+  unsigned char HUGE *rom;
+
+#ifndef        __TURBOC__
+  int  fh;
+  if ((fh = open("/dev/kmem",O_RDONLY|O_SYNC)) < 0) {
+    fprintf(stderr,"Could not open \"/dev/kmem\": %s\n",0 );//strerror(errno));
+    return(1); }
+  if ((rom = mmap(NULL,ROMEND-ROMSTART,PROT_READ,MAP_SHARED,fh,
+                 ROMSTART)) == MAP_FAILED) {
+    fprintf(stderr,"Could not mmap \"/dev/kmem\": %s\n",0); //strerror(errno));
+    close(fh);
+    return(1); }
+  close(fh);
+#endif
+  for (i = ROMEND; (i -= ROMINCREMENT) >= ROMSTART; )
+#ifdef __TURBOC__
+    rom_scan(0,i,ROMEND-i);
+#else
+    rom_scan(rom-ROMSTART,i,ROMEND-i);
+  munmap(rom,ROMEND-ROMSTART);
+#endif
+  return(0);
+}
diff --git a/contrib/romid/pktdrv.bat b/contrib/romid/pktdrv.bat
new file mode 100644 (file)
index 0000000..058fd4e
--- /dev/null
@@ -0,0 +1,84 @@
+@echo off\r
+if (%PKTDRV%)==(P) goto end\r
+A:\PKT\ROMID\r
+if (%ROMID%)==() goto select\r
+if (%ROMID%)==(NE) goto NE\r
+if (%ROMID%)==(WD) goto WD\r
+if (%ROMID%)==(3C509) goto 3C509\r
+if (%ROMID%)==(3C905B) goto 3C905B\r
+if (%ROMID%)==(EEPRO100) goto EEPRO100\r
+if (%PCIID%)==(10EC:8029) goto RTL8029\r
+if (%PCIID%)==(10EC:8139) goto RTL8139\r
+if (%PCIID%)==(11AD:0002) goto LITEON\r
+if (%PCIID%)==(1011:0009) goto DEC\r
+echo No Driver installed!\r
+goto end\r
+:select\r
+cls\r
+echo *** Select your network card.... ***\r
+echo.\r
+echo  1 -- Intel EtherExpress 100B PCI Adapter\r
+echo  2 -- 3Com 3C90X Etherlink III PCI Adapter\r
+echo  3 -- 3Com 3C5X9 Etherlink III ISA Adapter\r
+echo  4 -- NE2000 Novell ISA Adapter\r
+echo  5 -- Realtek 8029 PCI Adapter\r
+echo  6 -- Realtek 8139 PCI Adapter\r
+echo  7 -- SMC EliteUltra 8216 ISA Adapter\r
+echo  8 -- DEC21x4 Busmaster PCI Adapter\r
+echo  9 -- LiteOn PNIC Busmaster PCI Adapter\r
+echo.\r
+echo *** **************************** ***\r
+echo.\r
+choice /c123456789 /n Select:\r
+if errorlevel 9 goto LITEON\r
+if errorlevel 8 goto DEC\r
+if errorlevel 7 goto WD\r
+if errorlevel 6 goto RTL8139\r
+if errorlevel 5 goto RTL8029\r
+if errorlevel 4 goto NE\r
+if errorlevel 3 goto 3C509\r
+if errorlevel 2 goto 3C905B\r
+if errorlevel 1 goto EEPRO100\r
+goto end\r
+\r
+:EEPRO100\r
+A:\PKT\E100BPKT 0x60\r
+if errorlevel 0 goto ok\r
+goto end\r
+:NE\r
+A:\PKT\NE2000 0x60 11 0x0300\r
+if errorlevel 0 goto ok\r
+goto end\r
+:RTL8029\r
+A:\PKT\PCIPKT 0x60\r
+if errorlevel 0 goto ok\r
+goto end\r
+:RTL8139\r
+A:\PKT\RTSPKT 0x60\r
+if ERRORLEVEL 0 goto OK\r
+goto end\r
+:WD\r
+A:\PKT\SMC_WD 0x60\r
+if errorlevel 0 goto ok\r
+goto end\r
+:3C509\r
+A:\PKT\3C5X9PD 0x60\r
+if errorlevel 0 goto ok\r
+goto end\r
+:3C905B\r
+A:\PKT\3C90XPD 0x60\r
+if errorlevel 0 goto ok\r
+goto end\r
+:LITEON\r
+A:\PKT\FEPD 0x60\r
+if ERRORLEVEL 0 goto ok\r
+goto end\r
+:DEC\r
+A:\PKT\ETHPCI 0x60\r
+if ERRORLEVEL 0 goto ok\r
+goto end\r
+\r
+:ok\r
+SET PKTDRV=P\r
+:end\r
+\r
diff --git a/contrib/romid/readme b/contrib/romid/readme
new file mode 100644 (file)
index 0000000..6c6c500
--- /dev/null
@@ -0,0 +1,8 @@
+This simple utility has currently no correct error checking.\r
+If your environment space couldn't hold up the variables, the\r
+program breaks without an error message, so be sure to add a \r
+line similar to the following to your config.sys:\r
+SHELL=A:\COMMAND.COM A:\ /P/E:2048\r
+\r
+The batch is a sample which shows how it could be used for those\r
+one not familar with batch files and environment variables.
\ No newline at end of file
diff --git a/contrib/romid/romid.c b/contrib/romid/romid.c
new file mode 100644 (file)
index 0000000..f6049bf
--- /dev/null
@@ -0,0 +1,124 @@
+/* This little program is my try to provide information about the
+   EtherBoot rom via environment variables to a batch file. This
+   could be done better, I think, but it works...
+   The program compiles with Borland C 3.1; other versions not tested.
+   The C code for setting the environment variables I got from an
+   archive, it was written by Richard Marks <rmarks@KSP.unisys.COM>.
+   ROMID is written by Guenter Knauf <eflash@gmx.net>
+*/
+#define VERSION "0.6"
+#define VDATE "2003-08-24"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ROMSTART     0xC8000
+#define ROMEND       0xE8000
+#define ROMINCREMENT 0x00800
+#define ROMMASK      0x03FFF
+
+int verbose = 0;
+
+int settheenv(char *symbol, char *val);
+
+static int rom_scan(const unsigned char huge *rom,long offset,long len) {
+  long size,i,j;
+  char symbol[16];
+  char val[64];
+  char romid[64];
+  char *rptr;
+
+  if (rom[offset] != 0x55 || rom[offset+1] != 0xAA)
+    return 0;
+
+  size = (long)rom[offset+2]*512L;
+  if (verbose) {
+    printf("Found ROM header at %04lX:0000; announces %ldk image\n", offset/16,(size+512)/1024);
+    if (offset & ROMMASK)
+      printf("  This is a unusual position; not all BIOSs might find it.\n"
+                        "   Try to move to a 16kB boundary.\n");
+    if (size > len) {
+      printf("  This image extends beyond %04X:0000. It clashes with the system BIOS\n", ROMEND/16);
+      size = len;
+    }
+  }
+
+  for (i=0; i<64; i++) {
+    if (rom[offset+size-3-i] == 0xff)
+      break;
+  }
+  if (20<i && i<63) {
+    i--;
+    for (j=0; j<i; j++)
+      val[j] = rom[offset+size-3-i+j];
+    val[i] = 0;
+  } else
+    return 0;
+
+  if (strstr(val, "therboot") == NULL)
+    return 0;
+
+  if (verbose)
+    printf("ROM Signature '%s'\n", val);
+  if ((rptr = strstr(val, "rom")) != NULL) {
+    for (i=1; i<4; i++) {
+      rptr--;
+      if (rptr[0] == 0x2E)
+        break;
+    }
+    i = 0;
+    while (!(rptr[0] == 0x20 || rptr < val)) {
+      i++;
+      rptr--;
+    }
+    rptr++;
+    i--;
+    strncpy(romid, rptr, i);
+    romid[i] = 0;
+    if (verbose)
+      printf("ROM Driver ID '%s'\n", romid);
+    strcpy(symbol, "ROMID");
+    if (settheenv(symbol, romid))
+      printf("Error setting evironment var %s with value %s\n", symbol, romid);
+  } else {
+    if (verbose)
+      printf("Couldnt find driver name!\n");
+    return 0;
+  }
+  if (rom[offset+0x1C] == 'P' && rom[offset+0x1D] == 'C' && rom[offset+0x1E] == 'I') {
+    sprintf(val, "%02X%02X:%02X%02X", rom[offset+0x21], rom[offset+0x20],
+                        rom[offset+0x23], rom[offset+0x22]);
+    if (verbose)
+      printf("ROM Vendor ID '%s'\n", val);
+    strcpy(symbol, "PCIID");
+    if (settheenv(symbol, val))
+      printf("Error setting evironment var %s with value %s\n", symbol, val);
+  }
+  return 1;
+}
+
+/* **************** main stuff **************** */
+int main (int argc, char *argv[]) {
+  long  i;
+
+  printf("\nROM-ID for Etherboot v%s (c) G. Knauf %s\n", VERSION, VDATE);
+  if (argc > 1) {
+    /* parse input parameters */
+    for (argc--, argv++; *argv; argc--, argv++) {
+      if ((strnicmp (*argv, "-", 1) == 0) || (strnicmp (*argv, "/", 1) == 0)) {
+        if ((strnicmp (*argv, "-V", 2) == 0) || (strnicmp (*argv, "/V", 2) == 0)) {
+          verbose = 1;
+        } else {
+          printf("Usage: %s [-v]\n");
+        }
+      }
+    }
+  }
+  for (i = ROMEND; (i -= ROMINCREMENT) >= ROMSTART;)
+    if (rom_scan(0,i,ROMEND-i))
+      break;
+
+  return 0;
+}
diff --git a/contrib/romid/setenvs.c b/contrib/romid/setenvs.c
new file mode 100644 (file)
index 0000000..e18e399
--- /dev/null
@@ -0,0 +1,200 @@
+/* subroutine to put a value string into an environment symbol.
+   Uses the controling command.com environment, not the programs.
+   This means that the env variable is set so other routines in
+   a .BAT file may use it.
+
+   call:  settheenv (char * symbol, char * val);
+   symbol is an asciiz string containing the env variable name,
+   val    is an asciiz string containing the value to assign to this vbl.
+
+   returns: 0 = OK,
+            1 = failure.
+   failure is not unlikely.  The env block may be full.  Or on some
+   systems the env block might not be found
+
+   SETENVS.C was written by Richard Marks <rmarks@KSP.unisys.COM>.
+*/
+
+
+#include <stdio.h>
+#include <dos.h>
+#include <string.h>
+#include <stdlib.h>
+
+typedef struct {
+    char fill1[0x0A];
+    int *prev_term_handler;
+    int *prev_ctrl_c;
+    int *prev_crit_error;
+    char fill2[0x16];
+    int  envir_seg;
+} psp;
+
+typedef struct {
+    char  type;
+    int   psp_segment;
+    int   num_segments;
+    char  fill[11];
+    char  arena_data;
+} arena;
+
+
+#define NORMAL_ATYPE 0x4D
+#define LAST_ATYPE   0x5A
+
+
+static arena * get_next_arena (arena * ap) {
+    return( MK_FP( FP_SEG(ap)+1+ap->num_segments, 0) );
+}
+
+/* returns 0 if passed pointer is to an arena, else returns 1 */
+static int is_valid_arena (arena * ap) {
+    arena * ap1;
+    if (ap->type == NORMAL_ATYPE  &&
+          (ap1=get_next_arena(ap))->type == NORMAL_ATYPE  &&
+          ( (ap1=get_next_arena(ap1))->type == NORMAL_ATYPE  ||
+          ap1->type == LAST_ATYPE) )
+            return(0);
+    return (1);
+}
+
+
+static arena * get_first_arena () {
+/* return pointer to the first arena.
+ * scan memory for a 0x4D on a segment start,
+ * see if this points to another two levels of arena
+ */
+    arena * ap, * ap1;
+    int * temp;
+    int segment;
+
+    for (segment=0; segment<_CS;  segment++) {
+        ap = MK_FP(segment, 0);
+        if ( is_valid_arena (ap) == 0)  return (ap);
+    }
+    return(NULL);
+} /* end get_first_arena */
+
+
+static int is_valid_env (char * ad, int num_segs) {
+    char * base_ad;
+    base_ad = ad;
+    while ( (*ad) && (((ad-base_ad)>>4) < num_segs) ) {
+        if (strnicmp(ad, "COMSPEC=", 8)==0)  return(0);
+        ad += strlen(ad) + 1;
+    }
+    return (1);
+}
+
+
+static arena * get_arena_of_environment () {
+/* to get the arena of first environment block:
+   First get segment of COMMAND.COM from segment of previous critical err code.
+   Then scan all the arenas for an environment block with a matching PSP
+   segment */
+
+arena * ap;
+psp   * pspp, * pspc;
+unsigned int i, ccseg;
+
+/* set pspp to psp of this program */
+pspp = MK_FP(_psp,0);
+
+#ifdef DEBUG
+printf("prog psp=%p\n",pspp);
+#endif
+
+/* set pspc to psp of COMMAND.COM, back up a bit to get it if needed */
+ccseg = FP_SEG (pspp->prev_crit_error);
+if ( (i=ccseg-32) < 60)  i=60;
+
+while (ccseg>i) {
+    pspc = MK_FP (ccseg, 0);
+    if ( is_valid_arena((arena *) pspc) == 0)  goto L1;
+    ccseg--;
+}
+return (NULL);
+
+L1: pspc = MK_FP (++ccseg, 0);
+#ifdef DEBUG
+printf("comm.com=%p\n",pspc);
+#endif
+
+/* first see if env seg in command.com points to valid env block
+   if env seg is in a valid arena, then arena must point to this command.com
+   else assume env block is fabricated like for 4DOS, use 128 bytes */
+
+ap = MK_FP (pspc->envir_seg-1, 0);
+i  = ap->num_segments;
+
+if (is_valid_arena (ap) == 0) {
+    if (ap->psp_segment != FP_SEG(pspc))  goto L2;
+} else {
+    i = 9;
+}
+
+if ( is_valid_env (&ap->arena_data, i) == 0 )
+    return (ap);
+
+/* command.com did not so point, search thru all env blocks */
+
+L2:
+if ( (ap=get_first_arena()) != NULL ) {
+    while (ap->type != LAST_ATYPE) {
+#ifdef DEBUG
+        printf("%p\n",ap);
+#endif
+        if (ap->psp_segment == FP_SEG(pspc) &&
+            is_valid_env (&ap->arena_data, ap->num_segments)==0 )
+            return (ap);
+
+        ap = get_next_arena(ap);
+    }
+} return(NULL);
+}  /* end get_arena_of_environment */
+
+/*****************************************************************************/
+
+int settheenv(char * symbol, char * val) {
+int total_size,
+    needed_size=0,
+    strlength;
+char * sp, *op, *envir;
+char symb_len=strlen(symbol);
+char found=0;
+arena * ap;
+
+strupr(symbol);
+
+/* first, can COMMAND.COM's envir block be found ? */
+if ( (ap=get_arena_of_environment()) == NULL)
+    return(1);
+
+/* search to end of the envir block, get sizes */
+total_size = 16 * ap->num_segments;
+envir = &ap->arena_data;
+op=sp=envir;
+while (*sp) {
+    strlength = strlen(sp)+1;
+    if ( *(sp+symb_len)=='='  &&
+         strnicmp(sp,symbol,symb_len)==0 )
+        found=1;
+    else {
+        needed_size += strlength;
+        if (found) strcpy(op,sp);
+        op = &op[strlength];
+    }
+    sp += strlength;
+}
+*op=0;
+if (strlen(val) > 0) {
+    needed_size += 3 + strlen(symbol) + strlen(val);
+    if (needed_size > total_size)
+        return(1);  /* could mess with environment expansion here */
+
+    strcpy(op, symbol); strcat(op, "="); strcat(op, val);
+    op += strlen(op)+1;
+    *op = 0;
+}
+return(0);
+} /* end setheenv subroutine */
diff --git a/contrib/smc9462tx-flash/Makefile b/contrib/smc9462tx-flash/Makefile
new file mode 100644 (file)
index 0000000..dc5b3ff
--- /dev/null
@@ -0,0 +1,20 @@
+GCC = gcc
+KERNELDIR = ../linux-2.4.20
+KERNELSTYLE=-D__KERNEL__ -DCPU=__i386__ -DMODULE
+INCLUDE_DIR=-I$(KERNELDIR)/include -I../include -I$(ROOTDIR)/include
+
+all: dp83820flash.o dp83820_write
+
+CFLAGS+=-O2 -Wall -fomit-frame-pointer -fno-strength-reduce
+CFLAGS+=$(KERNELSTYLE) $(CDEBUG) $(INCLUDE_DIR)
+
+install:
+
+dp83820flash.o: dp83820flash.c
+       $(GCC) dp83820flash.c -o dp83820flash.o -c $(CFLAGS)
+
+dp83820_write: dp83820_write.c
+       $(GCC) $< -o $@ -Wall -O2
+
+clean: 
+       $(RM) *.o dp83820_write
diff --git a/contrib/smc9462tx-flash/README b/contrib/smc9462tx-flash/README
new file mode 100644 (file)
index 0000000..53501cb
--- /dev/null
@@ -0,0 +1,24 @@
+This code was written by Dave Ashley for NXTV, Inc. It is released under
+the terms of the GPL. The purpose is to let you write to the bootrom of
+the SMC9462TX card. The assumption is that you've stuck an AT29C512 in the
+socket. Note that the board has pins D5 + D6 reversed on the socket. Also
+the socket only supplies 3.3V to the rom. Good luck trying to locate a
+DIP programmable flash device that operates at 3.3V. What I do is to bend
+pin 32 back and solder a wire directly from the 5V side of the 3.3V regulator
+over to it. The dp83820's bootrom interface pins are all 5V logic tolerant.
+However mod your board at your own risk, no warranty or guarantees are implied
+or given!!! If you don't wire the 5V to the AT29C512, you can still read
+the rom contents (it operates ok at 3.3V evidently) but you can't write to it
+because the AT29C512 has a safety protection, it disables writes if the
+power supply voltage drops below 3.8V.
+
+See the comments at the top of the 2 C files for more information.
+
+The Makefile needs to be hacked to build for your system. If you can't
+figure it out you shouldn't be messing with this stuff anyway.
+
+-Dave Ashley
+Email address intentionally left out to avoid spam.
+http://www.xdr.com/dash
+
+Mon Mar  8 13:55:34 PST 2004
diff --git a/contrib/smc9462tx-flash/dp83820_write.c b/contrib/smc9462tx-flash/dp83820_write.c
new file mode 100644 (file)
index 0000000..ab6e566
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+   DP83820 flash utility written by Dave Ashley for NXTV, Inc.
+   Copyright (C) 2004 by NXTV, Inc.
+   Written 20040219 by Dave Ashley.
+
+   Currently only supports the AT29C512
+
+   This code is released under the terms of the GPL. No warranty.
+
+
+   THEORY:
+   This code uses the /proc/dp83820 file which is created by the
+   dp83820flash.o module. That file allows single byte reads + writes
+   to the bootrom.
+
+*/
+
+#include <unistd.h>
+#include <sys/io.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+
+
+// SMC9462TX card has D5 + D6 on the bootrom socket reversed
+int fixb(int val)
+{
+       return (val&~0x60) | ((val&0x20)<<1) | ((val&0x40)>>1);
+}
+int openit(void)
+{
+int fd;
+       fd=open("/proc/dp83820",O_RDWR);
+       if(fd<0)
+       {
+               printf("Failed to open the /proc/dp83820 file to access the flashrom.\n");
+               printf("Make sure you've done:\n");
+               printf("  modprobe dp83820flash\n");
+               exit(-1);
+       }
+       return fd;
+}
+void set(int addr, unsigned char val)
+{
+unsigned char msg[3];
+int fd;
+       fd=openit();
+       msg[0]=addr;
+       msg[1]=addr>>8;
+       msg[2]=val;
+       write(fd,msg,3);
+       close(fd);
+}
+int get(int addr)
+{
+unsigned char msg[2];
+int fd;
+       fd=openit();
+       msg[0]=addr;
+       msg[1]=addr>>8;
+       write(fd,msg,2);
+       read(fd,msg,1);
+       close(fd);
+       return msg[0];
+}
+
+
+int getromsize(unsigned char *id)
+{
+       if(id[0]==0xbf && id[1]==0xb6) return 0x40000;
+       if(id[0]==0xc2 && id[1]==0xb0) return 0x40000;
+       if(id[0]==0x1f && id[1]==0x3d) return 0x10000;
+       return -1;
+}
+
+#define MAXROMSIZE 0x200000
+unsigned char *buffer;
+
+int loadfile(char *name)
+{
+int filefd;
+int filesize;
+       filefd=open(name,O_RDONLY);
+       if(filefd<0)
+       {
+               printf("Couldn't open file %s\n",name);
+               return -1;
+       }
+       filesize=read(filefd,buffer,MAXROMSIZE);
+       close(filefd);
+       if(filesize<0)
+       {
+               printf("Error trying to read from file %s\n",name);
+       }
+       return filesize;
+}
+
+void readbios(char *name,int len)
+{
+int filefd;
+int filesize=0;
+unsigned char block[256];
+int i,j;
+
+       filefd=open(name,O_WRONLY|O_TRUNC|O_CREAT,0644);
+       if(filefd<0)
+       {
+               printf("Couldn't create file %s for writing\n",name);
+               return;
+       }
+       for(i=j=0;i<len;++i)
+       {
+               block[j++]=get(i);
+               if(j<sizeof(block)) continue;
+               filesize+=write(filefd,block,j);
+               j=0;
+       }
+       close(filefd);
+       if(filesize!=len)
+       {
+               printf("Error during write of %s file\n",name);
+               return;
+       }
+       printf("BIOS contents saved to %s, $%x bytes\n",name,len);
+}
+
+int verifybios(char *name,int len, int print)
+{
+int filelen;
+int i;
+int same=0;
+
+       filelen=loadfile(name);
+       for(i=0;i<filelen;++i)
+               if(get(i)!=buffer[i]) break;
+       if(i<filelen)
+       {
+               if(print)
+                       printf("BIOS contents does not match file %s, from byte $%x\n",
+                               name,i);
+       } else
+       {
+               if(print)
+                       printf("BIOS contents match file %s for all of its $%x bytes\n",
+                               name,i);
+               same=1;
+       }
+       return same;
+}
+
+void writebios(char *name,int len,unsigned char *id)
+{
+int i;
+int p1,p2;
+int sectorsize=128;
+
+       if(len!=loadfile(name))
+       {
+               printf("File size does not match expected ROM size\n");
+               return;
+       }
+       if(0 && (id[0]!=0xbf || id[1]!=0xb6))
+       {
+               printf("Don't know how to write this kind of flash device\n");
+               return;
+       }
+
+       printf("Erasing device\n");
+       set(0x5555,fixb(0xaa));
+       set(0x2aaa,fixb(0x55));
+       set(0x5555,fixb(0x80));
+       set(0x5555,fixb(0xaa));
+       set(0x2aaa,fixb(0x55));
+       set(0x5555,fixb(0x10));
+
+       for(;;)
+       {
+               printf(".");fflush(stdout);
+               usleep(250000);
+               if(get(0)==get(0) && get(0)==get(0))
+                       break;
+       }
+       printf("BIOS erased\n");
+
+       printf("Writing to BIOS\n");
+       p1=-1;
+       for(i=0;i<len;++i)
+       {
+               p2=100*i/(len-1);
+               if(p2!=p1)
+               {
+                       printf("\r%d%%",p1=p2);
+                       fflush(stdout);
+               }
+               if(i%sectorsize==0)
+               {
+                       set(0x5555,fixb(0xaa));
+                       set(0x2aaa,fixb(0x55));
+                       set(0x5555,fixb(0xa0));
+               }
+               set(i,buffer[i]);
+               if(i%sectorsize==sectorsize-1)
+                       while(get(0)!=get(0) || get(0)!=get(0));
+       }
+       printf("\n");
+}
+
+void helptext(char *name)
+{
+       printf("USE: %s <options>\n",name);
+       printf("  -v <filename>  = verify bios rom contents with file\n");
+       printf("  -w <filename>  = write to bios rom contents from file\n");
+       printf("  -r <filename>  = read from bios rom contents to file\n");
+       printf("  -f             = force erase/write even if contents already match\n");
+       exit(0);
+}
+
+int main(int argc,char **argv)
+{
+int i;
+int vals;
+unsigned char id[4];
+char *filename=0;
+char action=0;
+int romsize;
+int force=0;
+int same;
+
+       vals=0;
+
+       if(argc<2) helptext(argv[0]);
+       for(i=1;i<argc;++i)
+       {
+               if(argv[i][0]!='-')
+                       helptext(argv[0]);
+               switch(argv[i][1])
+               {
+               case 'f':
+                       force=1;
+                       break;
+               case 'v':
+               case 'w':
+               case 'r':
+                       action=argv[i][1];
+                       if(i+1<argc)
+                               filename=argv[++i];
+                       else helptext(argv[0]);
+                       break;
+               default:
+                       helptext(argv[0]);
+               }
+               
+       }
+
+       buffer=malloc(MAXROMSIZE);
+       if(!buffer)
+       {
+               printf("No memory available!\n");
+               exit(-1);
+       }
+
+       set(0x5555,fixb(0xaa)); // get into flash ID mode
+       set(0x2aaa,fixb(0x55));
+       set(0x5555,fixb(0x90));
+
+       for(i=0;i<4;++i) id[i]=get(i);
+
+       set(0x5555,fixb(0xaa)); // get out of flash ID mode
+       set(0x2aaa,fixb(0x55));
+       set(0x5555,fixb(0xf0));
+       usleep(10000);
+
+       for(i=0;i<4;++i)
+               if(id[i]!=get(i)) break;
+       if(i==4)
+       {
+               printf("Could not read BIOS flashrom ID.\n");
+               goto biosdone;
+       }
+       printf("ID %02x %02x\n",id[0],id[1]);
+       romsize=getromsize(id);
+       if(romsize<0)
+       {
+               printf("Unknown rom type\n");
+               goto biosdone;
+       }
+       printf("romsize=$%x bytes\n",romsize);
+       if(action=='r')
+               readbios(filename,romsize);
+       if(action=='w')
+       {
+               if(!force)
+                       same=verifybios(filename,romsize,0);
+               else
+                       same=0;
+               if(!same)
+                       writebios(filename,romsize,id);
+       }
+       if(action=='v' || action=='w')
+               verifybios(filename,romsize,1);
+
+biosdone:
+
+       return 0;
+}
diff --git a/contrib/smc9462tx-flash/dp83820flash.c b/contrib/smc9462tx-flash/dp83820flash.c
new file mode 100644 (file)
index 0000000..661c429
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+   Kernel module for the dp83820 flash write utility. This code was written
+   by Dave Ashley for NXTV, Inc.
+   Copyright 2004 by NXTV, Inc.
+   Written 20040219 by Dave Ashley.
+
+   This code is released under the terms of the GPL. No warranty.
+
+   THEORY: The dp83820 bootrom interface is flawed in that you can't
+   read or write a single byte at a time, and this is required in order
+   to write to flash devices like the AT29C512. So the workaround is
+   to use the chips ability to map into memory the bootrom, then the cpu
+   can directly do byte accesses.
+
+   The problem is that a "feature" of the dp83820 is that when you map
+   in the bootrom, you conveniently lose access to the PCI registers.
+   So we need to do this in kernel space and wrap every access to the
+   bootrom within interrupt_disable/restore, in case a network interrupt
+   were to come in.
+
+   This kernel module is very simple, it just creates a proc file
+   /proc/dp83820
+   If you write 3 bytes to this file you are doing a write to the flashrom:
+
+Byte 1   2    3
+   ALOW AHIGH DATA
+
+   If you write 2 bytes to this file you are doing a read from the flashrom:
+Byte 1   2
+   ALOW AHIGH
+   Then the next read from the file will return a single byte of what
+   was at that location.
+
+   You only get one shot at accessing the proc file, you need to then
+   close/open if you want to do another access. This could probably be
+   cleaned up pretty easily so more accesses can be done without having
+   to close/open the file.     
+
+*/
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+
+
+#define PROCNAME "dp83820"
+
+struct pci_dev *mydev=0;
+unsigned long loc;
+unsigned char *addr=0;
+
+unsigned char lastread;
+
+
+int my_read_proc(char *buf, char **start,off_t offset,int count, int *eof,void *data)
+{
+int retval=0;
+
+       if(count>0)
+       {
+               buf[0]=lastread;
+               retval=1;
+       }
+
+       *eof=1;
+
+       return retval;
+}
+
+int my_write_proc(struct file *file, const char *buffer, unsigned long count,
+               void *data)
+{
+unsigned char *msg;
+
+unsigned long flags;
+
+       msg=(void *)buffer;
+       save_flags(flags);
+       cli();
+       pci_write_config_dword(mydev, 0x30, loc | 1);
+
+       switch(count)
+       {
+               case 2:
+                       lastread=addr[msg[0] | (msg[1]<<8)];
+                       break;
+               case 3:
+                       addr[msg[0] | (msg[1]<<8)] = msg[2];
+                       break;
+       }
+       pci_write_config_dword(mydev, 0x30, loc);
+       restore_flags(flags);
+       return count;
+}
+
+
+struct proc_dir_entry *de=0;
+
+int __init init_module(void)
+{
+int found=0;
+       mydev=0;
+       pci_for_each_dev(mydev)
+       {
+               if(mydev->vendor==0x100b && mydev->device==0x0022)
+               {
+                       found=1;
+                       break;
+               }
+       }
+       if(!found)
+       {
+               printk("Could not find DP83820 network device\n");
+               return ENODEV;
+       }
+
+       de=create_proc_entry(PROCNAME,0,0);
+       if(!de)
+               return -1;
+       de->data=0;
+       de->read_proc=my_read_proc;
+       de->write_proc=my_write_proc;
+
+       loc=mydev->resource[PCI_ROM_RESOURCE].start;
+       addr=ioremap_nocache(loc,0x10000);
+
+
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       if(de)
+       {
+               remove_proc_entry(PROCNAME,0);
+               de=0;
+       }
+       if(addr)
+       {
+               iounmap(addr);
+               addr=0;
+       }
+}
+
diff --git a/contrib/t2hproxy/README b/contrib/t2hproxy/README
new file mode 100644 (file)
index 0000000..ce5e1e9
--- /dev/null
@@ -0,0 +1,95 @@
+T2hproxy
+
+This is a TFTP to HTTP proxy. To the TFTP client it looks like a TFTP
+server. To the HTTP server it looks like a HTTP client. So you can store
+your boot files on the HTTP server. Or even create them with a CGI
+program. E.g. if you can get dhcpd to send a filename which has strings
+representing attributes of the client, as determined from the DHCP
+request, then you can get the CGI program to parse this and send the
+appropriate image, which might even be synthesised.
+
+There are two versions of the proxy, in Perl and in Java.
+
+1. The Perl version.
+
+This is the original quick Perl hack conceived in a moment of madness.
+:-) Perl is great for prototyping.
+
+To run it, you need Perl 5.8.0 or later and all the Perl modules listed
+at the top of the program installed. Edit and install the xinetd config
+file as /etc/xinetd.d/t2hproxy and restart xinetd. The prefix is the
+string that is prepended to all filenames to form the URL requested from
+the HTTP server. Remember you need the trailing / if the filenames don't
+start with /.
+
+This is only a proof-of concept. It has these drawbacks at the moment:
+
++ (I don't consider this a draback, but some may.) It's started from
+xinetd because xinetd handles all the socket listening, IP address
+checking, rate limiting, etc.
+
++ It has no cache. Use a proxy to do the caching (there's a --proxy
+option). This also takes care of fetching from outside a firewall.
+
++ It reads the entire HTTP content into memory before serving. Ideally
+it should stream it from the HTTP server to minimise memory usage. This
+is a serious drawback for booting lots of clients. Each instance of the
+server will consume an amount of memory equal to the size of image
+loaded.
+
++ If the HTTP server is at the end of a slow link there is a delay
+before the first data block is sent.  The client may timeout before
+then.  Another reason for streaming, as this allows the first block to
+be sent sooner.  A local cache primed with the images in advance may
+help. Using the blocksize option helps here because this causes the
+server to send the OACK to the client immediately before the data is
+fetched and this prevents it from starting up another connection.
+
++ The transfer size may not be obtainable from the HTTP headers in all
+cases, e.g. a CGI constructed image. This matters for clients that need
+the tsize extension, which is not supported at the moment.
+
+If I'm feeling masochistic I may write a Java version, which should take
+care of the multi-threading and streaming.
+
+2. The Java version
+
+The main problem with the Perl version is that it does not stream the
+HTTP input but sucks it all in at once. As mentioned, this causes a
+delay as well as requiring memory to hold the image. I could fix this by
+doing the polling on the HTTP socket myself instead of letting LWP do
+it, but that's for later. Java has streaming facilities as well as
+threading and is also somewhat portable.  So I decided to be masochistic
+and give it a go.  But boy is Java bureaucratic.
+
+You will need a Java 1.4 JRE, because I use the java.nio classes; and
+the commons-httpclient and commons-logging jars from the
+jakarta.apache.org project. As I understand it, there are several ways
+to get those jars on your classpath. One is to put it in the directory
+where your java extensions jars are kept, normally
+$JAVA_HOME/jre/lib/ext. But it may not be writable to you. Another is to
+set your $CLASSPATH variable to have those jars in the path. A third is
+to use the -cp option of the java interpreter, see the shell script
+runT2hproxy for details.
+
+All the source is in one Java file. build.xml is a "Makefile" for ant to
+compile and jar it. You should then edit runT2proxy.sh as required, then
+start it. As with the Perl version, the prefix is what's prepended to
+the filenames requested by the TFTP client, and the proxy is the
+host:port string for the proxy if you are using one. On *ix you will
+need root permission to listen on ports below 1024 (TFTP is at 69 UDP by
+default).
+
+Currently it logs to stderr, but you can change this by downloading and
+installing the log4j jar from jakarta.apache.org and instructing
+commons-logging to use that, with a command line property setting and a
+property file.  Destinations could be syslog, or a file, or an event
+logger, or...; it's supposedly very flexible.
+
+3. Licensing
+
+All this code is GPLed. For details read the file COPYING found in the
+Etherboot top directory since it currently bundled with Etherboot. I
+don't see the point of including COPYING in every directory.
+
+Ken Yap, October 2003
diff --git a/contrib/t2hproxy/T2hproxy.java b/contrib/t2hproxy/T2hproxy.java
new file mode 100644 (file)
index 0000000..cfe1d1a
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ *  TFTP to HTTP proxy in Java
+ *
+ *  Copyright Ken Yap 2003
+ *  Released under GPL2
+ */
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.String;
+import java.lang.StringBuffer;
+import java.lang.Thread;
+import java.lang.NumberFormatException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HostConfiguration;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.methods.GetMethod;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *  Description of the Class
+ *
+ *@author     ken
+ *@created    24 September 2003
+ */
+public class T2hproxy implements Runnable {
+       /**
+        *  Description of the Field
+        */
+       public final static String NAME = T2hproxy.class.getName();
+       /**
+        *  Description of the Field
+        */
+       public final static String VERSION = "0.1";
+       /**
+        *  Description of the Field
+        */
+       public final static int MTU = 1500;
+       /**
+        *  Description of the Field
+        */
+       public final static short TFTP_RRQ = 1;
+       /**
+        *  Description of the Field
+        */
+       public final static short TFTP_DATA = 3;
+       /**
+        *  Description of the Field
+        */
+       public final static short TFTP_ACK = 4;
+       /**
+        *  Description of the Field
+        */
+       public final static short TFTP_ERROR = 5;
+       /**
+        *  Description of the Field
+        */
+       public final static short TFTP_OACK = 6;
+       /**
+        *  Description of the Field
+        */
+       public final static short ERR_NOFILE = 1;
+       /**
+        *  Description of the Field
+        */
+       public final static short ERR_ILLOP = 4;
+       /**
+        *  Description of the Field
+        */
+       public final static int MAX_RETRIES = 5;
+       /**
+        *  TFTP timeout in milliseconds
+        */
+       public final static int TFTP_ACK_TIMEOUT = 2000;
+       /**
+        *  Description of the Field
+        */
+       public final static int DEFAULT_PROXY_PORT = 3128;
+
+       private static Log log = LogFactory.getLog(T2hproxy.class);
+       /**
+        *  The members below must be per thread and must not share any storage with
+        *  the main thread
+        */
+       private DatagramSocket responsesocket;
+       private DatagramPacket response;
+       private InetAddress iaddr;
+       private int port;
+       private byte[] req;
+       private String prefix;
+       private String proxy = null;
+       private int timeout;
+       private HashMap options = new HashMap();
+       private int blocksize = 512;
+       private HttpClient client = new HttpClient();
+       private HttpMethod method;
+       private BufferedInputStream bstream = null;
+       private String message;
+
+
+       /**
+        *  Constructor for the T2hproxy object
+        *
+        *@param  i   Description of the Parameter
+        *@param  p   Description of the Parameter
+        *@param  b   Description of the Parameter
+        *@param  pf  Description of the Parameter
+        *@param  pr  Description of the Parameter
+        *@param  t   Timeout for HTTP GET
+        */
+       public T2hproxy(InetAddress i, int p, byte[] b, String pf, String pr, int t) {
+               iaddr = i;
+               port = p;
+               // make a copy of the request buffer
+               req = new byte[b.length];
+               System.arraycopy(b, 0, req, 0, b.length);
+               prefix = pf;
+               // proxy can be null
+               proxy = pr;
+               timeout = t;
+       }
+
+
+       /**
+        *  Extract an asciz string from bufer
+        *
+        *@param  buffer  Description of the Parameter
+        *@return         The asciz value
+        */
+       private String getAsciz(ByteBuffer buffer) {
+               StringBuffer s = new StringBuffer();
+               try {
+                       byte b;
+                       while ((b = buffer.get()) != 0) {
+                               s.append((char) b);
+                       }
+               } catch (BufferUnderflowException e) {
+               } finally {
+                       return (s.toString());
+               }
+       }
+
+
+       /**
+        *  Convert a string of digits to a number, invalid => 0
+        *
+        *@param  s  Description of the Parameter
+        *@return    Description of the Return Value
+        */
+       private int atoi(String s) {
+               if (s == null) {
+                       return (0);
+               }
+               int value = 0;
+               try {
+                       value = (new Integer(s)).intValue();
+               } catch (NumberFormatException e) {
+               }
+               return (value);
+       }
+
+
+       /**
+        *  Wait for ack packet with timeout
+        *
+        *@return    Return block number acked
+        */
+       private int waitForAck() {
+               DatagramPacket ack = new DatagramPacket(new byte[MTU], MTU);
+               try {
+                       do {
+                               responsesocket.setSoTimeout(TFTP_ACK_TIMEOUT);
+                               responsesocket.receive(ack);
+                       } while (!ack.getAddress().equals(iaddr) || ack.getPort() != port);
+               } catch (SocketTimeoutException e) {
+                       return (-1);
+               } catch (Exception e) {
+                       log.info(e.toString(), e);
+               }
+               ByteBuffer buffer = ByteBuffer.wrap(ack.getData(), ack.getOffset(), ack.getLength() - ack.getOffset());
+               short op;
+               if ((op = buffer.getShort()) == TFTP_ACK) {
+                       return ((int) buffer.getShort());
+               } else if (op == TFTP_ERROR) {
+                       return (-2);
+               }
+               return (-3);
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@param  error    Description of the Parameter
+        *@param  message  Description of the Parameter
+        */
+       private void sendError(short error, String message) {
+               ByteBuffer buffer = ByteBuffer.wrap(response.getData());
+               buffer.putShort(TFTP_ERROR).putShort(error).put(message.getBytes());
+               response.setLength(buffer.position());
+               try {
+                       responsesocket.send(response);
+               } catch (Exception e) {
+                       log.info(e.toString(), e);
+               }
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@return    Description of the Return Value
+        */
+       private boolean sendOackRecvAck() {
+               ByteBuffer buffer = ByteBuffer.wrap(response.getData());
+               buffer.putShort(TFTP_OACK).put("blksize".getBytes()).put((byte) 0).put(String.valueOf(blocksize).getBytes()).put((byte) 0);
+               response.setLength(buffer.position());
+               int retry;
+               for (retry = 0; retry < MAX_RETRIES; retry++) {
+                       try {
+                               responsesocket.send(response);
+                       } catch (Exception e) {
+                               log.info(e.toString(), e);
+                       }
+                       if (waitForAck() == 0) {
+                               log.debug("Ack received");
+                               break;
+                       }
+               }
+               return (retry < MAX_RETRIES);
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@param  block      Description of the Parameter
+        *@return            Description of the Return Value
+        */
+       private boolean sendDataBlock(int block) {
+               int retry;
+               for (retry = 0; retry < MAX_RETRIES; retry++) {
+                       try {
+                               responsesocket.send(response);
+                       } catch (Exception e) {
+                               log.info(e.toString(), e);
+                       }
+                       int ablock;
+                       if ((ablock = waitForAck()) == block) {
+                               log.debug("Ack received for " + ablock);
+                               break;
+                       } else if (ablock == -1) {
+                               log.info("Timeout waiting for ack");
+                       } else if (ablock == -2) {
+                               return (false);
+                       } else {
+                               log.info("Unknown opcode from ack");
+                       }
+               }
+               return (retry < MAX_RETRIES);
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@param  buffer  Description of the Parameter
+        *@return         Description of the Return Value
+        */
+       private boolean handleOptions(ByteBuffer buffer) {
+               for (; ; ) {
+                       String option = getAsciz(buffer);
+                       String value = getAsciz(buffer);
+                       if (option.equals("") || value.equals("")) {
+                               break;
+                       }
+                       log.info(option + " " + value);
+                       options.put(option, value);
+               }
+               blocksize = atoi((String) options.get("blksize"));
+               if (blocksize < 512) {
+                       blocksize = 512;
+               }
+               if (blocksize > 1432) {
+                       blocksize = 1432;
+               }
+               return (sendOackRecvAck());
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@param  url  Description of the Parameter
+        */
+       private void makeStream(String url) {
+               // establish a connection within timeout milliseconds
+               client.setConnectionTimeout(timeout);
+               if (proxy != null) {
+                       String[] hostport = proxy.split(":");
+                       int port = DEFAULT_PROXY_PORT;
+                       if (hostport.length > 1) {
+                               port = atoi(hostport[1]);
+                               if (port == 0) {
+                                       port = DEFAULT_PROXY_PORT;
+                               }
+                       }
+                       log.info("Proxy is " + hostport[0] + ":" + port);
+                       client.getHostConfiguration().setProxy(hostport[0], port);
+               }
+               // create a method object
+               method = new GetMethod(url);
+               method.setFollowRedirects(true);
+               method.setStrictMode(false);
+               try {
+                       int status;
+                       if ((status = client.executeMethod(method)) != 200) {
+                               log.info(message = method.getStatusText());
+                               return;
+                       }
+                       bstream = new BufferedInputStream(method.getResponseBodyAsStream());
+               } catch (HttpException he) {
+                       message = he.getMessage();
+               } catch (IOException ioe) {
+                       message = "Unable to get " + url;
+               }
+       }
+
+
+       /**
+        *  Reads a block of data from URL stream
+        *
+        *@param  stream     Description of the Parameter
+        *@param  data       Description of the Parameter
+        *@param  blocksize  Description of the Parameter
+        *@param  offset     Description of the Parameter
+        *@return            Number of bytes read
+        */
+       private int readBlock(BufferedInputStream stream, byte[] data, int offset, int blocksize) {
+               int status;
+               int nread = 0;
+               while (nread < blocksize) {
+                       try {
+                               status = stream.read(data, offset + nread, blocksize - nread);
+                       } catch (Exception e) {
+                               return (-1);
+                       }
+                       if (status < 0) {
+                               return (nread);
+                       }
+                       nread += status;
+               }
+               return (nread);
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@param  filename  Description of the Parameter
+        */
+       private void doRrq(String filename) {
+               String url = prefix + filename;
+               log.info("GET " + url);
+               makeStream(url);
+               if (bstream == null) {
+                       log.info(message);
+                       sendError(ERR_NOFILE, message);
+                       return;
+               }
+               // read directly into send buffer to avoid buffer copying
+               byte[] data;
+               ByteBuffer buffer = ByteBuffer.wrap(data = response.getData());
+               // dummy puts to get start position of data
+               buffer.putShort(TFTP_DATA).putShort((short) 0);
+               int start = buffer.position();
+               int length;
+               int block = 1;
+               do {
+                       length = readBlock(bstream, data, start, blocksize);
+                       block &= 0xffff;
+                       log.debug("Block " + block + " " + length);
+                       // fill in the block number
+                       buffer.position(0);
+                       buffer.putShort(TFTP_DATA).putShort((short) block);
+                       response.setLength(start + length);
+                       if (!sendDataBlock(block)) {
+                               break;
+                       }
+                       buffer.position(start);
+                       block++;
+               } while (length >= blocksize);
+               log.info("Closing TFTP session");
+               // clean up the connection resources
+               method.releaseConnection();
+               method.recycle();
+       }
+
+
+       /**
+        *  Main processing method for the T2hproxy object
+        */
+       public void run() {
+               ByteBuffer buffer = ByteBuffer.wrap(req);
+               buffer.getShort();
+               String filename = getAsciz(buffer);
+               String mode = getAsciz(buffer);
+               log.info(filename + " " + mode);
+               response = new DatagramPacket(new byte[MTU], MTU, iaddr, port);
+               try {
+                       responsesocket = new DatagramSocket();
+               } catch (SocketException e) {
+                       log.info(e.toString(), e);
+                       return;
+               }
+               if (!handleOptions(buffer)) {
+                       return;
+               }
+               doRrq(filename);
+       }
+
+
+       /**
+        *  Description of the Method
+        *
+        *@param  s        Description of the Parameter
+        *@param  r        Description of the Parameter
+        *@param  prefix   Description of the Parameter
+        *@param  proxy    Description of the Parameter
+        *@param  timeout  Description of the Parameter
+        */
+       public static void handleRequest(DatagramSocket s, DatagramPacket r, String prefix, String proxy, int timeout) {
+               log.info("Connection from " + r.getAddress().getCanonicalHostName() + ":" + r.getPort());
+               ByteBuffer buffer = ByteBuffer.wrap(r.getData(), r.getOffset(), r.getLength() - r.getOffset());
+               if (buffer.getShort() != TFTP_RRQ) {
+                       DatagramPacket error = new DatagramPacket(new byte[MTU], MTU);
+                       ByteBuffer rbuf = ByteBuffer.wrap(error.getData());
+                       rbuf.putShort(TFTP_ERROR).putShort(ERR_ILLOP).put("Illegal operation".getBytes());
+                       error.setLength(rbuf.position());
+                       try {
+                               s.send(error);
+                       } catch (Exception e) {
+                               log.info(e.toString(), e);
+                       }
+                       return;
+               }
+               // fork thread
+               new Thread(new T2hproxy(r.getAddress(), r.getPort(), r.getData(), prefix, proxy, timeout)).start();
+       }
+
+
+       /**
+        *  The main program for the T2hproxy class
+        *
+        *@param  argv             The command line arguments
+        *@exception  IOException  Description of the Exception
+        */
+       public static void main(String[] argv) throws IOException {
+               log.info(T2hproxy.NAME + "." + T2hproxy.VERSION);
+               int port = Integer.getInteger(T2hproxy.NAME + ".port", 69).intValue();
+               String prefix = System.getProperty(T2hproxy.NAME + ".prefix", "http://localhost/");
+               String proxy = System.getProperty(T2hproxy.NAME + ".proxy");
+               int timeout = Integer.getInteger(T2hproxy.NAME + ".timeout", 5000).intValue();
+               String propfile = System.getProperty(T2hproxy.NAME + ".properties");
+               if (propfile != null) {
+                       FileInputStream pf = new FileInputStream(propfile);
+                       Properties p = new Properties(System.getProperties());
+                       p.load(pf);
+                       // set the system properties
+                       System.setProperties(p);
+               }
+               DatagramSocket requestsocket;
+               try {
+                       requestsocket = new DatagramSocket(port);
+               } catch (SocketException e) {
+                       log.info(e.toString(), e);
+                       return;
+               }
+               DatagramPacket request = new DatagramPacket(new byte[MTU], MTU);
+               for (; ; ) {
+                       try {
+                               requestsocket.receive(request);
+                               handleRequest(requestsocket, request, prefix, proxy, timeout);
+                       } catch (Exception e) {
+                               log.info(e.toString(), e);
+                       }
+               }
+       }
+}
diff --git a/contrib/t2hproxy/build.xml b/contrib/t2hproxy/build.xml
new file mode 100644 (file)
index 0000000..5494ab9
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!--
+ Build file for T2hproxy
+-->
+<project name="T2hproxy" default="jar" basedir=".">
+  <target name="compile">
+    <javac fork="true" srcdir="." destdir="." />
+  </target>
+
+  <target name="jar" depends="compile">
+    <jar jarfile="T2hproxy.jar" basedir="."
+    includes="T2hproxy.class">
+      <manifest>
+        <attribute name="Main-Class" value="T2hproxy" />
+      </manifest>
+    </jar>
+  </target>
+</project>
+
diff --git a/contrib/t2hproxy/runT2proxy.sh b/contrib/t2hproxy/runT2proxy.sh
new file mode 100755 (executable)
index 0000000..d7fc0d2
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# If the httpclient and logging jars are not in the standard directories
+# edit and uncomment
+# CP='-cp /usr/local/lib/commons-httpclient-2.0-rc1.jar:/usr/local/lib/commons-logging-api.jar:/usr/local/lib/commons-logging.jar'
+
+# Edit and uncomment to use an alternate port
+# PORT='-DT2hproxy.port=1069'
+PREFIX='-DT2hproxy.prefix=http://localhost/'
+# Edit and uncomment to use a proxy
+# PROXY='-DT2hproxy.proxy=localhost:3128'
+# These T2hproxy properties can be put in a file and read in all at once
+# PROPERTIES='-DT2hproxy.properties=t2hproxy.prop
+
+exec java -jar $CP $PORT $PREFIX $PROXY $PROPERTIES T2hproxy.jar
diff --git a/contrib/t2hproxy/t2hproxy.pl b/contrib/t2hproxy/t2hproxy.pl
new file mode 100755 (executable)
index 0000000..4fc0178
--- /dev/null
@@ -0,0 +1,174 @@
+#!/usr/bin/perl -w
+#
+# tftp to http proxy
+# Copyright 2003 Ken Yap
+# Released under GPL2
+#
+
+require 5.8.0;         # needs constant and the pack Z format behaviour
+
+use bytes;             # to forestall Unicode interpretation of strings
+use strict;
+
+use Getopt::Long;
+use Socket;
+use Sys::Hostname;
+use Sys::Syslog;
+use LWP;
+use POSIX 'setsid';
+
+use constant PROGNAME => 't2hproxy';
+use constant VERSION => '0.1';
+
+use constant ETH_DATA_LEN => 1500;
+use constant {
+       TFTP_RRQ => 1, TFTP_WRQ => 2, TFTP_DATA => 3, TFTP_ACK => 4,
+       TFTP_ERROR => 5, TFTP_OACK => 6
+};
+use constant {
+       E_UNDEF => 0, E_FNF => 1, E_ACC => 2, E_DISK => 3, E_ILLOP => 4,
+       E_UTID => 5, E_FEXIST => 6, E_NOUSER => 7
+};
+
+use vars qw($prefix $proxy $sockh $timeout %options $tsize $bsize);
+
+# We can't use die because xinetd will think something's wrong
+sub log_and_exit ($) {
+       syslog('info', $_[0]);
+       exit;
+}
+
+sub what_source ($) {
+       my ($port, $saddr) = sockaddr_in($_[0]);
+       my $host = gethostbyaddr($saddr, AF_INET);
+       return ($host, $port);
+}
+
+sub send_error ($$$) {
+       my ($iaddr, $error, $message) = @_;
+       # error packets don't get acked
+       send(STDOUT, pack('nna*', TFTP_ERROR, $error, $message), 0, $iaddr);
+}
+
+sub send_ack_retry ($$$$$) {
+       my ($iaddr, $udptimeout, $maxretries, $blockno, $sendfunc) = @_;
+RETRY:
+       while ($maxretries-- > 0) {
+               &$sendfunc;
+               my $rin = '';
+               my $rout = '';
+               vec($rin, fileno($sockh), 1) = 1;
+               do {
+                       my ($fds, $timeleft) = select($rout = $rin, undef, undef, $udptimeout);
+                       last if ($fds <= 0);
+                       my $ack;
+                       my $theiripaddr = recv($sockh, $ack, 256, 0);
+                       # check it's for us
+                       if ($theiripaddr eq $iaddr) {
+                               my ($opcode, $ackblock) = unpack('nn', $ack);
+                               return (0) if ($opcode == TFTP_ERROR);
+                               # check that the right block was acked
+                               if ($ackblock == $blockno) {
+                                       return (1);
+                               } else {
+                                       syslog('info', "Resending block $blockno");
+                                       next RETRY;
+                               }
+                       }
+                       # stray packet for some other server instance
+                       send_error($theiripaddr, E_UTID, 'Wrong TID');
+               } while (1);
+       }
+       return (0);
+}
+
+sub handle_options ($$) {
+       my ($iaddr, $operand) = @_;
+       while ($operand ne '') {
+               my ($key, $value) = unpack('Z*Z*', $operand);
+               $options{$key} = $value;
+               syslog('info', "$key=$value");
+               $operand = substr($operand, length($key) + length($value) + 2);
+       }
+       my $optstr = '';
+       if (exists($options{blksize})) {
+               $bsize = $options{blksize};
+               $bsize = 512 if ($bsize < 512);
+               $bsize = 1432 if ($bsize > 1432);
+               $optstr .= pack('Z*Z*', 'blksize', $bsize . '');
+       }
+       # OACK expects an ack for block 0
+       log_and_exit('Abort received or retransmit limit reached, exiting')
+               unless send_ack_retry($iaddr, 2, 5, 0,
+               sub { send($sockh, pack('na*', TFTP_OACK, $optstr), 0, $iaddr); });
+}
+
+sub http_get ($) {
+       my ($url) = @_;
+       syslog('info', "GET $url");
+       my $ua = LWP::UserAgent->new;
+       $ua->timeout($timeout);
+       $ua->proxy(['http', 'ftp'], $proxy) if (defined($proxy) and $proxy);
+       my $req = HTTP::Request->new(GET => $url);
+       my $res = $ua->request($req);
+       return ($res->is_success, $res->status_line, $res->content_ref);
+}
+
+sub send_file ($$) {
+       my ($iaddr, $contentref) = @_;
+       my $blockno = 1;
+       my $data;
+       do {
+               $blockno &= 0xffff;
+               $data = substr($$contentref, ($blockno - 1) * $bsize, $bsize);
+               # syslog('info', "Block $blockno length " . length($data));
+               log_and_exit('Abort received or retransmit limit reached, exiting')
+                       unless send_ack_retry($iaddr, 2, 5, $blockno,
+                       sub { send($sockh, pack('nna*', TFTP_DATA, $blockno, $data), 0, $iaddr); });
+               $blockno++;
+       } while (length($data) >= $bsize);
+}
+
+sub do_rrq ($$) {
+       my ($iaddr, $packetref) = @_;
+       # fork and handle request in child so that *inetd can continue
+       # to serve incoming requests
+       defined(my $pid = fork) or log_and_exit("Can't fork: $!");
+       exit if $pid;           # parent exits
+       setsid or log_and_exit("Can't start a new session: $!");
+       socket(SOCK, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or log_and_exit('Cannot create UDP socket');
+       $sockh = *SOCK{IO};
+       my ($opcode, $operand) = unpack('na*', $$packetref);
+       my ($filename, $mode) = unpack('Z*Z*', $operand);
+       syslog('info', "RRQ $filename $mode");
+       my $length = length($filename) + length($mode) + 2;
+       $operand = substr($operand, $length);
+       handle_options($iaddr, $operand) if ($operand ne '');
+       my ($success, $status_line, $result) = http_get($prefix . $filename);
+       syslog('info', $status_line);
+       if ($success) {
+               send_file($iaddr, $result);
+       } else {
+               send_error($iaddr, E_FNF, $status_line);
+       }
+}
+
+$prefix = 'http://localhost/';
+$timeout = 60;
+GetOptions('prefix=s' => \$prefix,
+       'proxy=s' => \$proxy,
+       'timeout=i' => \$timeout);
+$bsize = 512;
+openlog(PROGNAME, 'cons,pid', 'user');
+syslog('info', PROGNAME . ' version ' . VERSION);
+my $packet;
+my $theiriaddr = recv(STDIN, $packet, ETH_DATA_LEN, 0);
+my ($host, $port) = what_source($theiriaddr);
+syslog('info', "Connection from $host:$port");
+my $opcode = unpack('n', $packet);
+if ($opcode == TFTP_RRQ) {
+       do_rrq($theiriaddr, \$packet);
+} else {       # anything else is an error
+       send_error($theiriaddr, E_ILLOP, 'Illegal operation');
+}
+exit 0;
diff --git a/contrib/t2hproxy/t2hproxy.xinetd b/contrib/t2hproxy/t2hproxy.xinetd
new file mode 100644 (file)
index 0000000..ea6a03f
--- /dev/null
@@ -0,0 +1,29 @@
+# Description: tftp to http proxy
+# A sample config file for xinetd, edit and put in /etc/xinetd.d
+# then killall -HUP xinetd, or restart xinetd
+
+service t2hproxy
+{
+       type            = UNLISTED
+       id              = t2hproxy
+       socket_type     = dgram
+       protocol        = udp
+#
+#      The pathname to where you have installed it
+#
+       server          = /usr/local/sbin/t2hproxy.pl
+#
+#      If your filenames don't start with /, then the trailing
+#      slash is needed
+#
+       server_args     = --prefix http://localhost/
+#
+#      --proxy http://proxyhost:3128/ can also be appended
+#
+       log_type        = FILE /var/log/t2hproxy.log
+       user            = nobody
+       wait            = yes
+       instances       = 10
+       disable         = no
+       port            = 69
+}                                                                               
diff --git a/contrib/tftp/Makefile b/contrib/tftp/Makefile
new file mode 100644 (file)
index 0000000..bd427cd
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 1987 Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that the above copyright notice and this paragraph are
+# duplicated in all such forms and that any documentation,
+# advertising materials, and other materials related to such
+# distribution and use acknowledge that the software was developed
+# by the University of California, Berkeley.  The name of the
+# University may not be used to endorse or promote products derived
+# from this software without specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#      @(#)Makefile    5.8 (Berkeley) 9/20/88
+#
+# We override /usr/include/arpa/tftp.h with our own because
+# we want tu_block to be unsigned short, not short as on most platforms
+#
+CFLAGS=        -I. -O2 -Dsin=sin_x
+SRCS=  main.c tftp.c tftpsubs.c tftpd.c
+OBJS=  main.o tftp.o tftpsubs.o
+DOBJS= tftpd.o tftpsubs.o
+CC=    gcc
+LIBS=  # -linet
+
+all: tftp tftpd
+
+tftp: ${OBJS}
+       ${CC} -o $@ ${CFLAGS} ${OBJS} # -linet
+
+tftpd: ${DOBJS}
+       ${CC} -o $@ ${CFLAGS} ${DOBJS} ${LIBS}
+
+clean:
+       rm -f ${OBJS} ${DOBJS} core tftp tftpd
+
+cleandir: clean
+       rm -f tags .depend
+
+depend: ${SRCS}
+       mkdep ${CFLAGS} ${SRCS}
+
+install:
+       install -s -o root -g root -m 755 tftp /usr/bin/tftp
+       install -c -o root -g root -m 444 tftp.1 /usr/man/man1
+       install -s -o root -g root -m 755 tftpd /usr/sbin/in.tftpd
+       install -c -o root -g root -m 444 tftpd.8 /usr/man/man8
+
+lint: ${SRCS}
+       lint ${CFLAGS} ${SRCS}
+
+tags: ${SRCS}
+       ctags ${SRCS}
diff --git a/contrib/tftp/README b/contrib/tftp/README
new file mode 100644 (file)
index 0000000..e495720
--- /dev/null
@@ -0,0 +1,28 @@
+This is a copy of the TFTP client as available from
+ftp://sunsite.unc.edu/pub/linux/system/Network/file-transfer; I
+modified the code, so that it understands RFC1782 and RFC1783
+extensions to the TFTP protocol.  This allows for negotating an
+extended transfer block size of up to 1432 bytes (as oppossed to the
+standard 512 bytes).  On busy networks, this will result in
+considerably improved throughput and less load on the network.
+
+For further information and for licensing conditions, please have a
+look at the header of the source files.
+
+Markus Gutschke <gutschk@math.uni-muenster.de>
+
+This is a copy of the TFTP server as available from
+ftp://sunsite.unc.edu/pub/linux/system/Network/file-transfer; I
+modified the code, so that it understands RFC1782 and RFC1783
+extensions to the TFTP protocol.  This allows for negotating an
+extended transfer block size of up to 1432 bytes (as oppossed to the
+standard 512 bytes).  On busy networks, this will result in
+considerably improved throughput and less load on the network.
+
+I also added two command line options for changing the root directory
+and for enabling debugging output.
+
+For further information and for licensing conditions, please have a
+look at the header of the source files.
+
+Markus Gutschke <gutschk@math.uni-muenster.de>
diff --git a/contrib/tftp/arpa/tftp.h b/contrib/tftp/arpa/tftp.h
new file mode 100644 (file)
index 0000000..0904407
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tftp.h      8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ARPA_TFTP_H
+#define        _ARPA_TFTP_H 1
+
+/*
+ * Trivial File Transfer Protocol (IEN-133)
+ */
+#define        SEGSIZE         512             /* data segment size */
+
+/*
+ * Packet types.
+ */
+#define        RRQ     01                              /* read request */
+#define        WRQ     02                              /* write request */
+#define        DATA    03                              /* data packet */
+#define        ACK     04                              /* acknowledgement */
+#define        ERROR   05                              /* error code */
+
+struct tftphdr {
+       short   th_opcode;                      /* packet type */
+       union {
+               unsigned short  tu_block;       /* block # */
+               short   tu_code;                /* error code */
+               char    tu_stuff[1];            /* request packet stuff */
+       } th_u;
+       char    th_data[1];                     /* data or error string */
+};
+
+#define        th_block        th_u.tu_block
+#define        th_code         th_u.tu_code
+#define        th_stuff        th_u.tu_stuff
+#define        th_msg          th_data
+
+/*
+ * Error codes.
+ */
+#define        EUNDEF          0               /* not defined */
+#define        ENOTFOUND       1               /* file not found */
+#define        EACCESS         2               /* access violation */
+#define        ENOSPACE        3               /* disk full or allocation exceeded */
+#define        EBADOP          4               /* illegal TFTP operation */
+#define        EBADID          5               /* unknown transfer ID */
+#define        EEXISTS         6               /* file already exists */
+#define        ENOUSER         7               /* no such user */
+
+#endif /* arpa/tftp.h */
diff --git a/contrib/tftp/main.c b/contrib/tftp/main.c
new file mode 100644 (file)
index 0000000..ca4427a
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c     5.8 (Berkeley) 10/11/88";
+#endif /* not lint */
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Command Interface.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+
+#include <netinet/in.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <netdb.h>
+
+#define        TIMEOUT         5               /* secs between rexmt's */
+
+struct sockaddr_in sin;
+int    f;
+short   port;
+int    trace;
+int    verbose;
+int    connected;
+char   mode[32];
+char   line[200];
+int    margc;
+char   *margv[20];
+char   *prompt = "tftp";
+jmp_buf        toplevel;
+void   intr(int);
+struct servent *sp;
+
+int    segsize = 512;
+
+int    quit(), help(), setverbose(), settrace(), status();
+int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
+int     setbinary(), setascii(), setblocksize();
+
+#define HELPINDENT (sizeof("connect"))
+
+struct cmd {
+       char    *name;
+       char    *help;
+       int     (*handler)();
+};
+
+char   vhelp[] = "toggle verbose mode";
+char   thelp[] = "toggle packet tracing";
+char   chelp[] = "connect to remote tftp";
+char   qhelp[] = "exit tftp";
+char   hhelp[] = "print help information";
+char   shelp[] = "send file";
+char   rhelp[] = "receive file";
+char   mhelp[] = "set file transfer mode";
+char   sthelp[] = "show current status";
+char   xhelp[] = "set per-packet retransmission timeout";
+char   ihelp[] = "set total retransmission timeout";
+char    ashelp[] = "set mode to netascii";
+char    bnhelp[] = "set mode to octet";
+char   bshelp[] = "set blocksize for next transfer";
+
+struct cmd cmdtab[] = {
+       { "connect",    chelp,          setpeer },
+       { "mode",       mhelp,          modecmd },
+       { "put",        shelp,          put },
+       { "get",        rhelp,          get },
+       { "quit",       qhelp,          quit },
+       { "verbose",    vhelp,          setverbose },
+       { "trace",      thelp,          settrace },
+       { "status",     sthelp,         status },
+       { "binary",     bnhelp,         setbinary },
+       { "ascii",      ashelp,         setascii },
+       { "rexmt",      xhelp,          setrexmt },
+       { "timeout",    ihelp,          settimeout },
+       { "blocksize",  bshelp,         setblocksize },
+       { "?",          hhelp,          help },
+       0
+};
+
+struct cmd *getcmd();
+char   *tail();
+char   *index();
+char   *rindex();
+
+main(argc, argv)
+       char *argv[];
+{
+       struct sockaddr_in sin;
+       int top;
+
+       sp = getservbyname("tftp", "udp");
+       if (sp == 0) {
+               fprintf(stderr, "tftp: udp/tftp: unknown service\n");
+               exit(1);
+       }
+       f = socket(AF_INET, SOCK_DGRAM, 0);
+       if (f < 0) {
+               perror("tftp: socket");
+               exit(3);
+       }
+       bzero((char *)&sin, sizeof (sin));
+       sin.sin_family = AF_INET;
+       if (bind(f, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+               perror("tftp: bind");
+               exit(1);
+       }
+       strcpy(mode, "netascii");
+       signal(SIGINT, intr);
+       if (argc > 1) {
+               if (setjmp(toplevel) != 0)
+                       exit(0);
+               setpeer(argc, argv);
+       }
+       top = setjmp(toplevel) == 0;
+       for (;;)
+               command(top);
+}
+
+char    hostname[100];
+
+setpeer(argc, argv)
+       int argc;
+       char *argv[];
+{
+       struct hostent *host;
+
+       if (argc < 2) {
+               strcpy(line, "Connect ");
+               printf("(to) ");
+               fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc > 3) {
+               printf("usage: %s host-name [port]\n", argv[0]);
+               return;
+       }
+       host = gethostbyname(argv[1]);
+       if (host) {
+               sin.sin_family = host->h_addrtype;
+               bcopy(host->h_addr, &sin.sin_addr, host->h_length);
+               strcpy(hostname, host->h_name);
+       } else {
+               sin.sin_family = AF_INET;
+               sin.sin_addr.s_addr = inet_addr(argv[1]);
+               if (sin.sin_addr.s_addr == -1) {
+                       connected = 0;
+                       printf("%s: unknown host\n", argv[1]);
+                       return;
+               }
+               strcpy(hostname, argv[1]);
+       }
+       port = sp->s_port;
+       if (argc == 3) {
+               port = atoi(argv[2]);
+               if (port < 0) {
+                       printf("%s: bad port number\n", argv[2]);
+                       connected = 0;
+                       return;
+               }
+               port = htons(port);
+       }
+       connected = 1;
+}
+
+struct modes {
+       char *m_name;
+       char *m_mode;
+} modes[] = {
+       { "ascii",      "netascii" },
+       { "netascii",   "netascii" },
+       { "binary",     "octet" },
+       { "image",      "octet" },
+       { "octet",     "octet" },
+/*      { "mail",       "mail" },       */
+       { 0,            0 }
+};
+
+modecmd(argc, argv)
+       char *argv[];
+{
+       register struct modes *p;
+       char *sep;
+
+       if (argc < 2) {
+               printf("Using %s mode to transfer files.\n", mode);
+               return;
+       }
+       if (argc == 2) {
+               for (p = modes; p->m_name; p++)
+                       if (strcmp(argv[1], p->m_name) == 0)
+                               break;
+               if (p->m_name) {
+                       setmode(p->m_mode);
+                       return;
+               }
+               printf("%s: unknown mode\n", argv[1]);
+               /* drop through and print usage message */
+       }
+
+       printf("usage: %s [", argv[0]);
+       sep = " ";
+       for (p = modes; p->m_name; p++) {
+               printf("%s%s", sep, p->m_name);
+               if (*sep == ' ')
+                       sep = " | ";
+       }
+       printf(" ]\n");
+       return;
+}
+
+setbinary(argc, argv)
+char *argv[];
+{       setmode("octet");
+}
+
+setascii(argc, argv)
+char *argv[];
+{       setmode("netascii");
+}
+
+setmode(newmode)
+char *newmode;
+{
+       strcpy(mode, newmode);
+       if (verbose)
+               printf("mode set to %s\n", mode);
+}
+
+
+/*
+ * Send file(s).
+ */
+put(argc, argv)
+       char *argv[];
+{
+       int fd;
+       register int n;
+       register char *cp, *targ;
+
+       if (argc < 2) {
+               strcpy(line, "send ");
+               printf("(file) ");
+               fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               putusage(argv[0]);
+               return;
+       }
+       targ = argv[argc - 1];
+       if (index(argv[argc - 1], ':')) {
+               char *cp;
+               struct hostent *hp;
+
+               for (n = 1; n < argc - 1; n++)
+                       if (index(argv[n], ':')) {
+                               putusage(argv[0]);
+                               return;
+                       }
+               cp = argv[argc - 1];
+               targ = index(cp, ':');
+               *targ++ = 0;
+               hp = gethostbyname(cp);
+               if (hp == NULL) {
+                       fprintf(stderr, "tftp: %s: ", cp);
+                       herror((char *)NULL);
+                       return;
+               }
+               bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+               sin.sin_family = hp->h_addrtype;
+               connected = 1;
+               strcpy(hostname, hp->h_name);
+       }
+       if (!connected) {
+               printf("No target machine specified.\n");
+               return;
+       }
+       if (argc < 4) {
+               cp = argc == 2 ? tail(targ) : argv[1];
+               fd = open(cp, O_RDONLY);
+               if (fd < 0) {
+                       fprintf(stderr, "tftp: "); perror(cp);
+                       return;
+               }
+               if (verbose)
+                       printf("putting %s to %s:%s [%s]\n",
+                               cp, hostname, targ, mode);
+               sin.sin_port = port;
+               sendfile(fd, targ, mode);
+               return;
+       }
+                               /* this assumes the target is a directory */
+                               /* on a remote unix system.  hmmmm.  */
+       cp = index(targ, '\0'); 
+       *cp++ = '/';
+       for (n = 1; n < argc - 1; n++) {
+               strcpy(cp, tail(argv[n]));
+               fd = open(argv[n], O_RDONLY);
+               if (fd < 0) {
+                       fprintf(stderr, "tftp: "); perror(argv[n]);
+                       continue;
+               }
+               if (verbose)
+                       printf("putting %s to %s:%s [%s]\n",
+                               argv[n], hostname, targ, mode);
+               sin.sin_port = port;
+               sendfile(fd, targ, mode);
+       }
+}
+
+putusage(s)
+       char *s;
+{
+       printf("usage: %s file ... host:target, or\n", s);
+       printf("       %s file ... target (when already connected)\n", s);
+}
+
+/*
+ * Receive file(s).
+ */
+get(argc, argv)
+       char *argv[];
+{
+       int fd;
+       register int n;
+       register char *cp;
+       char *src;
+
+       if (argc < 2) {
+               strcpy(line, "get ");
+               printf("(files) ");
+               fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               getusage(argv[0]);
+               return;
+       }
+       if (!connected) {
+               for (n = 1; n < argc ; n++)
+                       if (index(argv[n], ':') == 0) {
+                               getusage(argv[0]);
+                               return;
+                       }
+       }
+       for (n = 1; n < argc ; n++) {
+               src = index(argv[n], ':');
+               if (src == NULL)
+                       src = argv[n];
+               else {
+                       struct hostent *hp;
+
+                       *src++ = 0;
+                       hp = gethostbyname(argv[n]);
+                       if (hp == NULL) {
+                               fprintf(stderr, "tftp: %s: ", argv[n]);
+                               herror((char *)NULL);
+                               continue;
+                       }
+                       bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
+                       sin.sin_family = hp->h_addrtype;
+                       connected = 1;
+                       strcpy(hostname, hp->h_name);
+               }
+               if (argc < 4) {
+                       cp = argc == 3 ? argv[2] : tail(src);
+                       fd = creat(cp, 0644);
+                       if (fd < 0) {
+                               fprintf(stderr, "tftp: "); perror(cp);
+                               return;
+                       }
+                       if (verbose)
+                               printf("getting from %s:%s to %s [%s]\n",
+                                       hostname, src, cp, mode);
+                       sin.sin_port = port;
+                       recvfile(fd, src, mode);
+                       break;
+               }
+               cp = tail(src);         /* new .. jdg */
+               fd = creat(cp, 0644);
+               if (fd < 0) {
+                       fprintf(stderr, "tftp: "); perror(cp);
+                       continue;
+               }
+               if (verbose)
+                       printf("getting from %s:%s to %s [%s]\n",
+                               hostname, src, cp, mode);
+               sin.sin_port = port;
+               recvfile(fd, src, mode);
+       }
+}
+
+getusage(s)
+char * s;
+{
+       printf("usage: %s host:file host:file ... file, or\n", s);
+       printf("       %s file file ... file if connected\n", s);
+}
+
+int    rexmtval = TIMEOUT;
+
+setrexmt(argc, argv)
+       char *argv[];
+{
+       int t;
+
+       if (argc < 2) {
+               strcpy(line, "Rexmt-timeout ");
+               printf("(value) ");
+               fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc != 2) {
+               printf("usage: %s value\n", argv[0]);
+               return;
+       }
+       t = atoi(argv[1]);
+       if (t < 0)
+               printf("%d: bad value\n", t);
+       else
+               rexmtval = t;
+}
+
+int    maxtimeout = 5 * TIMEOUT;
+
+settimeout(argc, argv)
+       char *argv[];
+{
+       int t;
+
+       if (argc < 2) {
+               strcpy(line, "Maximum-timeout ");
+               printf("(value) ");
+               fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc != 2) {
+               printf("usage: %s value\n", argv[0]);
+               return;
+       }
+       t = atoi(argv[1]);
+       if (t < 0)
+               printf("%d: bad value\n", t);
+       else
+               maxtimeout = t;
+}
+
+status(argc, argv)
+       char *argv[];
+{
+       if (connected)
+               printf("Connected to %s.\n", hostname);
+       else
+               printf("Not connected.\n");
+       printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
+               verbose ? "on" : "off", trace ? "on" : "off");
+       printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
+               rexmtval, maxtimeout);
+}
+
+void intr(int sig)
+{
+       signal(SIGALRM, SIG_IGN);
+       alarm(0);
+       longjmp(toplevel, -1);
+}
+
+char *
+tail(filename)
+       char *filename;
+{
+       register char *s;
+       
+       while (*filename) {
+               s = rindex(filename, '/');
+               if (s == NULL)
+                       break;
+               if (s[1])
+                       return (s + 1);
+               *s = '\0';
+       }
+       return (filename);
+}
+
+/*
+ * Command parser.
+ */
+command(top)
+       int top;
+{
+       register struct cmd *c;
+
+       if (!top)
+               putchar('\n');
+       for (;;) {
+               printf("%s> ", prompt);
+               if (fgets(line, sizeof(line), stdin) == 0) {
+                       if (feof(stdin)) {
+                               quit();
+                       } else {
+                               continue;
+                       }
+               }
+               if (line[0] == 0)
+                       continue;
+               makeargv();
+               c = getcmd(margv[0]);
+               if (c == (struct cmd *)-1) {
+                       printf("?Ambiguous command\n");
+                       continue;
+               }
+               if (c == 0) {
+                       printf("?Invalid command\n");
+                       continue;
+               }
+               (*c->handler)(margc, margv);
+       }
+}
+
+struct cmd *
+getcmd(name)
+       register char *name;
+{
+       register char *p, *q;
+       register struct cmd *c, *found;
+       register int nmatches, longest;
+
+       longest = 0;
+       nmatches = 0;
+       found = 0;
+       for (c = cmdtab; p = c->name; c++) {
+               for (q = name; *q == *p++; q++)
+                       if (*q == 0)            /* exact match? */
+                               return (c);
+               if (!*q) {                      /* the name was a prefix */
+                       if (q - name > longest) {
+                               longest = q - name;
+                               nmatches = 1;
+                               found = c;
+                       } else if (q - name == longest)
+                               nmatches++;
+               }
+       }
+       if (nmatches > 1)
+               return ((struct cmd *)-1);
+       return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+makeargv()
+{
+       register char *cp;
+       register char **argp = margv;
+
+       margc = 0;
+       for (cp = line; *cp;) {
+               while (isspace(*cp))
+                       cp++;
+               if (*cp == '\0')
+                       break;
+               *argp++ = cp;
+               margc += 1;
+               while (*cp != '\0' && !isspace(*cp))
+                       cp++;
+               if (*cp == '\0')
+                       break;
+               *cp++ = '\0';
+       }
+       *argp++ = 0;
+}
+
+/*VARARGS*/
+quit()
+{
+       exit(0);
+}
+
+/*
+ * Help command.
+ */
+help(argc, argv)
+       int argc;
+       char *argv[];
+{
+       register struct cmd *c;
+
+       if (argc == 1) {
+               printf("Commands may be abbreviated.  Commands are:\n\n");
+               for (c = cmdtab; c->name; c++)
+                       printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
+               return;
+       }
+       while (--argc > 0) {
+               register char *arg;
+               arg = *++argv;
+               c = getcmd(arg);
+               if (c == (struct cmd *)-1)
+                       printf("?Ambiguous help command %s\n", arg);
+               else if (c == (struct cmd *)0)
+                       printf("?Invalid help command %s\n", arg);
+               else
+                       printf("%s\n", c->help);
+       }
+}
+
+/*VARARGS*/
+settrace()
+{
+       trace = !trace;
+       printf("Packet tracing %s.\n", trace ? "on" : "off");
+}
+
+/*VARARGS*/
+setverbose()
+{
+       verbose = !verbose;
+       printf("Verbose mode %s.\n", verbose ? "on" : "off");
+}
+
+setblocksize(argc, argv)
+       char *argv[];
+{
+       int t;
+
+       if (argc < 2) {
+               strcpy(line, "blocksize ");
+               printf("(value) ");
+               fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc != 2) {
+               printf("usage: %s value\n", argv[0]);
+               return;
+       }
+       t = atoi(argv[1]);
+       if (t < 8 || t > 1432)
+               printf("%d: bad value\n", t);
+       else
+               segsize = t;
+}
diff --git a/contrib/tftp/tftp.1 b/contrib/tftp/tftp.1
new file mode 100644 (file)
index 0000000..fc235b2
--- /dev/null
@@ -0,0 +1,159 @@
+.\" Copyright (c) 1986 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"    @(#)tftp.1      5.3 (Berkeley) 9/20/88
+.\"
+.TH TFTP 1 "September 20, 1988"
+.UC 6
+.SH NAME
+tftp \- trivial file transfer program
+.SH SYNOPSIS
+.B tftp
+[
+host
+]
+.SH DESCRIPTION
+.I Tftp
+is the user interface to the Internet TFTP
+(Trivial File Transfer Protocol),
+which allows users to transfer files to and from a remote machine.
+The remote
+.I host
+may be specified on the command line, in which case
+.I tftp
+uses
+.I host
+as the default host for future transfers (see the
+.B connect
+command below).
+.SH COMMANDS
+Once
+.I tftp
+is running, it issues the prompt
+.B tftp>
+and recognizes the following commands:
+.TP
+\fBconnect\fP \fIhost-name\fP [ \fIport\fP ]
+Set the
+.I host
+(and optionally
+.IR port )
+for transfers.
+Note that the TFTP protocol, unlike the FTP protocol,
+does not maintain connections betweeen transfers; thus, the
+.I connect
+command does not actually create a connection,
+but merely remembers what host is to be used for transfers.
+You do not have to use the 
+.I connect
+command; the remote host can be specified as part of the
+.I get
+or
+.I put
+commands.
+.TP
+\fBmode\fP \fItransfer-mode\fP
+Set the mode for transfers; 
+.I transfer-mode
+may be one of
+.IR ascii
+or
+.IR binary .
+The default is
+.IR ascii .
+.TP
+\fBput\fP \fIfile\fP
+.ns
+.TP
+\fBput\fP \fIlocalfile remotefile\fP
+.ns
+.TP
+\fBput\fP \fIfile1 file2 ... fileN remote-directory\fP
+Put a file or set of files to the specified
+remote file or directory.
+The destination
+can be in one of two forms:
+a filename on the remote host, if the host has already been specified,
+or a string of the form
+.I host:filename
+to specify both a host and filename at the same time.
+If the latter form is used,
+the hostname specified becomes the default for future transfers.
+If the remote-directory form is used, the remote host is
+assumed to be a
+.I UNIX
+machine.
+.TP
+\fBget\fP \fIfilename\fP
+.ns
+.TP
+\fBget\fP \fIremotename\fP \fIlocalname\fP
+.ns
+.TP
+\fBget\fP \fIfile1\fP \fIfile2\fP ... \fIfileN\fP
+Get a file or set of files from the specified
+.IR sources .
+.I Source
+can be in one of two forms:
+a filename on the remote host, if the host has already been specified,
+or a string of the form
+.I host:filename
+to specify both a host and filename at the same time.
+If the latter form is used,
+the last hostname specified becomes the default for future transfers.
+.TP
+.B quit
+Exit
+.IR tftp .
+An end of file also exits.
+.TP
+.B verbose
+Toggle verbose mode.
+.TP
+.B trace
+Toggle packet tracing.
+.TP
+.B status
+Show current status.
+.TP
+\fBrexmt\fP \fIretransmission-timeout\fP
+Set the per-packet retransmission timeout, in seconds.
+.TP
+\fBtimeout\fP \fItotal-transmission-timeout\fP
+Set the total transmission timeout, in seconds.
+.TP
+.B ascii
+Shorthand for "mode ascii"
+.TP
+.B binary
+Shorthand for "mode binary"
+.TP
+\fBblocksize\fP \fItransfer-blocksize\fP
+Set the blocksize that is used for transfers. This assumes that the
+server knows about RFC1782 and RFC1783 extensions to the TFTP
+protocol; automatic fallback is supported and will result in a default
+blocksize of 512 octets.
+.TP
+\fB?\fP \ [ \fIcommand-name\fP ... ]
+Print help information.
+.SH BUGS
+.PP
+Because there is no user-login or validation within
+the
+.I TFTP
+protocol, the remote site will probably have some
+sort of file-access restrictions in place.  The
+exact methods are specific to each site and therefore
+difficult to document here.
diff --git a/contrib/tftp/tftp.c b/contrib/tftp/tftp.c
new file mode 100644 (file)
index 0000000..894e535
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tftp.c     5.7 (Berkeley) 6/29/88";
+#endif /* not lint */
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Protocol Machines
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/tftp.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+
+extern int errno;
+
+extern  struct sockaddr_in sin;         /* filled in by main */
+extern  int     f;                      /* the opened socket */
+extern  int     trace;
+extern  int     verbose;
+extern  int     rexmtval;
+extern  int     maxtimeout;
+extern int     segsize;
+
+#define PKTSIZE    (1432+4) /* SEGSIZE+4 */
+char    ackbuf[PKTSIZE];
+int    timeout;
+jmp_buf        toplevel;
+jmp_buf        timeoutbuf;
+
+#ifndef OACK
+#define OACK   6
+#endif
+
+void timer(int sig)
+{
+
+       signal(SIGALRM, timer);
+       timeout += rexmtval;
+       if (timeout >= maxtimeout) {
+               printf("Transfer timed out.\n");
+               longjmp(toplevel, -1);
+       }
+       longjmp(timeoutbuf, 1);
+}
+
+strnlen(s, n)
+       char *s;
+       int n;
+{
+       int i = 0;
+
+       while (n-- > 0 && *s++) i++;
+       return(i);
+}
+
+/*
+ * Parse an OACK package and set blocksize accordingly
+ */
+parseoack(cp, sz)
+       char *cp;
+       int sz;
+{
+       int n;
+       
+       segsize = 512;
+       while (sz > 0 && *cp) {
+               n = strnlen(cp, sz);
+               if (n == 7 && !strncmp("blksize", cp, 7)) {
+                       cp += 8;
+                       sz -= 8;
+                       if (sz <= 0)
+                               break;
+                       for (segsize = 0, n = strnlen(cp, sz); n > 0;
+                            n--, cp++, sz--) {
+                               if (*cp < '0' || *cp > '9')
+                                       break;
+                               segsize = 10*segsize + *cp - '0'; }
+               }
+               cp += n + 1;
+               sz -= n + 1;
+       }
+       if (segsize < 8 || segsize > 1432) {
+               printf("Remote host negotiated illegal blocksize %d\n",
+                      segsize);
+               segsize = 512;
+               longjmp(timeoutbuf, -1);
+       }
+}
+
+/*
+ * Send the requested file.
+ */
+sendfile(fd, name, mode)
+       int fd;
+       char *name;
+       char *mode;
+{
+       register struct tftphdr *ap;       /* data and ack packets */
+       struct tftphdr *r_init(), *dp;
+       register int size, n;
+       u_short block = 0;
+       register unsigned long amount = 0;
+       struct sockaddr_in from;
+       int fromlen;
+       int convert;            /* true if doing nl->crlf conversion */
+       FILE *file;
+
+       startclock();           /* start stat's clock */
+       dp = r_init();          /* reset fillbuf/read-ahead code */
+       ap = (struct tftphdr *)ackbuf;
+       file = fdopen(fd, "r");
+       convert = !strcmp(mode, "netascii");
+
+       signal(SIGALRM, timer);
+       do {
+               if (block == 0)
+                       size = makerequest(WRQ, name, dp, mode) - 4;
+               else {
+               /*      size = read(fd, dp->th_data, SEGSIZE);   */
+                       size = readit(file, &dp, convert);
+                       if (size < 0) {
+                               nak(errno + 100);
+                               break;
+                       }
+                       dp->th_opcode = htons((u_short)DATA);
+                       dp->th_block = htons(block);
+               }
+               timeout = 0;
+               (void) setjmp(timeoutbuf);
+send_data:
+               if (trace)
+                       tpacket("sent", dp, size + 4);
+               n = sendto(f, dp, size + 4, 0, (struct sockaddr *)&sin,
+                          sizeof (sin));
+               if (n != size + 4) {
+                       perror("tftp: sendto");
+                       goto abort;
+               }
+               if (block) /* do not start reading until the blocksize
+                             has been negotiated */
+                       read_ahead(file, convert);
+               for ( ; ; ) {
+                       alarm(rexmtval);
+                       do {
+                               fromlen = sizeof (from);
+                               n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
+                                            (struct sockaddr *)&from,
+                                            &fromlen);
+                       } while (n <= 0);
+                       alarm(0);
+                       if (n < 0) {
+                               perror("tftp: recvfrom");
+                               goto abort;
+                       }
+                       sin.sin_port = from.sin_port;   /* added */
+                       if (trace)
+                               tpacket("received", ap, n);
+                       /* should verify packet came from server */
+                       ap->th_opcode = ntohs(ap->th_opcode);
+                       if (ap->th_opcode == ERROR) {
+                               printf("Error code %d: %s\n", ap->th_code,
+                                       ap->th_msg);
+                               goto abort;
+                       }
+                       if (ap->th_opcode == ACK) {
+                               int j;
+
+                               ap->th_block = ntohs(ap->th_block);
+
+                               if (block == 0) {
+                                       if (trace)
+                                               printf("server does not know "
+                                                      "about RFC1782; reset"
+                                                      "ting blocksize\n");
+                                       segsize = 512;
+                               }
+                               if (ap->th_block == block) {
+                                       break;
+                               }
+                               /* On an error, try to synchronize
+                                * both sides.
+                                */
+                               j = synchnet(f);
+                               if (j && trace) {
+                                       printf("discarded %d packets\n",
+                                                       j);
+                               }
+                               if (ap->th_block == (block-1)) {
+                                       goto send_data;
+                               }
+                       }
+                       else if (ap->th_opcode == OACK) {
+                               if (block) {
+                                       printf("protocol violation\n");
+                                       longjmp(toplevel, -1);
+                               }
+                               parseoack(&ap->th_stuff, n - 2);
+                               break;
+                       }
+               }
+               if (block > 0)
+                       amount += size;
+               else
+                       read_ahead(file, convert);
+               block++;
+       } while (size == segsize || block == 1);
+abort:
+       fclose(file);
+       stopclock();
+       if (amount > 0)
+               printstats("Sent", amount);
+}
+
+/*
+ * Receive a file.
+ */
+recvfile(fd, name, mode)
+       int fd;
+       char *name;
+       char *mode;
+{
+       register struct tftphdr *ap;
+       struct tftphdr *dp, *w_init();
+       register int n, size;
+       u_short block = 1;
+       unsigned long amount = 0;
+       struct sockaddr_in from;
+       int fromlen, firsttrip = 1;
+       FILE *file;
+       int convert;                    /* true if converting crlf -> lf */
+       int waitforoack = 1;
+
+       startclock();
+       dp = w_init();
+       ap = (struct tftphdr *)ackbuf;
+       file = fdopen(fd, "w");
+       convert = !strcmp(mode, "netascii");
+
+       signal(SIGALRM, timer);
+       do {
+               if (firsttrip) {
+                       size = makerequest(RRQ, name, ap, mode);
+                       firsttrip = 0;
+               } else {
+                       ap->th_opcode = htons((u_short)ACK);
+                       ap->th_block = htons(block);
+                       size = 4;
+                       block++;
+               }
+               timeout = 0;
+               (void) setjmp(timeoutbuf);
+send_ack:
+               if (trace)
+                       tpacket("sent", ap, size);
+               if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&sin,
+                   sizeof (sin)) != size) {
+                       alarm(0);
+                       perror("tftp: sendto");
+                       goto abort;
+               }
+               if (!waitforoack)
+                       write_behind(file, convert);
+               for ( ; ; ) {
+                       alarm(rexmtval);
+                       do  {
+                               fromlen = sizeof (from);
+                               n = recvfrom(f, dp, PKTSIZE, 0,
+                                   (struct sockaddr *)&from, &fromlen);
+                       } while (n <= 0);
+                       alarm(0);
+                       if (n < 0) {
+                               perror("tftp: recvfrom");
+                               goto abort;
+                       }
+                       sin.sin_port = from.sin_port;   /* added */
+                       if (trace)
+                               tpacket("received", dp, n);
+                       /* should verify client address */
+                       dp->th_opcode = ntohs(dp->th_opcode);
+                       if (dp->th_opcode == ERROR) {
+                               printf("Error code %d: %s\n", dp->th_code,
+                                       dp->th_msg);
+                               goto abort;
+                       }
+                       if (dp->th_opcode == DATA) {
+                               int j;
+
+                               if (waitforoack) {
+                                       if (trace)
+                                               printf("server does not know "
+                                                      "about RFC1782; reset"
+                                                      "ting blocksize\n");
+                                       waitforoack = 0;
+                                       segsize = 512;
+                               }
+                               dp->th_block = ntohs(dp->th_block);
+                               if (dp->th_block == block) {
+                                       break;          /* have next packet */
+                               }
+                               /* On an error, try to synchronize
+                                * both sides.
+                                */
+                               j = synchnet(f);
+                               if (j && trace) {
+                                       printf("discarded %d packets\n", j);
+                               }
+                               if (dp->th_block == (block-1)) {
+                                       goto send_ack;  /* resend ack */
+                               }
+                       }
+                       else if (dp->th_opcode == OACK) {
+                               if (block != 1 || !waitforoack) {
+                                       printf("protocol violation\n");
+                                       longjmp(toplevel, -1);
+                               }
+                               waitforoack = 0;
+                               parseoack(&dp->th_stuff, n - 2);
+                               ap->th_opcode = htons((u_short)ACK);
+                               ap->th_block = htons(0);
+                               size = 4;
+                               goto send_ack;
+                       }
+               }
+               /* size = write(fd, dp->th_data, n - 4); */
+               size = writeit(file, &dp, n - 4, convert);
+               if (size < 0) {
+                       nak(errno + 100);
+                       break;
+               }
+               amount += size;
+       } while (size == segsize);
+abort:                                          /* ok to ack, since user */
+       ap->th_opcode = htons((u_short)ACK);    /* has seen err msg */
+       ap->th_block = htons(block);
+       (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&sin, sizeof (sin));
+       write_behind(file, convert);            /* flush last buffer */
+       fclose(file);
+       stopclock();
+       if (amount > 0)
+               printstats("Received", amount);
+}
+
+makerequest(request, name, tp, mode)
+       int request;
+       char *name, *mode;
+       struct tftphdr *tp;
+{
+       register char *cp;
+
+       tp->th_opcode = htons((u_short)request);
+       cp = tp->th_stuff;
+       strcpy(cp, name);
+       cp += strlen(name);
+       *cp++ = '\0';
+       strcpy(cp, mode);
+       cp += strlen(mode);
+       *cp++ = '\0';
+       strcpy(cp, "blksize");
+       cp += 7;
+       *cp++ = '\0';
+       sprintf(cp, "%d", segsize);
+       cp += strlen(cp) + 1;
+       return (cp - (char *)tp);
+}
+
+struct errmsg {
+       int     e_code;
+       const char      *e_msg;
+} errmsgs[] = {
+       { EUNDEF,       "Undefined error code" },
+       { ENOTFOUND,    "File not found" },
+       { EACCESS,      "Access violation" },
+       { ENOSPACE,     "Disk full or allocation exceeded" },
+       { EBADOP,       "Illegal TFTP operation" },
+       { EBADID,       "Unknown transfer ID" },
+       { EEXISTS,      "File already exists" },
+       { ENOUSER,      "No such user" },
+       { -1,           0 }
+};
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+nak(error)
+       int error;
+{
+       register struct tftphdr *tp;
+       int length;
+       register struct errmsg *pe;
+/*     extern char *sys_errlist[]; */
+
+       tp = (struct tftphdr *)ackbuf;
+       tp->th_opcode = htons((u_short)ERROR);
+       tp->th_code = htons((u_short)error);
+       for (pe = errmsgs; pe->e_code >= 0; pe++)
+               if (pe->e_code == error)
+                       break;
+       if (pe->e_code < 0) {
+               pe->e_msg = sys_errlist[error - 100];
+               tp->th_code = EUNDEF;
+       }
+       strcpy(tp->th_msg, pe->e_msg);
+       length = strlen(pe->e_msg) + 4;
+       if (trace)
+               tpacket("sent", tp, length);
+       if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&sin, sizeof (sin))
+           != length)
+               perror("nak");
+}
+
+topts(cp, sz)
+       char *cp;
+       int sz;
+{
+       int n, i = 0;
+       
+       while (sz > 0 && *cp) {
+               n = strnlen(cp, sz);
+               if (n > 0) {
+                       printf("%s%s=", i++ ? ", " : "", cp);
+                       cp += n + 1;
+                       sz -= n + 1;
+                       if (sz <= 0)
+                               break;
+                       n = strnlen(cp, sz);
+                       if (n > 0)
+                               printf("%s", cp);
+               }
+               cp += n + 1;
+               sz -= n + 1;
+       }
+}
+
+tpacket(s, tp, n)
+       char *s;
+       struct tftphdr *tp;
+       int n;
+{
+       static char *opcodes[] =
+          { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
+       register char *cp, *file;
+       u_short op = ntohs(tp->th_opcode);
+       char *index();
+
+       if (op < RRQ || op > OACK)
+               printf("%s opcode=%x ", s, op);
+       else
+               printf("%s %s ", s, opcodes[op]);
+       switch (op) {
+
+       case RRQ:
+       case WRQ:
+               n -= 2;
+               file = cp = tp->th_stuff;
+               cp = index(cp, '\0');
+               printf("<file=%s, mode=%s, opts: ", file, cp + 1);
+               topts(index(cp + 1, '\000') + 1, n - strlen(file)
+                     - strlen(cp + 1) - 2);
+               printf(">\n");
+               break;
+
+       case DATA:
+               printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
+               break;
+
+       case ACK:
+               printf("<block=%d>\n", ntohs(tp->th_block));
+               break;
+
+       case ERROR:
+               printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
+               break;
+       case OACK:
+               printf("<");
+               topts(tp->th_stuff, n - 2);
+               printf(">\n");
+               break;
+       }
+}
+
+struct timeval tstart;
+struct timeval tstop;
+struct timezone zone;
+
+startclock() {
+       gettimeofday(&tstart, &zone);
+}
+
+stopclock() {
+       gettimeofday(&tstop, &zone);
+}
+
+printstats(direction, amount)
+char *direction;
+unsigned long amount;
+{
+       double delta;
+                       /* compute delta in 1/10's second units */
+       delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
+               ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
+       delta = delta/10.;      /* back to seconds */
+       printf("%s %ld bytes in %.1f seconds", direction, amount, delta);
+       if ((verbose) && (delta >= 0.1))
+                       printf(" [%.0f bits/sec]", (amount*8.)/delta);
+       putchar('\n');
+}
+
diff --git a/contrib/tftp/tftpd.8 b/contrib/tftp/tftpd.8
new file mode 100644 (file)
index 0000000..6a154c1
--- /dev/null
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"    @(#)tftpd.8     6.3 (Berkeley) 9/20/88
+.\"
+.TH TFTPD 8 "September 20, 1988"
+.UC 5
+.SH NAME
+tftpd \- DARPA Trivial File Transfer Protocol server
+.SH SYNOPSIS
+.B /etc/tftpd
+[
+.SM \-c
+<rootdir> ] [
+.SM \-d
+] [
+.SM \-r
+<filter> ]
+.SH DESCRIPTION
+.I Tftpd
+is a server which supports the DARPA Trivial File Transfer
+Protocol.
+The TFTP server operates
+at the port indicated in the ``tftp'' service description;
+see
+.IR services (5).
+The server is normally started by
+.IR inetd (8).
+.PP
+The use of
+.I tftp
+does not require an account or password on the remote system.
+Due to the lack of authentication information, 
+.I tftpd
+will allow only publicly readable files to be
+accessed.
+Files may be written only if they already exist and are publicly writable.
+Note that this extends the concept of ``public'' to include
+all users on all hosts that can be reached through the network;
+this may not be appropriate on all systems, and its implications
+should be considered before enabling tftp service.
+The server should have the user ID with the lowest possible privilege.
+.SH OPTIONS
+.TP
+.B \-c
+Pathname of a directory that is considered the rootdirectory for all
+transfers. N.B.
+.I tftpd
+does not actually perform a
+.IR chroot (2)
+call; you should be aware of the security implications and you
+probably should run the server from an unpriviledged account.
+.TP
+.B \-d
+Increased debugging level.
+.TP
+.B \-r
+Pathname of a file that is considered to be a filter program. Whenever
+a client tries to download this file, the filter will be started and
+its output is send to the client. An arbitrary amount of these
+filters can be specified.
+.SH "SEE ALSO"
+tftp(1), inetd(8)
diff --git a/contrib/tftp/tftpd.c b/contrib/tftp/tftpd.c
new file mode 100644 (file)
index 0000000..325a713
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tftpd.c    5.8 (Berkeley) 6/18/88";
+#endif /* not lint */
+
+/*
+ * Trivial file transfer protocol server.
+ *
+ * This version includes many modifications by Jim Guyton <guyton@rand-unix>
+ *
+ * Further modifications by Markus Gutschke <gutschk@math.uni-muenster.de>
+ *  - RFC1782 option parsing
+ *  - RFC1783 extended blocksize
+ *  - "-c" option for changing the root directory
+ *  - "-d" option for debugging output
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <arpa/tftp.h>
+
+#include <alloca.h>
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <setjmp.h>
+#include <syslog.h>
+
+#define        TIMEOUT         5
+
+#ifndef        OACK
+#define        OACK    06
+#endif
+
+#ifndef EOPTNEG
+#define        EOPTNEG 8
+#endif
+
+extern int errno;
+struct sockaddr_in sin = { AF_INET };
+int    peer;
+int    rexmtval = TIMEOUT;
+int    maxtimeout = 5*TIMEOUT;
+
+#define        PKTSIZE (1432+4) /* SEGSIZE+4 */
+int    segsize = SEGSIZE;
+char   buf[PKTSIZE];
+char   ackbuf[PKTSIZE];
+struct sockaddr_in from;
+int    fromlen;
+
+char   *rootdir = NULL;
+int    debug = 0;
+
+struct filters {
+       struct filters *next;
+       char           *fname;
+} *filters = NULL;
+int     isfilter = 0;
+
+main(argc, argv)
+       char *argv[];
+{
+       register struct tftphdr *tp;
+       register int n;
+       int on = 1;
+       extern int optind;
+       extern char *optarg;
+
+       openlog(argv[0], LOG_PID, LOG_DAEMON);
+
+       while ((n = getopt(argc, argv, "c:dr:")) >= 0) {
+               switch (n) {
+               case 'c':
+                       if (rootdir)
+                               goto usage;
+                       rootdir = optarg;
+                       break;
+               case 'd':
+                       debug++;
+                       break;
+               case 'r': {
+                       struct filters *fp = (void *)
+                                            malloc(sizeof(struct filters) +
+                                                   strlen(optarg) + 1);
+                       fp->next  = filters;
+                       fp->fname = (char *)(fp + 1);
+                       strcpy(fp->fname, optarg);
+                       filters   = fp;
+                       break; }
+               default:
+               usage:
+                       syslog(LOG_ERR, "Usage: %s [-c chroot] "
+                              "[-r readfilter] [-d]\n",
+                              argv[0]);
+                       exit(1);
+               }
+       }
+       if (argc-optind != 0)
+               goto usage;
+
+       ioctl(0, FIONBIO, &on);
+/*     if (ioctl(0, FIONBIO, &on) < 0) {
+               syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
+               exit(1);
+       }
+*/
+       fromlen = sizeof (from);
+       n = recvfrom(0, buf, segsize+4, 0,
+           (struct sockaddr *)&from, &fromlen);
+       if (n < 0) {
+               syslog(LOG_ERR, "recvfrom: %m\n");
+               exit(1);
+       }
+       /*
+        * Now that we have read the message out of the UDP
+        * socket, we fork and exit.  Thus, inetd will go back
+        * to listening to the tftp port, and the next request
+        * to come in will start up a new instance of tftpd.
+        *
+        * We do this so that inetd can run tftpd in "wait" mode.
+        * The problem with tftpd running in "nowait" mode is that
+        * inetd may get one or more successful "selects" on the
+        * tftp port before we do our receive, so more than one
+        * instance of tftpd may be started up.  Worse, if tftpd
+        * break before doing the above "recvfrom", inetd would
+        * spawn endless instances, clogging the system.
+        */
+       {
+               int pid;
+               int i, j;
+
+               for (i = 1; i < 20; i++) {
+                   pid = fork();
+                   if (pid < 0) {
+                               sleep(i);
+                               /*
+                                * flush out to most recently sent request.
+                                *
+                                * This may drop some request, but those
+                                * will be resent by the clients when
+                                * they timeout.  The positive effect of
+                                * this flush is to (try to) prevent more
+                                * than one tftpd being started up to service
+                                * a single request from a single client.
+                                */
+                               j = sizeof from;
+                               i = recvfrom(0, buf, segsize+4, 0,
+                                   (struct sockaddr *)&from, &j);
+                               if (i > 0) {
+                                       n = i;
+                                       fromlen = j;
+                               }
+                   } else {
+                               break;
+                   }
+               }
+               if (pid < 0) {
+                       syslog(LOG_ERR, "fork: %m\n");
+                       exit(1);
+               } else if (pid != 0) {
+                       exit(0);
+               }
+       }
+       from.sin_family = AF_INET;
+       alarm(0);
+       close(0);
+       close(1);
+       peer = socket(AF_INET, SOCK_DGRAM, 0);
+       if (peer < 0) {
+               syslog(LOG_ERR, "socket: %m\n");
+               exit(1);
+       }
+       if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+               syslog(LOG_ERR, "bind: %m\n");
+               exit(1);
+       }
+       if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
+               syslog(LOG_ERR, "connect: %m\n");
+               exit(1);
+       }
+       tp = (struct tftphdr *)buf;
+       tp->th_opcode = ntohs(tp->th_opcode);
+       if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
+               tftp(tp, n);
+       exit(1);
+}
+
+int    validate_access();
+int    sendfile(), recvfile();
+
+struct formats {
+       char    *f_mode;
+       int     (*f_validate)();
+       int     (*f_send)();
+       int     (*f_recv)();
+       int     f_convert;
+} formats[] = {
+       { "netascii",   validate_access,        sendfile,       recvfile, 1 },
+       { "octet",      validate_access,        sendfile,       recvfile, 0 },
+#ifdef notdef
+       { "mail",       validate_user,          sendmail,       recvmail, 1 },
+#endif
+       { 0 }
+};
+
+int    set_blksize();
+
+struct options {
+       char    *o_opt;
+       int     (*o_fnc)();
+} options[] = {
+       { "blksize",    set_blksize },
+       { 0 }
+};
+
+/*
+ * Set a non-standard block size (c.f. RFC1783)
+ */
+
+set_blksize(val, ret)
+       char *val;
+       char **ret;
+{
+       static char b_ret[5];
+       int sz = atoi(val);
+
+       if (sz < 8) {
+               if (debug)
+                       syslog(LOG_ERR, "Requested packetsize %d < 8\n", sz);
+               return(0);
+       } else if (sz > PKTSIZE-4) {
+               if (debug)
+                       syslog(LOG_INFO, "Requested packetsize %d > %d\n",
+                              sz, PKTSIZE-4);
+               sz = PKTSIZE-4;
+       } else if (debug)
+               syslog(LOG_INFO, "Adjusted packetsize to %d octets\n", sz);
+       
+       segsize = sz;
+       sprintf(*ret = b_ret, "%d", sz);
+       return(1);
+}
+
+/*
+ * Parse RFC1782 style options
+ */
+
+do_opt(opt, val, ap)
+       char *opt;
+       char *val;
+       char **ap;
+{
+       struct options *po;
+       char *ret;
+
+       for (po = options; po->o_opt; po++)
+               if (strcasecmp(po->o_opt, opt) == 0) {
+                       if (po->o_fnc(val, &ret)) {
+                               if (*ap + strlen(opt) + strlen(ret) + 2 >=
+                                   ackbuf + sizeof(ackbuf)) {
+                                       if (debug)
+                                               syslog(LOG_ERR,
+                                                      "Ackbuf overflow\n");
+                                       nak(ENOSPACE);
+                                       exit(1);
+                               }
+                               *ap = strrchr(strcpy(strrchr(strcpy(*ap, opt),
+                                                            '\000')+1, val),
+                                             '\000')+1;
+                       } else {
+                               nak(EOPTNEG);
+                               exit(1);
+                       }
+                       break;
+               }
+       if (debug && !po->o_opt)
+               syslog(LOG_WARNING, "Unhandled option: %d = %d\n", opt, val);
+       return;
+}
+
+/*
+ * Handle initial connection protocol.
+ */
+tftp(tp, size)
+       struct tftphdr *tp;
+       int size;
+{
+       register char *cp;
+       int argn = 0, ecode;
+       register struct formats *pf;
+       char *filename, *mode;
+       char *val, *opt;
+       char *ap = ackbuf+2;
+       int  isopts;
+
+       ((struct tftphdr *)ackbuf)->th_opcode = ntohs(OACK);
+       filename = cp = tp->th_stuff;
+again:
+       while (cp < buf + size) {
+               if (*cp == '\0')
+                       break;
+               cp++;
+       }
+       if (*cp != '\0') {
+               if (debug)
+                       syslog(LOG_WARNING, "Received illegal request\n");
+               nak(EBADOP);
+               exit(1);
+       }
+       if (!argn++) {
+               mode = ++cp;
+               goto again;
+       } else {
+               if (debug && argn == 3)
+                       syslog(LOG_INFO, "Found RFC1782 style options\n");
+               *(argn & 1 ? &val : &opt) = ++cp;
+               if (argn & 1)
+                       do_opt(opt, val, &ap);
+               if (cp < buf + size && *cp != '\000')
+                       goto again;
+       }
+       
+       for (cp = mode; *cp; cp++)
+               if (isupper(*cp))
+                       *cp = tolower(*cp);
+       for (pf = formats; pf->f_mode; pf++)
+               if (strcmp(pf->f_mode, mode) == 0)
+                       break;
+       if (pf->f_mode == 0) {
+               if (debug)
+                       syslog(LOG_WARNING, "Unknown data format: %s\n", mode);
+               nak(EBADOP);
+               exit(1);
+       }
+
+       if (rootdir) {
+               cp = alloca(strlen(rootdir) + strlen(filename) + 1);
+               if (cp == NULL) {
+                       nak(100+ENOMEM);
+                       exit(1);
+               }
+               if (*filename != '/') {
+                       if (debug)
+                               syslog(LOG_ERR,
+                                      "Filename has to be absolute: %s\n",
+                                      filename);
+                       nak(EACCESS);
+                       exit(1);
+               }
+               filename = strcat(strcpy(cp, rootdir), filename);
+       }
+       
+       ecode = (*pf->f_validate)(filename, tp->th_opcode);
+       if (ecode) {
+               nak(ecode, ERROR);
+               exit(1);
+       }
+       isopts = ap != (ackbuf+2);
+       (tp->th_opcode == WRQ ? *pf->f_recv : *pf->f_send)
+               (pf, isopts ? ackbuf : NULL, isopts ? ap-ackbuf : 0);
+       exit(0);
+}
+
+
+FILE *file;
+
+/*
+ * Validate file access.  Since we
+ * have no uid or gid, for now require
+ * file to exist and be publicly
+ * readable/writable.
+ * Note also, full path name must be
+ * given as we have no login directory.
+ */
+validate_access(filename, mode)
+       char *filename;
+       int mode;
+{
+       struct stat stbuf;
+       int     fd;
+       char    *cp;
+
+       isfilter = 0;
+       if (mode == RRQ) {
+               struct filters *fp = filters;
+               for (; fp; fp = fp->next) {
+                       if (!strcmp(fp->fname,
+                                   filename +
+                                   (rootdir ? strlen(rootdir) : 0))) {
+                               if (debug)
+                                       syslog(LOG_INFO, "Opening input "
+                                              "filter: %s\n", filename);
+                               if ((file = popen(filename, "r")) == NULL) {
+                                       syslog(LOG_ERR, "Failed to open input "
+                                              "filter\n");
+                                       return (EACCESS); }
+                               fd = fileno(file);
+                               isfilter = 1;
+                               return (0);
+                       }
+               }
+       }
+                                      
+       if (*filename != '/') {
+               if (debug)
+                       syslog(LOG_ERR, "Filename has to be absolute: %s\n",
+                              filename);
+               return (EACCESS);
+       }
+       for (cp = filename; *cp; cp++)
+               if (*cp == '~' || *cp == '$' ||
+                   (*cp == '/' && cp[1] == '.' && cp[2] == '.')) {
+                       if (debug)
+                               syslog(LOG_ERR, "Illegal filename: %s\n",
+                                      filename);
+                       return (EACCESS);
+               }
+       if (debug)
+               syslog(LOG_INFO, "Validating \"%s\" for %sing\n",
+                      filename, mode == RRQ ? "read" : "writ");
+       if (stat(filename, &stbuf) < 0)
+               return (errno == ENOENT ? ENOTFOUND : EACCESS);
+       if (mode == RRQ) {
+               if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
+                       return (EACCESS);
+       } else {
+               if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
+                       return (EACCESS);
+       }
+       fd = open(filename, mode == RRQ ? 0 : 1);
+       if (fd < 0)
+               return (errno + 100);
+       file = fdopen(fd, (mode == RRQ)? "r":"w");
+       if (file == NULL) {
+               return errno+100;
+       }
+       return (0);
+}
+
+int    timeout;
+jmp_buf        timeoutbuf;
+
+void timer(int sig)
+{
+
+       timeout += rexmtval;
+       if (timeout >= maxtimeout) {
+               if (debug)
+                       syslog(LOG_WARNING, "Timeout!\n");
+               exit(1);
+       }
+       longjmp(timeoutbuf, 1);
+}
+
+/*
+ * Send the requested file.
+ */
+sendfile(pf, oap, oacklen)
+       struct formats *pf;
+       struct tftphdr *oap;
+       int oacklen;
+{
+       struct tftphdr *dp, *r_init();
+       register struct tftphdr *ap;    /* ack packet */
+       register int size, n;
+       u_short block = 1;
+
+       signal(SIGALRM, timer);
+
+       ap = (struct tftphdr *)ackbuf;
+
+       if (oap) {
+               timeout = 0;
+               (void) setjmp(timeoutbuf);
+       oack:
+               if (send(peer, oap, oacklen, 0) != oacklen) {
+                       syslog(LOG_ERR, "tftpd: write: %m\n");
+                       goto abort;
+               }
+               for ( ; ; ) {
+                       alarm(rexmtval);
+                       n = recv(peer, ackbuf, sizeof (ackbuf), 0);
+                       alarm(0);
+                       if (n < 0) {
+                               syslog(LOG_ERR, "tftpd: read: %m\n");
+                               goto abort;
+                       }
+                       ap->th_opcode = ntohs((u_short)ap->th_opcode);
+                       ap->th_block = ntohs(ap->th_block);
+                       
+                       if (ap->th_opcode == ERROR) {
+                               if (debug)
+                                       syslog(LOG_ERR, "Client does not "
+                                              "accept options\n");
+                               goto abort; }
+                       
+                       if (ap->th_opcode == ACK) {
+                               if (ap->th_block == 0) {
+                                       if (debug)
+                                               syslog(LOG_DEBUG,
+                                                      "RFC1782 option "
+                                                      "negotiation "
+                                                      "succeeded\n");
+                                       break;
+                               }
+                               /* Re-synchronize with the other side */
+                               (void) synchnet(peer);
+                               goto oack;
+                       }
+               }
+       }
+       
+       dp = r_init();
+       do {
+               size = readit(file, &dp, pf->f_convert);
+               if (size < 0) {
+                       nak(errno + 100);
+                       goto abort;
+               }
+               dp->th_opcode = htons((u_short)DATA);
+               dp->th_block = htons(block);
+               timeout = 0;
+               (void) setjmp(timeoutbuf);
+
+send_data:
+               if (send(peer, dp, size + 4, 0) != size + 4) {
+                       syslog(LOG_ERR, "tftpd: write: %m\n");
+                       goto abort;
+               }
+               read_ahead(file, pf->f_convert);
+               for ( ; ; ) {
+                       alarm(rexmtval);        /* read the ack */
+                       n = recv(peer, ackbuf, sizeof (ackbuf), 0);
+                       alarm(0);
+                       if (n < 0) {
+                               syslog(LOG_ERR, "tftpd: read: %m\n");
+                               goto abort;
+                       }
+                       ap->th_opcode = ntohs((u_short)ap->th_opcode);
+                       ap->th_block = ntohs(ap->th_block);
+
+                       if (ap->th_opcode == ERROR)
+                               goto abort;
+                       
+                       if (ap->th_opcode == ACK) {
+                               if (ap->th_block == block) {
+                                       break;
+                               }
+                               /* Re-synchronize with the other side */
+                               (void) synchnet(peer);
+                               if (ap->th_block == (block -1)) {
+                                       goto send_data;
+                               }
+                       }
+
+               }
+               block++;
+       } while (size == segsize);
+abort:
+       if (isfilter)
+               pclose(file);
+       else
+               (void) fclose(file);
+       isfilter = 0;
+}
+
+void justquit(int sig)
+{
+       exit(0);
+}
+
+
+/*
+ * Receive a file.
+ */
+recvfile(pf, oap, oacklen)
+       struct formats *pf;
+       struct tftphdr *oap;
+       int oacklen;
+{
+       struct tftphdr *dp, *w_init();
+       register struct tftphdr *ap;    /* ack buffer */
+       register int acksize, n, size;
+       u_short block = 0;
+
+       signal(SIGALRM, timer);
+       dp = w_init();
+       do {
+               timeout = 0;
+
+               if (!block++ && oap) {
+                       ap = (struct tftphdr *)oap;
+                       acksize = oacklen;
+               } else {
+                       ap = (struct tftphdr *)ackbuf;
+                       ap->th_opcode = htons((u_short)ACK);
+                       ap->th_block = htons(block-1);
+                       acksize = 4;
+               }
+               (void) setjmp(timeoutbuf);
+send_ack:
+               if (send(peer, (char *)ap, acksize, 0) != acksize) {
+                       syslog(LOG_ERR, "tftpd: write: %m\n");
+                       goto abort;
+               }
+               write_behind(file, pf->f_convert);
+               for ( ; ; ) {
+                       alarm(rexmtval);
+                       n = recv(peer, dp, segsize+4, 0);
+                       alarm(0);
+                       if (n < 0) {            /* really? */
+                               syslog(LOG_ERR, "tftpd: read: %m\n");
+                               goto abort;
+                       }
+                       dp->th_opcode = ntohs((u_short)dp->th_opcode);
+                       dp->th_block = ntohs(dp->th_block);
+                       if (dp->th_opcode == ERROR)
+                               goto abort;
+                       if (dp->th_opcode == DATA) {
+                               if (dp->th_block == block) {
+                                       break;   /* normal */
+                               }
+                               /* Re-synchronize with the other side */
+                               (void) synchnet(peer);
+                               if (dp->th_block == (block-1))
+                                       goto send_ack;          /* rexmit */
+                       }
+               }
+               /*  size = write(file, dp->th_data, n - 4); */
+               size = writeit(file, &dp, n - 4, pf->f_convert);
+               if (size != (n-4)) {                    /* ahem */
+                       if (size < 0) nak(errno + 100);
+                       else nak(ENOSPACE);
+                       goto abort;
+               }
+       } while (size == segsize);
+       write_behind(file, pf->f_convert);
+       if (isfilter)
+               pclose(file);
+       else
+               (void) fclose(file);            /* close data file */
+       isfilter = 0;
+
+       ap = (struct tftphdr *)ackbuf;
+       ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
+       ap->th_block = htons(block);
+       (void) send(peer, ackbuf, 4, 0);
+
+       signal(SIGALRM, justquit);      /* just quit on timeout */
+       alarm(rexmtval);
+       n = recv(peer, buf, segsize, 0); /* normally times out and quits */
+       alarm(0);
+       if (n >= 4 &&                   /* if read some data */
+           dp->th_opcode == DATA &&    /* and got a data block */
+           block == dp->th_block) {    /* then my last ack was lost */
+               (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
+       }
+abort:
+       return;
+}
+
+struct errmsg {
+       int     e_code;
+       const char      *e_msg;
+} errmsgs[] = {
+       { EUNDEF,       "Undefined error code" },
+       { ENOTFOUND,    "File not found" },
+       { EACCESS,      "Access violation" },
+       { ENOSPACE,     "Disk full or allocation exceeded" },
+       { EBADOP,       "Illegal TFTP operation" },
+       { EBADID,       "Unknown transfer ID" },
+       { EEXISTS,      "File already exists" },
+       { ENOUSER,      "No such user" },
+       { EOPTNEG,      "Failure to negotiate RFC1782 options" },
+       { -1,           0 }
+};
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+nak(error)
+       int error;
+{
+       register struct tftphdr *tp;
+       int length;
+       register struct errmsg *pe;
+/*     extern char *sys_errlist[];     */
+
+       tp = (struct tftphdr *)buf;
+       tp->th_opcode = htons((u_short)ERROR);
+       tp->th_code = htons((u_short)error);
+       for (pe = errmsgs; pe->e_code >= 0; pe++)
+               if (pe->e_code == error)
+                       break;
+       if (pe->e_code < 0) {
+               pe->e_msg = sys_errlist[error -100];
+               tp->th_code = EUNDEF;   /* set 'undef' errorcode */
+       }
+       strcpy(tp->th_msg, pe->e_msg);
+       length = strlen(pe->e_msg);
+       tp->th_msg[length] = '\0';
+       length += 5;
+       if (debug)
+               syslog(LOG_ERR, "Negative acknowledge: %s\n", tp->th_msg);
+       if (send(peer, buf, length, 0) != length)
+               syslog(LOG_ERR, "nak: %m\n");
+}
diff --git a/contrib/tftp/tftpsubs.c b/contrib/tftp/tftpsubs.c
new file mode 100644 (file)
index 0000000..608d64e
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tftpsubs.c 5.4 (Berkeley) 6/29/88";
+#endif /* not lint */
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+   server.  Written originally with multiple buffers in mind, but current
+   implementation has two buffer logic wired in.
+
+   Todo:  add some sort of final error check so when the write-buffer
+   is finally flushed, the caller can detect if the disk filled up
+   (or had an i/o error) and return a nak to the other side.
+
+                       Jim Guyton 10/85
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+#include <stdio.h>
+
+#define PKTSIZE (1432+4) /* SEGSIZE+4 */      /* should be moved to tftp.h */
+
+struct bf {
+       int counter;            /* size of data in buffer, or flag */
+       char buf[PKTSIZE];      /* room for data packet */
+} bfs[2];
+
+                               /* Values for bf.counter  */
+#define BF_ALLOC -3             /* alloc'd but not yet filled */
+#define BF_FREE  -2             /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+extern int segsize;
+
+static int nextone;     /* index of next buffer to use */
+static int current;     /* index of buffer in use */
+
+                       /* control flags for crlf conversions */
+int newline = 0;        /* fillbuf: in middle of newline expansion */
+int prevchar = -1;      /* putbuf: previous char (cr check) */
+
+struct tftphdr *rw_init();
+
+struct tftphdr *w_init() { return rw_init(0); }         /* write-behind */
+struct tftphdr *r_init() { return rw_init(1); }         /* read-ahead */
+
+struct tftphdr *
+rw_init(x)              /* init for either read-ahead or write-behind */
+int x;                  /* zero for write-behind, one for read-head */
+{
+       newline = 0;            /* init crlf flag */
+       prevchar = -1;
+       bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */
+       current = 0;
+       bfs[1].counter = BF_FREE;
+       nextone = x;                    /* ahead or behind? */
+       return (struct tftphdr *)bfs[0].buf;
+}
+
+
+/* Have emptied current buffer by sending to net and getting ack.
+   Free it and return next buffer filled with data.
+ */
+readit(file, dpp, convert)
+       FILE *file;                     /* file opened for read */
+       struct tftphdr **dpp;
+       int convert;                    /* if true, convert to ascii */
+{
+       struct bf *b;
+
+       bfs[current].counter = BF_FREE; /* free old one */
+       current = !current;             /* "incr" current */
+
+       b = &bfs[current];              /* look at new buffer */
+       if (b->counter == BF_FREE)      /* if it's empty */
+               read_ahead(file, convert);      /* fill it */
+/*      assert(b->counter != BF_FREE);  /* check */
+       *dpp = (struct tftphdr *)b->buf;        /* set caller's ptr */
+       return b->counter;
+}
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are  lf -> cr,lf  and cr -> cr, nul
+ */
+read_ahead(file, convert)
+       FILE *file;                     /* file opened for read */
+       int convert;                    /* if true, convert to ascii */
+{
+       register int i;
+       register char *p;
+       register int c;
+       struct bf *b;
+       struct tftphdr *dp;
+
+       b = &bfs[nextone];              /* look at "next" buffer */
+       if (b->counter != BF_FREE)      /* nop if not free */
+               return;
+       nextone = !nextone;             /* "incr" next buffer ptr */
+
+       dp = (struct tftphdr *)b->buf;
+
+       if (convert == 0) {
+               int i;
+               b->counter = 0;
+               do {
+                       i = read(fileno(file), dp->th_data + b->counter,
+                                segsize - b->counter);
+                       if (i > 0)
+                               b->counter += i;
+               } while (i != 0 && !(i < 0 && errno != EINTR) &&
+                        b->counter < segsize);
+               return;
+       }
+
+       p = dp->th_data;
+       for (i = 0 ; i < segsize; i++) {
+               if (newline) {
+                       if (prevchar == '\n')
+                               c = '\n';       /* lf to cr,lf */
+                       else    c = '\0';       /* cr to cr,nul */
+                       newline = 0;
+               }
+               else {
+                       c = getc(file);
+                       if (c == EOF) break;
+                       if (c == '\n' || c == '\r') {
+                               prevchar = c;
+                               c = '\r';
+                               newline = 1;
+                       }
+               }
+              *p++ = c;
+       }
+       b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+   from the queue.  Calls write_behind only if next buffer not
+   available.
+ */
+writeit(file, dpp, ct, convert)
+       FILE *file;
+       struct tftphdr **dpp;
+       int convert;
+{
+       bfs[current].counter = ct;      /* set size of data to write */
+       current = !current;             /* switch to other buffer */
+       if (bfs[current].counter != BF_FREE)     /* if not free */
+               write_behind(file, convert);     /* flush it */
+       bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
+       *dpp =  (struct tftphdr *)bfs[current].buf;
+       return ct;                      /* this is a lie of course */
+}
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR  and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else.  In this case we leave it alone.
+ */
+write_behind(file, convert)
+       FILE *file;
+       int convert;
+{
+       char *buf;
+       int count;
+       register int ct;
+       register char *p;
+       register int c;                 /* current character */
+       struct bf *b;
+       struct tftphdr *dp;
+
+       b = &bfs[nextone];
+       if (b->counter < -1)            /* anything to flush? */
+               return 0;               /* just nop if nothing to do */
+
+       count = b->counter;             /* remember byte count */
+       b->counter = BF_FREE;           /* reset flag */
+       dp = (struct tftphdr *)b->buf;
+       nextone = !nextone;             /* incr for next time */
+       buf = dp->th_data;
+
+       if (count <= 0) return -1;      /* nak logic? */
+
+       if (convert == 0)
+               return write(fileno(file), buf, count);
+
+       p = buf;
+       ct = count;
+       while (ct--) {                  /* loop over the buffer */
+           c = *p++;                   /* pick up a character */
+           if (prevchar == '\r') {     /* if prev char was cr */
+               if (c == '\n')          /* if have cr,lf then just */
+                  fseek(file, -1, 1);  /* smash lf on top of the cr */
+               else
+                  if (c == '\0')       /* if have cr,nul then */
+                       goto skipit;    /* just skip over the putc */
+               /* else just fall through and allow it */
+           }
+           putc(c, file);
+skipit:
+           prevchar = c;
+       }
+       return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch.  Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+int
+synchnet(f)
+int    f;              /* socket to flush */
+{
+       int i, j = 0;
+       char rbuf[PKTSIZE];
+       struct sockaddr_in from;
+       int fromlen;
+
+       while (1) {
+               (void) ioctl(f, FIONREAD, &i);
+               if (i) {
+                       j++;
+                       fromlen = sizeof from;
+                       (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+                               (struct sockaddr *)&from, &fromlen);
+               } else {
+                       return(j);
+               }
+       }
+}
diff --git a/contrib/tomsrtbt/tomsrtbt-net.txt b/contrib/tomsrtbt/tomsrtbt-net.txt
new file mode 100644 (file)
index 0000000..c5e1b0f
--- /dev/null
@@ -0,0 +1,37 @@
+Notes on turning tomsrtbt El Torito into a Etherboot image:
+
+0. Tomsrtbt (http://www.toms.net/) is an all-purpose rescue and utility
+1-floppy Linux system. You can read all about it at the web site. These
+notes explain how to turn the El Torito version of it into a netbootable
+image for Etherboot.  Note that the .img file is not an ISO image, it is
+a 2.88M floppy emulation image for writing onto a CD-R(W) with mkisofs.
+It's actually a minix filesystem.  Inside it are the kernel bz2bzImage
+and initrd.bz2.
+
+1. First uncompress the .img:
+
+       bunzip2 tomsrtbt-2.0.103.ElTorito.288.img.bz2
+
+2. Mount the image using loopback. You probably need to be root to do
+this:
+
+       mount -o ro,loop tomsrtbt-2.0.103.ElTorito.288.img /media/floppy
+
+I've specified /media/floppy which is the floppy mount point for my
+system, but any convenient directory will do.
+
+3. Copy the kernel image and initrd off it:
+
+       cp -p /media/floppy/bz2bzImage /media/floppy/initrd.bz2 .
+
+4. Use mkelf-linux (or mknbi-linux) to make a netbootable image:
+
+mkelf-linux --append='root=100' bz2bzImage initrd.bz2 > tomsrtbt.nb
+
+root=100 means use /dev/ram0 (device 1,0) as the root device.
+
+5. That's it. Clean up by unmounting the .img:
+
+       umount /media/cdrom
+
+tomsrtbt.nb can now be loaded with Etherboot. Have fun.
diff --git a/contrib/wakeonlan/Makefile b/contrib/wakeonlan/Makefile
new file mode 100644 (file)
index 0000000..563faa9
--- /dev/null
@@ -0,0 +1,37 @@
+## Makefile for use with gnu make and MinGW32 gnu gcc
+
+TARGET=wol
+
+CC=gcc
+LD=gcc
+
+CPPFLAGS= -Wall -O2
+LFLAGS= -s
+
+#LIBFILES= -lwsock
+#LIBPATH= -L/usr/lib
+
+ICON=$(TARGET).ico
+OBJS=$(TARGET).o
+RESF=$(TARGET).rc
+
+#RESNAME=$(TARGET).res
+#BINNAME=$(TARGET).exe
+BINNAME=$(TARGET)
+
+$(BINNAME): $(OBJS) $(RESNAME)
+       $(LD) $(LFLAGS) -o $@ $^ $(LIBPATH) $(LIBFILES)
+
+%.res:%.rc
+       windres -I rc -O coff -i $< -o $@
+
+%.rc:Makefile
+       @echo 100 ICON "$(ICON)" > $@
+
+dist:$(BINNAME)
+       rm -f $(OBJS) $(RESNAME) $(RESF)
+
+clean:
+       rm -f $(OBJS) $(RESNAME) $(RESF)
+       rm -f $(BINNAME)
+
diff --git a/contrib/wakeonlan/README b/contrib/wakeonlan/README
new file mode 100644 (file)
index 0000000..03b7e61
--- /dev/null
@@ -0,0 +1,3 @@
+Here are two programs to send Wake-On-LAN packets to a dormant workstation
+using the WOL feature. Please contact the respective authors for any
+queries.
diff --git a/contrib/wakeonlan/maclist.txt b/contrib/wakeonlan/maclist.txt
new file mode 100644 (file)
index 0000000..b96b3e4
--- /dev/null
@@ -0,0 +1,9 @@
+# maclist - mac addresses for wakeonlan
+00:BA:BE:FA:CE:00 mainframe
+00:11:22:33:44:5A maschine1
+00:11:22:33:44:B5 maschine2
+00:11:22:33:44:5C maschine3
+0A:BB:CC:DD:EE:F9 macintosh
+1A:BB:CC:DD:E6:FF 
+3A:BB:CC:DD:EE:F5 testpc
+3A:BB:CC:DD:EE:F6 123.45.6.7
diff --git a/contrib/wakeonlan/mp-form.pl b/contrib/wakeonlan/mp-form.pl
new file mode 100644 (file)
index 0000000..144b507
--- /dev/null
@@ -0,0 +1,172 @@
+#!/perl/bin/perl -w\r
+# Magic Packet for the Web\r
+# Perl version by ken.yap@acm.org after DOS/Windows C version posted by\r
+# Steve_Marfisi@3com.com on the Netboot mailing list\r
+# modified to work with web by G. Knauf <info@gknw.de>\r
+# Released under GNU Public License\r
+#\r
+use CGI qw(:standard); # import shortcuts\r
+use Socket;\r
+\r
+$ver = 'v0.52 &copy; gk 2003-Apr-24 11:00:00';\r
+\r
+# Defaults - Modify to point to the location of your mac file\r
+$www = "$ENV{'DOCUMENT_ROOT'}/perldemo";\r
+$maclist = "$www/maclist.txt";\r
+# Defaults - Modify to fit to your network\r
+$defbc = '255.255.255.255';\r
+$port = 60000;\r
+\r
+MAIN:\r
+{\r
+  # Read in all the variables set by the form\r
+  if (param()) {\r
+    &process_form();\r
+  } else {\r
+    &print_form();\r
+  }\r
+}\r
+\r
+sub process_form {\r
+  # Print the header\r
+  print header();\r
+  print start_html("Mp-Form - send Magic Packets");\r
+  # If defined new mac save it\r
+  if (defined(param("mac"))) {\r
+    print h1("Result of adding an entry to the maclist");\r
+    print '<HR><H3><TT>';\r
+    &add_entry();\r
+    print '</TT></H3><HR>';\r
+    print '<FORM method="POST"><input type="submit" value="ok"></FORM>';\r
+  } else {\r
+    # send magic packets to selected macs\r
+    print h1("Result of sending magic packets to multiple PCs");\r
+    print '<HR><H3><TT>';\r
+    if (param("all")) {\r
+      &process_file(S);\r
+    } else {\r
+      for (param()) {\r
+        my ($brc,$mac) = split(/-/,param($_)); \r
+        &send_broadcast_packet(inet_aton($brc),$mac);\r
+      }\r
+    }\r
+    print '</TT></H3><HR>';\r
+    print '<FORM><input type="button" value="back" onClick="history.back()"></FORM>';\r
+  }\r
+  # Close the document cleanly.\r
+  print end_html;\r
+}\r
+\r
+sub print_form {\r
+  # Print the header\r
+  print header();\r
+  print start_html("Mp-Form - send Magic Packets");\r
+  print h1("Form for sending magic packets to multiple PCs");\r
+  print <<ENDOFTEXT;\r
+<HR>\r
+<FORM method="POST">\r
+<H2>Select the destination mac addresses:</H2>\r
+<TABLE BORDER COLS=3 WIDTH="80%">\r
+<TR>\r
+<TD><CENTER><B><FONT SIZE="+1">Broadcast address</FONT></B></CENTER></TD>\r
+<TD><CENTER><B><FONT SIZE="+1">MAC address</FONT></B></CENTER></TD>\r
+<TD><CENTER><B><FONT SIZE="+1">Name</FONT></B></CENTER></TD>\r
+<TD><CENTER><B><FONT SIZE="+1"><input type=checkbox name="all" value="all">Select all</FONT></B></CENTER></TD>\r
+</TR>\r
+ENDOFTEXT\r
+  # build up table with mac addresses\r
+  &process_file(R);\r
+  # print rest of the form\r
+  print <<ENDOFTEXT;\r
+</TABLE>\r
+<P><B><FONT SIZE="+1">\r
+Press <input type="submit" value="wakeup"> to send the magic packets to your selections. \r
+Press <input type="reset" value="clear"> to reset the form.\r
+</FONT></B>\r
+</FORM>\r
+<HR>\r
+<FORM method="POST">\r
+<H2>Enter new destination mac address:</H2>\r
+<B><FONT SIZE="+1">Broadcast: </FONT></B><input name="brc" size="15" maxlength="15" value="$defbc"> \r
+<B><FONT SIZE="+1">MAC: </FONT></B><input name="mac" size="17" maxlength="17"> \r
+<B><FONT SIZE="+1">Name: </FONT></B><input name="ip" size="40" maxlength="40">\r
+<P><B><FONT SIZE="+1">\r
+Press <input type="submit" value="save"> to add the entry to your maclist. \r
+Press <input type="reset" value="clear"> to reset the form.\r
+</FONT></B>\r
+</FORM>\r
+<HR>\r
+$ver\r
+ENDOFTEXT\r
+  # Close the document cleanly.\r
+  print end_html;\r
+}\r
+\r
+sub send_broadcast_packet {\r
+  my ($nbc,$mac) = @_;\r
+  if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i)  {\r
+    print "Malformed MAC address $mac<BR>\n";\r
+    return;\r
+  }\r
+  printf("Sending wakeup packet to %04X:%08X-%s<BR>\n", $port, unpack('N',$nbc), $mac);\r
+  # Remove colons\r
+  $mac =~ tr/://d;\r
+  # Magic packet is 6 bytes of FF followed by the MAC address 16 times\r
+  $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);\r
+  # Create socket\r
+  socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "socket: $!\n";\r
+  # Enable broadcast\r
+  setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";\r
+  # Send the wakeup packet\r
+  defined(send(S, $magic, 0, sockaddr_in($port, $nbc))) or print "send: $!\n";\r
+  close(S);\r
+}\r
+\r
+sub process_file {\r
+  unless (open(F, $maclist)) {\r
+    print "Error reading $maclist: $!\n";\r
+  } else {\r
+    while (<F>) {\r
+      next if (/^\s*#|^\s*;/); # skip comments\r
+      my ($mac, $ip) = split;\r
+      next if (!defined($mac) or $mac eq '');\r
+      $mac = uc($mac);\r
+      my $bc = $defbc;\r
+      ($bc,$mac) = split(/-/,$mac) if ($mac =~ /-/);\r
+      my $nbc = inet_aton($bc);\r
+      if ($_[0] eq 'S') {\r
+        &send_broadcast_packet($nbc, $mac);\r
+      } else {\r
+        my $hbc = sprintf("0x%08X", unpack('N',$nbc));\r
+        print "<TD WIDTH=20%><CENTER><TT>$hbc</TT></CENTER></TD>";\r
+        print "<TD WIDTH=30%><CENTER><TT>$mac</TT></CENTER></TD>";\r
+        $ip = '&nbsp;' if (!defined($ip) or $ip eq '');\r
+        print "<TD WIDTH=30%><CENTER><TT>$ip</TT></CENTER></TD>";\r
+        print "<TD WIDTH=20%><CENTER><input type=checkbox name=mac$. value=$hbc-$mac><TT>WakeUp</TT></CENTER></TD></TR>\n";\r
+      }\r
+    }\r
+    close(F);\r
+  }\r
+}\r
+\r
+sub add_entry {\r
+  if (param("brc") !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i) {\r
+    print "Malformed broadcast address ",param("brc"),"\n";\r
+    return;\r
+  }\r
+  if (param("mac") !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {\r
+    print "Malformed MAC address ",param("mac"),"\n";\r
+    return;\r
+  }\r
+  unless (open(F, ">> $maclist")) {\r
+    print "Error writing $maclist: $!\n";\r
+  } else {\r
+    #my $nbc = inet_aton(param("brc"));\r
+    #my $hbc = sprintf("0x%8X", unpack('N',$nbc));\r
+    #print F $hbc."-".uc(param("mac"))." ".param("ip")."\n";\r
+    print F param("brc")."-".uc(param("mac"))." ".param("ip")."\n";\r
+    close(F);\r
+    print "Saved entry to maclist: ".param("brc")."-".uc(param("mac"))." ".param("ip")."\n";\r
+  }\r
+}\r
+\r
diff --git a/contrib/wakeonlan/mp-form.txt b/contrib/wakeonlan/mp-form.txt
new file mode 100644 (file)
index 0000000..2c2ca5b
--- /dev/null
@@ -0,0 +1,26 @@
+mp-form.pl - Send magic packets with your web server\r
+\r
+This is my trial of waking up PCs with a form via web server. \r
+The perl script reads in a text file which contains lines of the form\r
+aa:bb:cc:dd:ee:ff 12.34.56.78 or\r
+aa:bb:cc:dd:ee:ff foo.bar.com\r
+aa:bb:cc:dd:ee:ff\r
+The script is based on wake.pl by Ken Yap who is also the author of the Etherboot package. \r
+The script uses CGI.pm to parse form input and Socket.pm to send the magic packets, both \r
+modules should belong to your perl distribution. The script runs with linux as well as \r
+with NT, with NetWare you have to use the Socket.NLP from recent Perl build #334, with \r
+Perl build #333 and earlier I got an error from the Socket.pm.\r
+This script uses only broadcast so you don't need root rights to use it.\r
+\r
+To install the script copy it to your ../cgi-bin directory. Then for Linux do a chmod 755 \r
+to the script. Modify the lines which point to the location of the maclist. If you do not \r
+have a maclist, the form could save new entries to a list (with unix perhaps you have to \r
+create an empty file). Check also the first line of mp-form.pl and modify it to point to \r
+your perl5 location. For NetWare copy the script to /novonyx/suitespot/docs/perlroot.\r
+\r
+Older version: If you have problems running the script with CGI.pm you could try the older \r
+version mp-form1.pl which uses cgi-lib.pl to parse form input. You can get cgi-lib.pl \r
+from http://cgi-lib.berkeley.edu/. With NetWare you should also use mp-form1.pl as using \r
+CGI.pm consumes much memory. The older version is also included in the zip archive. \r
+\r
+Homepage of the script: http://www.gknw.de/mpform.html\r
diff --git a/contrib/wakeonlan/mp-form1.pl b/contrib/wakeonlan/mp-form1.pl
new file mode 100644 (file)
index 0000000..d42624a
--- /dev/null
@@ -0,0 +1,171 @@
+#!/usr/bin/perl -w\r
+# Magic Packet for the Web\r
+# Perl version by ken.yap@acm.org after DOS/Windows C version posted by\r
+# Steve_Marfisi@3com.com on the Netboot mailing list\r
+# modified to work with web by G. Knauf <info@gknw.de>\r
+# Released under GNU Public License\r
+#\r
+require "cgi-lib.pl";\r
+use Socket;\r
+\r
+$ver = 'v0.52 &copy; gk 2003-Apr-24 11:00:00';\r
+\r
+# Defaults - Modify to point to the location of your mac file\r
+$www = "$ENV{'DOCUMENT_ROOT'}/perldemo";\r
+$maclist = "$www/maclist.txt";\r
+# Defaults - Modify to fit to your network\r
+$defbc = '255.255.255.255';\r
+$port = 60000;\r
+\r
+MAIN: \r
+{\r
+  # Read in all the variables set by the form\r
+  if (&ReadParse(*input)) {\r
+    &process_form();\r
+  } else {\r
+    &print_form();\r
+  }\r
+}\r
+\r
+sub process_form {\r
+  # Print the header\r
+  print &PrintHeader();\r
+  # If defined new mac save it\r
+  if (defined($input{'mac'})) {\r
+    print &HtmlTop("Result of adding an entry to the maclist");\r
+    print '<HR><H3><TT>';\r
+    &add_entry;\r
+    print '</TT></H3><HR>';\r
+    print '<FORM method="POST"><input type=submit value="ok"></FORM>';\r
+  } else {\r
+    # send magic packets to selected macs\r
+    print &HtmlTop("Result of sending magic packets to multiple PCs");\r
+    print '<HR><H3><TT>';\r
+    if (defined($input{'all'})) {\r
+      &process_file(S);\r
+    } else {\r
+      foreach $x (keys %input) {\r
+        my ($brc,$mac) = split(/-/,$input{$x}); \r
+        &send_broadcast_packet(inet_aton($brc),$mac);\r
+      }\r
+    }\r
+    print '</TT></H3><HR>';\r
+    print '<form><input type=button value="back" onClick="history.back()"></FORM>';\r
+  }\r
+  # Close the document cleanly.\r
+  print &HtmlBot;\r
+  exit;\r
+}\r
+\r
+sub print_form {\r
+  print &PrintHeader();\r
+  print &HtmlTop("Form for sending magic packets to multiple PCs");\r
+  # Print out the body of the form\r
+  print <<ENDOFTEXT;\r
+<HR>\r
+<FORM method="POST">\r
+<H2> Select the destination mac addresses: </H2>\r
+<TABLE BORDER COLS=3 WIDTH="80%">\r
+<TR>\r
+<TD><CENTER><B><FONT SIZE="+1">Broadcast address</FONT></B></CENTER></TD>\r
+<TD><CENTER><B><FONT SIZE="+1">MAC address</FONT></B></CENTER></TD>\r
+<TD><CENTER><B><FONT SIZE="+1">Name</FONT></B></CENTER></TD>\r
+<TD><CENTER><B><FONT SIZE="+1"><input type=checkbox name="all" value="all">Select all</FONT></B></CENTER></TD>\r
+</TR>\r
+ENDOFTEXT\r
+  # build up table with mac addresses\r
+  &process_file;\r
+  # print rest of the form\r
+  print <<ENDOFTEXT;\r
+</TABLE>\r
+<P><B><FONT SIZE="+1">\r
+Press <input type="submit" value="wakeup"> to send the magic packets to your selections. \r
+Press <input type="reset" value="clear"> to reset the form.\r
+</FONT></B>\r
+</FORM>\r
+<HR>\r
+<FORM method="POST">\r
+<H2>Enter new destination mac address:</H2>\r
+<B><FONT SIZE="+1">Broadcast: </FONT></B><input name="brc" size="15" maxlength="15" value="$defbc"> \r
+<B><FONT SIZE="+1">MAC: </FONT></B><input name="mac" size=17 maxlength=17> \r
+<B><FONT SIZE="+1">Name: </FONT></B><input name="ip" size=40 maxlength=40>\r
+<P><B><FONT SIZE="+1">\r
+Press <input type="submit" value="save"> to add the entry to your maclist. \r
+Press <input type="reset" value="clear"> to reset the form.\r
+</FONT></B>\r
+</FORM>\r
+<HR>\r
+$ver\r
+ENDOFTEXT\r
+  # Close the document cleanly.\r
+  print &HtmlBot;\r
+}\r
+\r
+sub send_broadcast_packet {\r
+  my ($nbc,$mac) = @_;\r
+  if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i)  {\r
+    print "Malformed MAC address $mac<BR>\n";\r
+    return;\r
+  }\r
+  printf("Sending wakeup packet to %04X:%08X-%s<BR>\n", $port, unpack('N',$nbc), $mac);\r
+  # Remove colons\r
+  $mac =~ tr/://d;\r
+  # Magic packet is 6 bytes of FF followed by the MAC address 16 times\r
+  $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);\r
+  # Create socket\r
+  socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "socket: $!\n";\r
+  # Enable broadcast\r
+  setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";\r
+  # Send the wakeup packet\r
+  defined(send(S, $magic, 0, sockaddr_in($port, $nbc))) or print "send: $!\n";\r
+  close(S);\r
+}\r
+\r
+sub process_file {\r
+  unless (open(F, $maclist)) {\r
+    print "Error reading $maclist: $!\n";\r
+  } else {\r
+    while (<F>) {\r
+      next if (/^\s*#|^\s*;/); # skip comments\r
+      my ($mac, $ip) = split;\r
+      next if (!defined($mac) or $mac eq '');\r
+      $mac = uc($mac);\r
+      my $bc = $defbc;\r
+      ($bc,$mac) = split(/-/,$mac) if ($mac =~ /-/);\r
+      my $nbc = inet_aton($bc);\r
+      if ($_[0] eq 'S') {\r
+        &send_broadcast_packet($nbc, $mac);\r
+      } else {\r
+        my $hbc = sprintf("0x%08X", unpack('N',$nbc));\r
+        print "<TD WIDTH=20%><CENTER><TT>$hbc</TT></CENTER></TD>";\r
+        print "<TD WIDTH=30%><CENTER><TT>$mac</TT></CENTER></TD>";\r
+        $ip = '&nbsp;' if (!defined($ip) or $ip eq '');\r
+        print "<TD WIDTH=30%><CENTER><TT>$ip</TT></CENTER></TD>";\r
+        print "<TD WIDTH=20%><CENTER><input type=checkbox name=mac$. value=$hbc-$mac><TT>WakeUp</TT></CENTER></TD></TR>\n";\r
+      }\r
+    }\r
+    close(F);\r
+  }\r
+}\r
+\r
+sub add_entry {\r
+  if (param("brc") !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i) {\r
+    print "Malformed broadcast address ",param("brc"),"\n";\r
+    return;\r
+  }\r
+  if (param("mac") !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {\r
+    print "Malformed MAC address ",param("mac"),"\n";\r
+    return;\r
+  }\r
+  unless (open(F, ">> $maclist")) {\r
+    print "Error writing $maclist: $!\n";\r
+  } else {\r
+    #my $nbc = inet_aton(param("brc"));\r
+    #my $hbc = sprintf("0x%8X", unpack('N',$nbc));\r
+    #print F $hbc."-".uc(param("mac"))." ".param("ip")."\n";\r
+    print F param("brc")."-".uc(param("mac"))." ".param("ip")."\n";\r
+    close(F);\r
+    print "Saved entry to maclist: ".param("brc")."-".uc(param("mac"))." ".param("ip")."\n";\r
+  }\r
+}\r
+\r
diff --git a/contrib/wakeonlan/readme.txt b/contrib/wakeonlan/readme.txt
new file mode 100644 (file)
index 0000000..94f2ef3
--- /dev/null
@@ -0,0 +1,35 @@
+mp-form.pl - Send magic packets with your web server\r
+\r
+This is my trial of waking up PCs with a form via web server. \r
+The perl script reads in a text file which contains lines of the form\r
+aa:bb:cc:dd:ee:ff 12.34.56.78 or\r
+aa:bb:cc:dd:ee:ff foo.bar.com\r
+aa:bb:cc:dd:ee:ff\r
+optional a broadcast address mask can be prefixed:\r
+192.168.1.255-aa:bb:cc:dd:ee:ff\r
+\r
+The script is based on wake.pl by Ken Yap who is also the author of the Etherboot package. \r
+The script uses CGI.pm to parse form input and Socket.pm to send the magic packets, both \r
+modules should belong to your perl distribution. The script runs with linux as well as \r
+with NT, with NetWare you have to use the Socket.NLP from recent Perl build #334, with \r
+Perl build #333 and earlier I got an error from the Socket.pm. You should also update\r
+your Perl to minimum #331 from CPAN: http://www.cpan.org/ports/index.html#netware.\r
+This script uses only broadcast so you don't need root rights to use it.\r
+\r
+To install the script copy it to your ../cgi-bin directory. Then for Linux do a chmod 755 \r
+to the script. Modify the lines which point to the location of the maclist. If you do not \r
+have a maclist, the form could save new entries to a list (with unix perhaps you have to \r
+create an empty file). Check also the first line of mp-form.pl and modify it to point to \r
+your perl5 location. For NetWare copy the script to /novonyx/suitespot/docs/perlroot.\r
+\r
+Older version: If you have problems running the script with CGI.pm you could try the older \r
+version mp-form1.pl which uses cgi-lib.pl to parse form input. You can get cgi-lib.pl \r
+from http://cgi-lib.berkeley.edu/. With NetWare you should also use mp-form1.pl as using \r
+CGI.pm consumes much memory. The older version is also included in the zip archive. \r
+\r
+A modified version of the original script is now also included which runs with older \r
+Getopt::Std.pm as shipped with NetWare. This script you could use from command line \r
+or from cron. With NetWare copy the script to /perl/scripts; then call from console with:\r
+perl wakeup.pl <parameters>.\r
+\r
+Homepage of the script: http://www.gknw.de/mpform.html\r
diff --git a/contrib/wakeonlan/wake.pl b/contrib/wakeonlan/wake.pl
new file mode 100644 (file)
index 0000000..d9be35b
--- /dev/null
@@ -0,0 +1,116 @@
+#!/usr/bin/perl -w
+#
+# If called as wake.pl -f file it reads lines of the form
+#
+# aa:bb:cc:dd:ee;ff 12.34.56.78 or
+# aa:bb:cc:dd:ee:ff foo.bar.com
+# aa:bb:cc:dd:ee:ff
+#
+# which are MAC addresses and hostnames of NICs to send a wakeup packet.
+# In the first two cases, unicast is used (and root permission may be
+# required if the ARP cache needs to be injected with a mapping).
+# In the third case, broadcast is used, and anybody can run the command.
+# Comments in the file start with #.
+#
+# Or MAC addresses can be specified on the command line
+#
+# wake.pl aa.bb.cc.dd.ee.ff
+#
+# Or both can be used:
+#
+# wake.pl -f addresses.cfg 11:22:33:44:55:66
+#
+# This program may have to be run with superuser privilege because it
+# may need to inject an ARP entry into the cache.
+# Be careful, you could corrupt valid entries if those NICs are
+# already active.
+#
+# Perl version by ken_yap@users.sourceforge.net after DOS/Windows C version posted by
+# Steve_Marfisi@3com.com on the Netboot mailing list
+# Released under GNU Public License, 2000-01-08
+# Added switch -q for quiet mode, changed Getopt usage to work with older versions,
+# added switch -u for unicast mode, now default is always broadcast mode,
+# added switch -s for seach pattern so you could filter entries from file.
+# Guenter.Knauf@dialup.soco.de, 2000-10-14
+#
+use Getopt::Std;
+use Socket;
+
+getopts('quf:s:');
+if (defined($opt_f)) {
+       unless (open(F, $opt_f)) {
+               print STDERR "open: $opt_f: $!\n";
+       } else {
+               while (<F>) {
+                       next if /^\s*#/;        # skip comments
+                       ($mac, $ip) = split;
+                       next if !defined($mac) or $mac eq '';
+                       next if defined($opt_s) and (!/$opt_s/);
+                       if (!defined($ip) or $ip eq '' or !$opt_u) {
+                               &send_broadcast_packet($mac);
+                       } else {
+                               &send_unicast_packet($mac, $ip);
+                       }
+               }
+               close(F);
+       }
+}
+while (@ARGV) {
+       send_broadcast_packet(shift(@ARGV));
+}
+
+sub send_broadcast_packet {
+       ($mac) = @_;
+
+       if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i)  {
+               print STDERR "Malformed MAC address $mac\n";
+               return;
+       }
+       # Remove colons
+       $mac =~ tr/://d;
+       # Magic packet is 6 bytes of FF followed by the MAC address 16 times
+       $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);
+       # Create socket
+       socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp'))
+               or die "socket: $!\n";
+       # Enable broadcast
+       setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1)
+               or die "setsockopt: $!\n";
+       # Send the wakeup packet
+       if (!$opt_q) {
+               print "Sending wakeup packet to MAC address $mac";
+               print " ($ip)" if (defined($ip));
+               print "\n";
+       }
+       defined(send(S, $magic, 0, sockaddr_in(0x2fff, INADDR_BROADCAST)))
+               or print STDERR "send: $!\n";
+       close(S);
+}
+
+sub send_unicast_packet {
+       ($mac, $ip) = @_;
+
+       if (!defined($iaddr = inet_aton($ip))) {
+               print STDERR "Cannot resolve $ip\n";
+               return;
+       }
+       if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i)  {
+               print STDERR "Malformed MAC address $mac\n";
+               return;
+       }
+       # Inject entry into ARP table, in case it's not there already
+       system("arp -s $ip $mac") == 0
+               or print STDERR "Warning: arp command failed, you need to be root\n";
+       # Remove colons
+       $mac =~ tr/://d;
+       # Magic packet is 6 bytes of FF followed by the MAC address 16 times
+       $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);
+       # Create socket
+       socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp'))
+               or die "socket: $!\n";
+       # Send the wakeup packet
+       print "Sending wakeup packet to $ip at MAC address $mac\n" if (!$opt_q);
+       defined(send(S, $magic, 0, sockaddr_in(0x2fff, $iaddr)))
+               or print STDERR "send: $!\n";
+       close(S);
+}
diff --git a/contrib/wakeonlan/wakeserver.patch b/contrib/wakeonlan/wakeserver.patch
new file mode 100644 (file)
index 0000000..43e78b1
--- /dev/null
@@ -0,0 +1,179 @@
+To: etherboot-developers@lists.sourceforge.net
+X-face: #Qvg5o3u!)WoVDDi4-bFy`fl@""4^pm68%_,`puon{0Q6lQ-O,)3D.J.":A&^,#4O2vc8`?
+ 3^1lhBh=EQH,"Qq*e1vY":she&t^8:!&Fb32Ed:nM2Y<E9|i[+z20G?CO=E=-IWv;bL"=Y`+`q,ML6
+ ,!Me?==j&In1
+Mime-Version: 1.0
+Content-Type: multipart/mixed ;
+       boundary="==_Exmh_-19971541890"
+From: Tilmann Bubeck <bubeck@think-at-work.de>
+Message-Id: <20010219195622.C97A84ABD8@chaos.think-at-work.de>
+Subject: [Etherboot-developers] Wake-on-LAN patch
+Sender: etherboot-developers-admin@lists.sourceforge.net
+Errors-To: etherboot-developers-admin@lists.sourceforge.net
+X-BeenThere: etherboot-developers@lists.sourceforge.net
+X-Mailman-Version: 2.0
+Precedence: bulk
+List-Help: <mailto:etherboot-developers-request@lists.sourceforge.net?subject=help>
+List-Post: <mailto:etherboot-developers@lists.sourceforge.net>
+List-Subscribe: <http://lists.sourceforge.net/lists/listinfo/etherboot-developers>,
+       <mailto:etherboot-developers-request@lists.sourceforge.net?subject=subscribe>
+List-Id: Discussion list for Etherboot developers <etherboot-developers.lists.sourceforge.net>
+List-Unsubscribe: <http://lists.sourceforge.net/lists/listinfo/etherboot-developers>,
+       <mailto:etherboot-developers-request@lists.sourceforge.net?subject=unsubscribe>
+List-Archive: <http://lists.sourceforge.net/archives//etherboot-developers/>
+Date: Mon, 19 Feb 2001 20:56:22 +0100
+Status: RO
+Content-Length: 5351
+Lines: 152
+
+This is a multipart MIME message.
+
+--==_Exmh_-19971541890
+Content-Type: text/plain; charset=us-ascii
+
+
+Hello!
+
+please find enclosed a patch to optionally enable etherboot to start the 
+server it is booting from by sending a magic wake-on-lan packet to the 
+sleeping server first.
+
+This is very important for an etherboot-server, which is not running all the 
+time and is not easily accessible from the etherboot machine (e.g. because it 
+is installed in the basement of the house and one must climb several stairs to 
+switch the server on...)
+
+Are the authors of etherboot willing to accept this patch for inclusion? 
+Please note, that the wake-on-lan code is only compiled in, when setting 
+appropriate flags in src/Config.
+
+If you don't want to include the patch, should I change anything of the 
+implementation or do you dislike the idea at all?
+Thanks!
+   Till
+
++-------+--------------------------------------------------------------+
+|       | dr. tilmann bubeck               think@work it consulting    |
+|       |                                  professional services       |
+| think | cell.: +49 172 8842972           widmaierstrasse 58          |
+| @work | fax  : +49 711 7227734           70567 stuttgart             |
+|       | email: bubeck@think-at-work.de   http://www.think-at-work.de |
++-------+ -------------------------------------------------------------+
+
+
+--==_Exmh_-19971541890
+Content-Type: application/x-patch ; name="etherboot-4.7.17-wol.patch"
+Content-Description: etherboot-4.7.17-wol.patch
+Content-Disposition: attachment; filename="etherboot-4.7.17-wol.patch"
+
+diff -r -u etherboot-4.7.17/src/Config etherboot-4.7.17-wol/src/Config
+--- etherboot-4.7.17/src/Config        Sat Jan  6 16:25:23 2001
++++ etherboot-4.7.17-wol/src/Config    Mon Feb 19 20:28:00 2001
+@@ -113,6 +113,16 @@
+ #     -DINTERNAL_BOOTP_DATA
+ #                     - define if the area 0x93C00-0x93FFF is not available
+ #                       for use for bootpd_data by the loader for some reason
++#     -DWAKEUP_SERVER 
++#                       - define this for sending a Wake-On-LAN (WOL) 
++#                         "Magic Packet" to a sleeping server, before trying 
++#                         a etherboot. Useful if your server is soft-off all
++#                         the time and must be switched on when booting a 
++#                         client. Define SERVER_MAC with the MAC address of the
++#                         server to wakeup. CAUTION! This MAC address is 
++#                         stored in the rom image. The rom is therefore not
++#                         generic anymore but tailored for a specific
++#                         server!
+ # These default settings compile Etherboot with a small number of options.
+ # You may wish to enable more of the features if the size of your ROM allows.
+@@ -142,6 +152,10 @@
+ # These flags affect the loader that is prepended to the Etherboot image
+ LCONFIG+=     -DMOVEROM
++
++# Include code for sending a Wake-On-LAN (WOL) "Magic Packet" to a sleeping
++# server, before trying a etherboot.
++CFLAGS32+=    -DWAKEUP_SERVER -DSERVER_MAC=0x00,0x01,0x02,0xDA,0xDF,0x77
+ # you should normally not need to change these
+ RM=           rm -f
+diff -r -u etherboot-4.7.17/src/main.c etherboot-4.7.17-wol/src/main.c
+--- etherboot-4.7.17/src/main.c        Fri Jan  5 12:45:29 2001
++++ etherboot-4.7.17-wol/src/main.c    Thu Feb  8 20:46:59 2001
+@@ -137,6 +137,7 @@
+  *    declarations, but in this case I like to see main() as the first
+  *    routine.
+  */
++static void wakeup_server(void) ;
+ static int bootp(void);
+ static int rarp(void);
+ static void load(void);
+@@ -217,6 +218,11 @@
+                       rfc951_sleep(++card_retries);
+       }
+ #endif
++
++#ifdef WAKEUP_SERVER
++      wakeup_server();
++#endif
++
+       while (1) {
+               /* -1:  timeout or ESC
+                  -2:  error return from loader
+@@ -650,6 +656,46 @@
+       return (0);
+ }
+ #endif        /* DOWNLOAD_PROTO_TFTP */
++
++#ifdef WAKEUP_SERVER
++#ifndef SERVER_MAC 
++#error "Please define SERVER_MAC to the MAC address of the sleeping server"
++#endif
++
++/**************************************************************************
++WOL - Wake up a sleeping server by transmitting a Wake-On-LAN (WOL) "Magic
++      Packet", used for restarting machines that have been soft-powered-down
++      (ACPI D3-warm state). It currently generates the standard AMD Magic
++      Packet format.
++**************************************************************************/
++static void wakeup_server(void) 
++{
++      unsigned char data[100];
++      int i, len, retry;
++      char server_adr[] = { SERVER_MAC };
++      unsigned long time;
++
++      /* build "Magic Packet" */
++      len = 0;
++      data[len++] = 0xff;
++      data[len++] = 0xff;
++      data[len++] = 0xff;
++      data[len++] = 0xff;
++      data[len++] = 0xff;
++      data[len++] = 0xff;
++      for ( i = 0; i < 16; i++ ) {
++              memcpy(&data[len], server_adr, 6);
++              len += 6;
++      }
++
++      printf("Sending Wake-On-LAN (WOL) \"Magic Packet\" to server %b:%b:%b:%b:%b:%b...", 
++             server_adr[0], server_adr[1], server_adr[2],
++             server_adr[3], server_adr[4], server_adr[5]);
++      
++      eth_transmit(broadcast, 0x0842, len, data);
++      printf("done\n");
++}
++#endif
+ #ifdef        RARP_NOT_BOOTP
+ /**************************************************************************
+
+--==_Exmh_-19971541890--
+
+
+
+_______________________________________________
+Etherboot-developers mailing list
+Etherboot-developers@lists.sourceforge.net
+http://lists.sourceforge.net/lists/listinfo/etherboot-developers
diff --git a/contrib/wakeonlan/wakeup.pl b/contrib/wakeonlan/wakeup.pl
new file mode 100644 (file)
index 0000000..83cf363
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/perl\r
+#!/usr/bin/perl -w\r
+#\r
+# If called as wakeup.pl -f file it reads lines of the form\r
+#\r
+# aa:bb:cc:dd:ee;ff 12.34.56.78 or\r
+# aa:bb:cc:dd:ee:ff foo.bar.com\r
+# aa:bb:cc:dd:ee:ff\r
+#\r
+# which are MAC addresses and hostnames of NICs to send a wakeup packet.\r
+# Broadcast is used to send the magic packets, so anybody can run the command.\r
+# Notice that many routers do NOT forward broadcasts automatically!!\r
+# Comments in the file start with #.\r
+#\r
+# Or MAC addresses can be specified on the command line\r
+#\r
+# wakeup.pl aa.bb.cc.dd.ee.ff\r
+#\r
+# Or both can be used:\r
+#\r
+# wakeup.pl -f addresses.cfg 11:22:33:44:55:66\r
+# \r
+# Use option -b to specify broadcast mask.\r
+# Use option -d for screen output.\r
+#\r
+# Perl version by ken.yap@acm.org after DOS/Windows C version posted by\r
+# Steve_Marfisi@3com.com on the Netboot mailing list\r
+# Released under GNU Public License, 2000-01-08\r
+# Modified for use with NetWare by gk@gknw.de, 2000-09-18\r
+# With NetWare you have to use Socket.NLP from NetWare Perl #334 or higher!\r
+# You could download Socket.NLP #334 from: http://www.gknw.de/mpform.html\r
+#\r
+\r
+use Getopt::Std;\r
+use Socket;\r
+\r
+getopts('b:df:p:q');\r
+\r
+$brc = $opt_b || '255.255.255.255';\r
+$port = $opt_p || 60000;\r
+die "Malformed broadcast address: $brc!\n" if ($brc !~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)/);\r
+\r
+if (defined($opt_f)) {\r
+       unless (open(F, $opt_f)) {\r
+               print "open: $opt_f: $!\n";\r
+       } else {\r
+               print "Using file $opt_f...\n" if ($opt_d);\r
+               while (<F>) {\r
+                       next if /^\s*#/;        # skip comments\r
+                       my ($mac, $ip) = split;\r
+                       next if !defined($mac) or $mac eq '';\r
+                       &send_broadcast_packet($mac,$ip);\r
+               }\r
+               close(F);\r
+       }\r
+}\r
+while (@ARGV) {\r
+       send_broadcast_packet(shift(@ARGV));\r
+}\r
+\r
+sub send_broadcast_packet {\r
+       my ($mac,$ip) = @_;\r
+       if ($mac =~ /-/) {\r
+               ($bc,$mac) = split(/-/,$mac);\r
+       } else {\r
+               $bc = $brc;\r
+       }\r
+       if ($mac !~ /^[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}:[\da-f]{2}$/i) {\r
+               print "Malformed MAC address $mac\n";\r
+               return;\r
+       }\r
+       my $nbc = inet_aton($bc);\r
+       # Remove colons\r
+       $mac =~ tr/://d;\r
+       # Magic packet is 6 bytes of FF followed by the MAC address 16 times\r
+       $magic = ("\xff" x 6) . (pack('H12', $mac) x 16);\r
+       # Create socket\r
+       socket(S, PF_INET, SOCK_DGRAM, getprotobyname('udp')) or die "socket: $!\n";\r
+       # Enable broadcast\r
+       setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";\r
+       # Send the wakeup packet\r
+       printf("$0: Sending wakeup packet to %04X:%08X-%s %s\n",$port,unpack('N',$nbc),uc($mac),$ip) if ($opt_d);\r
+       defined(send(S, $magic, 0, sockaddr_in($port, $nbc)))\r
+               or print "send: $!\n";\r
+       close(S);\r
+}\r
diff --git a/contrib/wakeonlan/wakeup.txt b/contrib/wakeonlan/wakeup.txt
new file mode 100644 (file)
index 0000000..b96b3e4
--- /dev/null
@@ -0,0 +1,9 @@
+# maclist - mac addresses for wakeonlan
+00:BA:BE:FA:CE:00 mainframe
+00:11:22:33:44:5A maschine1
+00:11:22:33:44:B5 maschine2
+00:11:22:33:44:5C maschine3
+0A:BB:CC:DD:EE:F9 macintosh
+1A:BB:CC:DD:E6:FF 
+3A:BB:CC:DD:EE:F5 testpc
+3A:BB:CC:DD:EE:F6 123.45.6.7
diff --git a/contrib/wakeonlan/wol.c b/contrib/wakeonlan/wol.c
new file mode 100644 (file)
index 0000000..07b7e4f
--- /dev/null
@@ -0,0 +1,374 @@
+/*****************************************************************************
+ *
+ * wol.c - Wake-On-LAN utility to wake a networked PC
+ *
+ * by R. Edwards (bob@cs.anu.edu.au), January 2000
+ * (in_ether routine adapted from net-tools-1.51/lib/ether.c by
+ * Fred N. van Kempen)
+ * added file input, some minor changes for compiling for NetWare
+ * added switches -q and -d=<ms>, added Win32 target support
+ * by G. Knauf (gk@gknw.de), 30-Jan-2001
+ * added switches -b=<bcast> and -p=<port>
+ * by G. Knauf (gk@gknw.de), 10-Okt-2001
+ * added OS/2 target support
+ * by G. Knauf (gk@gknw.de), 24-May-2002
+ *
+ * This utility allows a PC with WOL configured to be powered on by
+ * sending a "Magic Packet" to it's network adaptor (see:
+ * http://www.amd.com/products/npd/overview/20212.html).
+ * Only the ethernet dest address needs to be given to make this work.
+ * Current version uses a UDP broadcast to send out the Magic Packet.
+ *
+ * compile with: gcc -Wall -o wol wol.c
+ * with Solaris: (g)cc -o wol wol.c -lsocket -lnsl
+ * with MingW32: gcc -Wall -o wol wol.c -lwsock32
+ *
+ * usage: wol <dest address>
+ * where <dest address> is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format.
+ * or: wol [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<File name>
+ * where <File name> is a file containing one dest address per line,
+ * optional followed by a hostname or ip separated by a blank.
+ * -b sets optional broadcast address, -p sets optional port,
+ * -q supresses output, -d=<ms> delays ms milliseconds between sending.
+ *
+ * Released under GNU Public License January, 2000.
+ */
+
+#define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WATTCP
+  #define strncasecmp strnicmp
+  #include <ctype.h>
+  #include <dos.h>
+  #include <tcp.h>
+#else
+#ifdef WIN32                            /* Win32 platform */
+  #define USE_WINSOCKAPI
+  #define delay Sleep
+  #if (defined(__LCC__) || defined(__BORLANDC__))
+    #define strncasecmp strnicmp
+  #else
+    #define strncasecmp _strnicmp
+  #endif
+#elif defined(N_PLAT_NLM)               /* NetWare platform */
+#ifdef __NOVELL_LIBC__
+  #include <ctype.h>
+#else
+  extern int isdigit(int c);            /* no ctype.h for NW3.x */
+  #include <nwthread.h>
+  #define strncasecmp strnicmp
+#endif
+#elif defined(__OS2__)                  /* OS/2 platform */
+  #ifdef __EMX__
+    #define strncasecmp strnicmp
+  #endif
+  extern int DosSleep(long t);
+  #define delay DosSleep
+#else                                   /* all other platforms */
+  #define delay(t) usleep(t*1000)
+#endif
+#ifndef N_PLAT_NLM                      /* ! NetWare platform */
+  #include <ctype.h>
+#endif
+#ifndef WIN32                           /* ! Win32 platform */
+  #include <unistd.h>
+#endif
+#ifdef USE_WINSOCKAPI                   /* Winsock2 platforms */
+  #ifdef N_PLAT_NLM                     /* NetWare platform */
+    #include <ws2nlm.h>
+  #else
+    #include <winsock.h>
+  #endif
+  #define close(s) { \
+    closesocket(s); \
+    WSACleanup(); \
+  }
+#else                                   /* Socket platforms */
+  #include <sys/types.h>
+  #include <sys/socket.h>
+  #include <netinet/in.h>
+  #if defined(__OS2__) && !defined(__EMX__)
+    #include <utils.h>
+  #else
+    #include <arpa/inet.h>
+  #endif
+#endif
+
+#endif
+
+static int read_file (char *destfile);
+static int in_ether (char *bufp, unsigned char *addr);
+static int send_wol (char *dest, char *host);
+
+
+char *progname;
+int quiet = 0;
+int twait = 0;
+unsigned int port = 60000;
+unsigned long bcast = 0xffffffff;
+
+int main (int argc, char *argv[]) {
+
+    int cmdindx = 0;
+    progname    = argv[0];
+
+    if (argc > 1) {
+        /* parse input parameters */
+        for (argc--, argv++; *argv; argc--, argv++) {
+            char *bp;
+            char *ep;
+
+            if (strncasecmp (*argv, "-", 1) == 0) {
+                if (strncasecmp (*argv, "-F=", 3) == 0) {
+                    bp = *argv + 3;
+                    read_file (bp);
+                } else if (strncasecmp (*argv, "-B=", 3) == 0) {
+                    bp = *argv + 3;
+                    bcast = inet_addr(bp);
+                    if (bcast == -1) {
+                        fprintf (stderr, "%s: expected address argument at %s\n", progname, *argv);
+                        exit (1);
+                    }
+                } else if (strncasecmp (*argv, "-D=", 3) == 0) {
+                    bp = *argv + 3;
+                    twait = strtol (bp, &ep, 0);
+                    if (ep == bp || *ep != '\0') {
+                        fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
+                        exit (1);
+                    }
+                } else if (strncasecmp (*argv, "-P=", 3) == 0) {
+                    bp = *argv + 3;
+                    port = strtol (bp, &ep, 0);
+                    if (ep == bp || *ep != '\0') {
+                        fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
+                        exit (1);
+                    }
+                } else if (strncasecmp (*argv, "-Q", 2) == 0) {
+                    quiet = 1;
+                } else if (strncasecmp (*argv, "-V", 2) == 0) {
+                    fprintf (stderr, "\r%s Version %s\n", progname, VERSION);
+                    exit (0);
+                } else {
+                    fprintf (stderr, "\r%s: invalid or unknown option %s\n", progname, *argv);
+                    exit (1);
+                }
+            } else {
+                send_wol (*argv, "");
+            }
+        cmdindx++;
+        }
+        return (0);
+    } else {
+        /* No arguments given -> usage message */
+        fprintf (stderr, "\rUsage: %s [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<file> | <dest>\n", progname);
+        fprintf (stderr, "       need at least hardware address or file option\n");
+        return (-1);
+    }
+}
+
+
+
+static int in_ether (char *bufp, unsigned char *addr) {
+
+    char c, *orig;
+    int i;
+    unsigned char *ptr = addr;
+    unsigned val;
+
+    i = 0;
+    orig = bufp;
+    while ((*bufp != '\0') && (i < 6)) {
+        val = 0;
+        c = *bufp++;
+        if (isdigit(c))
+            val = c - '0';
+        else if (c >= 'a' && c <= 'f')
+            val = c - 'a' + 10;
+        else if (c >= 'A' && c <= 'F')
+            val = c - 'A' + 10;
+        else {
+#ifdef DEBUG
+            fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
+#endif
+            errno = EINVAL;
+            return (-1);
+        }
+        val <<= 4;
+        c = *bufp;
+        if (isdigit(c))
+            val |= c - '0';
+        else if (c >= 'a' && c <= 'f')
+            val |= c - 'a' + 10;
+        else if (c >= 'A' && c <= 'F')
+            val |= c - 'A' + 10;
+        else if (c == ':' || c == 0)
+            val >>= 4;
+        else {
+#ifdef DEBUG
+            fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
+#endif
+            errno = EINVAL;
+            return (-1);
+        }
+        if (c != 0)
+            bufp++;
+        *ptr++ = (unsigned char) (val & 0377);
+        i++;
+
+        /* We might get a semicolon here - not required. */
+        if (*bufp == ':') {
+            if (i == 6) {
+                ;           /* nothing */
+            }
+            bufp++;
+        }
+    }
+    if (bufp - orig != 17) {
+        return (-1);
+    } else {
+        return (0);
+    }
+} /* in_ether */
+
+
+static int read_file (char *destfile) {
+
+    FILE    *pfile = NULL;
+    char    dest[64];
+    char    host[32];
+    char    buffer[512];
+
+    pfile = fopen (destfile, "r+");
+
+    if (pfile) {
+        while (fgets (buffer, 511, pfile) != NULL) {
+            if (buffer[0] != '#' && buffer[0] != ';') {
+                dest[0] = host[0] = '\0';
+                sscanf (buffer, "%s %s", dest, host);
+                send_wol (dest, host);
+            }
+        }
+        fclose (pfile);
+        return (0);
+    } else {
+        fprintf (stderr, "\r%s: destfile '%s' not found\n", progname, destfile);
+        return (-1);
+    }
+}
+
+
+static int send_wol (char *dest, char *host) {
+
+    int i, j;
+    int packet;
+    struct sockaddr_in sap;
+    unsigned char ethaddr[8];
+    unsigned char *ptr;
+    unsigned char buf [128];
+    unsigned long bc;
+    char mask[32];
+    char *tmp;
+#ifdef USE_WINSOCKAPI
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    int err;
+#endif
+#ifdef WATTCP
+    static udp_Socket sock;
+    udp_Socket *s;
+#else
+    int optval = 1;
+#endif
+
+    /* Fetch the broascast address if present. */
+    if ((tmp = strstr(dest,"-"))) {
+printf("found: %s\n", tmp);
+       tmp[0] = 32;
+       sscanf (dest, "%s %s", mask, dest);
+       bc = inet_addr(mask);
+printf("bc: string %s address %08lX\n", mask, bc);
+       if (bc == -1) {
+           fprintf (stderr, "\r%s: expected address argument at %s\n", progname, mask);
+           return (-1);
+       }
+    } else
+       bc = bcast;
+
+    /* Fetch the hardware address. */
+    if (in_ether (dest, ethaddr) < 0) {
+        fprintf (stderr, "\r%s: invalid hardware address\n", progname);
+        return (-1);
+    }
+
+#ifdef USE_WINSOCKAPI
+    /* I would like to have Socket Vers. 1.1 */
+    wVersionRequested = MAKEWORD(1, 1);
+    err = WSAStartup (wVersionRequested, &wsaData);
+    if (err != 0) {
+        fprintf (stderr, "\r%s: couldn't init Winsock Version 1.1\n", progname);
+        WSACleanup ();
+        return (-1);
+    }
+#endif
+
+    /* setup the packet socket */
+#ifdef WATTCP
+    sock_init();
+    s = &sock;
+    if (!udp_open( s, 0, bc, port, NULL )) {
+#else
+    if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+#endif
+        fprintf (stderr, "\r%s: socket failed\n", progname);
+#ifdef USE_WINSOCKAPI
+        WSACleanup ();
+#endif
+        return (-1);
+    }
+
+#ifndef WATTCP
+    /* Set socket options */
+    if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) {
+        fprintf (stderr, "\r%s: setsocket failed %s\n", progname, strerror (errno));
+        close (packet);
+        return (-1);
+    }
+
+    /* Set up broadcast address */
+    sap.sin_family = AF_INET;
+    sap.sin_addr.s_addr = bc;                 /* broadcast address */
+    sap.sin_port = htons(port);
+#endif
+
+    /* Build the message to send - 6 x 0xff then 16 x dest address */
+    ptr = buf;
+    for (i = 0; i < 6; i++)
+        *ptr++ = 0xff;
+    for (j = 0; j < 16; j++)
+        for (i = 0; i < 6; i++)
+            *ptr++ = ethaddr [i];
+
+    /* Send the packet out */
+#ifdef WATTCP
+    sock_write( s, buf, 102 );
+    sock_close( s );
+#else
+    if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0) {
+        fprintf (stderr, "\r%s: sendto failed, %s\n", progname, strerror(errno));
+        close (packet);
+        return (-1);
+    }
+    close (packet);
+#endif
+    if (!quiet) fprintf (stderr, "\r%s: packet sent to %04X:%08lX-%s %s\n",
+            progname, port, (unsigned long)htonl(bc), dest, host);
+    if (twait > 0 ) {
+        delay (twait);
+    }
+    return (0);
+}
+
diff --git a/eb.png b/eb.png
new file mode 100644 (file)
index 0000000..544c841
Binary files /dev/null and b/eb.png differ
diff --git a/index-berlios.html b/index-berlios.html
new file mode 100644 (file)
index 0000000..354d6c1
--- /dev/null
@@ -0,0 +1,254 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta name="generator" content=
+"HTML Tidy for Linux/x86 (vers 1st April 2002), see www.w3.org">
+<title>Welcome to EtherBoot.org</title>
+<meta http-equiv="Content-Type" content=
+"text/html; charset=iso-8859-1">
+<link rel=StyleSheet href="style.css" type="text/css"/>
+</head>
+<body>
+<table summary="welcome" width="95%" border="0" cellspacing="0"
+cellpadding="3" align="center">
+<tr bgcolor="#0F3161">
+<td width="278" bgcolor="#0F3161" valign="bottom">
+<h2 class="c1">Welcome to the</h2>
+</td>
+<td bgcolor="#0F3161">
+</td>
+<td></td>
+</tr>
+
+<tr>
+<td bgcolor="#BFCBD9">
+<div class="c2">EtherBoot Project</div>
+</td>
+<td align="middle">
+<div class="c2">
+<a href="http://osdir.com/Article198.phtml"><img src=
+"http://www.osdir.com/images/2003osdirwinnerbadge.gif" width=
+"125" height="65" border="0" alt="OSDir 2003 Winner Badge"></a>
+</div>
+</td>
+<td bgcolor="#BFCBD9">
+<div class="c4"><a href="index.html" class="c3"><img src=
+"doc/html/images/etherboot_logo.png" alt="Etherboot logo" width=
+"125" height="54" border="0"></a></div>
+</td>
+</tr>
+</table>
+
+<table summary="index" width="95%" border="0" cellspacing="0"
+cellpadding="0" align="center">
+<tr>
+<td bgcolor="#0F3161" width="165" height="56" valign="top">
+<table summary="index.html" width="100%" border="0" cellspacing=
+"10" cellpadding="0" align="right">
+<tr>
+<td height="45">
+<div class="c4"><a href="index.html" class=
+"c5"><b>Home</b></a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/projects/etherboot" class=
+"c3">Sourceforge project home</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://developer.berlios.de/projects/etherboot" class=
+"c3">Berlios project mirror</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/news/?group_id=4233" class=
+"c3">News</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="doc/html/documentation.html" class=
+"c3">Documentation</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://wiki.etherboot.org" class=
+"c3">Wiki</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://rom-o-matic.net/" class=
+"c3">Make ROMs</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/project/showfiles.php?group_id=4233" class=
+"c3">Download source from Sourceforge</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://etherboot.berlios.de/dist/" class=
+"c3">Download source from Berlios (Germany)</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="doc/html/contributing.html" class=
+"c3">Volunteering</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/mail/?group_id=4233" class=
+"c3">Mailing Lists</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href=
+"http://etherboot.sourceforge.net/relatedlinks.html" class=
+"c3">Related Links</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href=
+"http://etherboot.sourceforge.net/clinks.html" class=
+"c3">Commercial Links</a></div>
+</td>
+</tr>
+</table>
+</td>
+<td width="700" height="56" bgcolor="#FFFFFF" valign="top" align=
+"left">
+<blockquote>
+<h2 class="c6">About EtherBoot</h2>
+
+<p class="c7">Etherboot is a software package for creating ROM
+images that can download code over an Ethernet network to be
+executed on an x86 computer. Many network adapters have a socket
+where a ROM chip can be installed. Etherboot is code that can be
+put in such a ROM. Etherboot is normally used for for booting PCs
+diskless. This is useful in various situations, for example:</p>
+
+<ul class="c11">
+<li>An X-terminal.</li>
+
+<li>Clusters of compute servers.</li>
+
+<li>Routers.</li>
+
+<li>Various kinds of remote servers, e.g. a tape drive server that
+can be accessed with the RMT protocol.</li>
+
+<li>Machines doing tasks in environments unfriendly to disks.</li>
+
+<li>A user platform where remote partitions are mounted over the
+network and you are willing to accept the lower speed compared to
+disk.</li>
+
+<li>Maintaining software for a cluster of equally configured
+workstations centrally.</li>
+</ul>
+
+<p class="c7">Etherboot can boot computers faster than from a disk
+because there are no delays in spinning up disks, etc. A moment's
+calculation will show that even with a 10Mbit Ethernet, sending a
+500kB kernel will take only a couple of seconds typically. With
+100Mbit Ethernet it gets even better.</p>
+
+<p class="c7">Compared to booting from solid-state devices, e.g.
+Flash disks, Etherboot has the advantage of centralising software
+adminstration, the tradeoff being the dependence on a server. This
+can be partly alleviated by providing redundant servers.</p>
+
+<p class="c7">Etherboot can work with RAM disks, NFS filesystems,
+or even local disks, if desired. It's a component technology and
+can be combined with other technologies to do things the way you
+want.</p>
+
+<p class="c7">Etherboot is usually used to load Linux, FreeBSD or
+DOS. However the protocol and boot file formats are general, so
+there is no reason why it could not be used to load arbitrary
+images to a PC, including other OSes.</p>
+
+<p class="c7">Etherboot is Open Source under the GNU General Public
+License Version 2 (GPL2).</p>
+
+<p class="c7">The components needed by Etherboot are</p>
+
+<ul class="c11">
+<li>A bootstrap loader, usually in an EPROM on a network card, or
+installed in the flash BIOS, but could be put anywhere in the
+address space the BIOS probes in. For testing this could be put on
+a floppy disk or a hard disk partition. Some configurations may
+even be always run from a floppy disk (e.g. temporary testing
+setups or pedagogic uses).</li>
+
+<li>A DHCP or bootp server, for returning an IP address and other
+information when sent a MAC (Ethernet card) address.</li>
+
+<li>A tftp server, for sending the kernel images and other files
+required in the boot process. Alternatively, Etherboot can boot
+from an NFS mount.</li>
+
+<li>A Linux or FreeBSD kernel.</li>
+
+<li>Optionally, a NFS server, for providing the disk partitions
+that will be mounted if Linux or FreeBSD is being booted.</li>
+
+<li>Optionally, a RAM disk contained in the loaded image. This can
+be the initial RAM disk if desired.</li>
+
+<li>Software tools for building the download image, and tools for
+debugging.</li>
+</ul>
+</blockquote>
+
+</td>
+<td width="12" height="56" bgcolor="#0F3161"></td>
+</tr>
+</table>
+
+<table summary="pad" width="95%" border="0" cellspacing="0"
+cellpadding="0" align="center">
+<tr>
+<td height="5" bgcolor="#BFCBD9">&nbsp;</td>
+</tr>
+</table>
+
+<table summary="sponsor" width="95%" border="0" cellspacing="3"
+cellpadding="0" align="center" bgcolor="#0F3161">
+<tr>
+<td valign="middle" width="81">
+<div class="c10">Hosted by</div>
+</td>
+<td valign="middle" width="610"><a href="http://developer.berlios.de"><img
+src=
+"http://developer.berlios.de/sflogo.php?group_id=190&amp;type=1"
+width="118" height="52" border="0" alt="BerliOS Logo"></a> </td>
+</tr>
+</table>
+</body>
+</html>
+
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..653ea4e
--- /dev/null
@@ -0,0 +1,254 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta name="generator" content=
+"HTML Tidy for Linux/x86 (vers 1st April 2002), see www.w3.org">
+<title>Welcome to EtherBoot.org</title>
+<meta http-equiv="Content-Type" content=
+"text/html; charset=iso-8859-1">
+<link rel=StyleSheet href="style.css" type="text/css"/>
+</head>
+<body>
+<table summary="welcome" width="95%" border="0" cellspacing="0"
+cellpadding="3" align="center">
+<tr bgcolor="#0F3161">
+<td width="278" bgcolor="#0F3161" valign="bottom">
+<h2 class="c1">Welcome to the</h2>
+</td>
+<td bgcolor="#0F3161">
+</td>
+<td></td>
+</tr>
+
+<tr>
+<td bgcolor="#BFCBD9">
+<div class="c2">EtherBoot Project</div>
+</td>
+<td align="middle">
+<div class="c2">
+<a href="http://osdir.com/Article198.phtml"><img src=
+"http://www.osdir.com/images/2003osdirwinnerbadge.gif" width=
+"125" height="65" border="0" alt="OSDir 2003 Winner Badge"></a>
+</div>
+</td>
+<td bgcolor="#BFCBD9">
+<div class="c4"><a href="index.html" class="c3"><img src=
+"doc/html/images/etherboot_logo.png" alt="Etherboot logo" width=
+"125" height="54" border="0"></a></div>
+</td>
+</tr>
+</table>
+
+<table summary="index" width="95%" border="0" cellspacing="0"
+cellpadding="0" align="center">
+<tr>
+<td bgcolor="#0F3161" width="165" height="56" valign="top">
+<table summary="index.html" width="100%" border="0" cellspacing=
+"10" cellpadding="0" align="right">
+<tr>
+<td height="45">
+<div class="c4"><a href="index.html" class=
+"c5"><b>Home</b></a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/projects/etherboot" class=
+"c3">Sourceforge project home</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://developer.berlios.de/projects/etherboot" class=
+"c3">Berlios project mirror</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/news/?group_id=4233" class=
+"c3">News</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="doc/html/documentation.html" class=
+"c3">Documentation</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://wiki.etherboot.org" class=
+"c3">Wiki</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://rom-o-matic.net/" class=
+"c3">Make ROMs</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/project/showfiles.php?group_id=4233" class=
+"c3">Download source from Sourceforge</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://etherboot.berlios.de/dist/" class=
+"c3">Download source from Berlios (Germany)</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="doc/html/contributing.html" class=
+"c3">Volunteering</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href="http://sourceforge.net/mail/?group_id=4233" class=
+"c3">Mailing Lists</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href=
+"http://etherboot.sourceforge.net/relatedlinks.html" class=
+"c3">Related Links</a></div>
+</td>
+</tr>
+
+<tr>
+<td height="45">
+<div class="c4"><a href=
+"http://etherboot.sourceforge.net/clinks.html" class=
+"c3">Commercial Links</a></div>
+</td>
+</tr>
+</table>
+</td>
+<td width="700" height="56" bgcolor="#FFFFFF" valign="top" align=
+"left">
+<blockquote>
+<h2 class="c6">About EtherBoot</h2>
+
+<p class="c7">Etherboot is a software package for creating ROM
+images that can download code over an Ethernet network to be
+executed on an x86 computer. Many network adapters have a socket
+where a ROM chip can be installed. Etherboot is code that can be
+put in such a ROM. Etherboot is normally used for for booting PCs
+diskless. This is useful in various situations, for example:</p>
+
+<ul class="c11">
+<li>An X-terminal.</li>
+
+<li>Clusters of compute servers.</li>
+
+<li>Routers.</li>
+
+<li>Various kinds of remote servers, e.g. a tape drive server that
+can be accessed with the RMT protocol.</li>
+
+<li>Machines doing tasks in environments unfriendly to disks.</li>
+
+<li>A user platform where remote partitions are mounted over the
+network and you are willing to accept the lower speed compared to
+disk.</li>
+
+<li>Maintaining software for a cluster of equally configured
+workstations centrally.</li>
+</ul>
+
+<p class="c7">Etherboot can boot computers faster than from a disk
+because there are no delays in spinning up disks, etc. A moment's
+calculation will show that even with a 10Mbit Ethernet, sending a
+500kB kernel will take only a couple of seconds typically. With
+100Mbit Ethernet it gets even better.</p>
+
+<p class="c7">Compared to booting from solid-state devices, e.g.
+Flash disks, Etherboot has the advantage of centralising software
+adminstration, the tradeoff being the dependence on a server. This
+can be partly alleviated by providing redundant servers.</p>
+
+<p class="c7">Etherboot can work with RAM disks, NFS filesystems,
+or even local disks, if desired. It's a component technology and
+can be combined with other technologies to do things the way you
+want.</p>
+
+<p class="c7">Etherboot is usually used to load Linux, FreeBSD or
+DOS. However the protocol and boot file formats are general, so
+there is no reason why it could not be used to load arbitrary
+images to a PC, including other OSes.</p>
+
+<p class="c7">Etherboot is Open Source under the GNU General Public
+License Version 2 (GPL2).</p>
+
+<p class="c7">The components needed by Etherboot are</p>
+
+<ul class="c11">
+<li>A bootstrap loader, usually in an EPROM on a network card, or
+installed in the flash BIOS, but could be put anywhere in the
+address space the BIOS probes in. For testing this could be put on
+a floppy disk or a hard disk partition. Some configurations may
+even be always run from a floppy disk (e.g. temporary testing
+setups or pedagogic uses).</li>
+
+<li>A DHCP or bootp server, for returning an IP address and other
+information when sent a MAC (Ethernet card) address.</li>
+
+<li>A tftp server, for sending the kernel images and other files
+required in the boot process. Alternatively, Etherboot can boot
+from an NFS mount.</li>
+
+<li>A Linux or FreeBSD kernel.</li>
+
+<li>Optionally, a NFS server, for providing the disk partitions
+that will be mounted if Linux or FreeBSD is being booted.</li>
+
+<li>Optionally, a RAM disk contained in the loaded image. This can
+be the initial RAM disk if desired.</li>
+
+<li>Software tools for building the download image, and tools for
+debugging.</li>
+</ul>
+</blockquote>
+
+</td>
+<td width="12" height="56" bgcolor="#0F3161"></td>
+</tr>
+</table>
+
+<table summary="pad" width="95%" border="0" cellspacing="0"
+cellpadding="0" align="center">
+<tr>
+<td height="5" bgcolor="#BFCBD9">&nbsp;</td>
+</tr>
+</table>
+
+<table summary="sponsor" width="95%" border="0" cellspacing="3"
+cellpadding="0" align="center" bgcolor="#0F3161">
+<tr>
+<td valign="middle" width="81">
+<div class="c10">Hosted by</div>
+</td>
+<td valign="middle" width="610"><a href="http://sourceforge.net"><img src=
+"http://sourceforge.net/sflogo.php?group_id=4233&amp;type=1" width=
+"88" height="31" border="0" alt="SourceForge Logo"></a>
+</td>
+</tr>
+</table>
+</body>
+</html>
+
diff --git a/index.xhtml b/index.xhtml
new file mode 100644 (file)
index 0000000..f5f0e41
--- /dev/null
@@ -0,0 +1,83 @@
+<blockquote>
+<h2 class="c6">About EtherBoot</h2>
+
+<p class="c7">Etherboot is a software package for creating ROM
+images that can download code over an Ethernet network to be
+executed on an x86 computer. Many network adapters have a socket
+where a ROM chip can be installed. Etherboot is code that can be
+put in such a ROM. Etherboot is normally used for for booting PCs
+diskless. This is useful in various situations, for example:</p>
+
+<ul class="c11">
+<li>An X-terminal.</li>
+
+<li>Clusters of compute servers.</li>
+
+<li>Routers.</li>
+
+<li>Various kinds of remote servers, e.g. a tape drive server that
+can be accessed with the RMT protocol.</li>
+
+<li>Machines doing tasks in environments unfriendly to disks.</li>
+
+<li>A user platform where remote partitions are mounted over the
+network and you are willing to accept the lower speed compared to
+disk.</li>
+
+<li>Maintaining software for a cluster of equally configured
+workstations centrally.</li>
+</ul>
+
+<p class="c7">Etherboot can boot computers faster than from a disk
+because there are no delays in spinning up disks, etc. A moment's
+calculation will show that even with a 10Mbit Ethernet, sending a
+500kB kernel will take only a couple of seconds typically. With
+100Mbit Ethernet it gets even better.</p>
+
+<p class="c7">Compared to booting from solid-state devices, e.g.
+Flash disks, Etherboot has the advantage of centralising software
+adminstration, the tradeoff being the dependence on a server. This
+can be partly alleviated by providing redundant servers.</p>
+
+<p class="c7">Etherboot can work with RAM disks, NFS filesystems,
+or even local disks, if desired. It's a component technology and
+can be combined with other technologies to do things the way you
+want.</p>
+
+<p class="c7">Etherboot is usually used to load Linux, FreeBSD or
+DOS. However the protocol and boot file formats are general, so
+there is no reason why it could not be used to load arbitrary
+images to a PC, including other OSes.</p>
+
+<p class="c7">Etherboot is Open Source under the GNU General Public
+License Version 2 (GPL2).</p>
+
+<p class="c7">The components needed by Etherboot are</p>
+
+<ul class="c11">
+<li>A bootstrap loader, usually in an EPROM on a network card, or
+installed in the flash BIOS, but could be put anywhere in the
+address space the BIOS probes in. For testing this could be put on
+a floppy disk or a hard disk partition. Some configurations may
+even be always run from a floppy disk (e.g. temporary testing
+setups or pedagogic uses).</li>
+
+<li>A DHCP or bootp server, for returning an IP address and other
+information when sent a MAC (Ethernet card) address.</li>
+
+<li>A tftp server, for sending the kernel images and other files
+required in the boot process. Alternatively, Etherboot can boot
+from an NFS mount.</li>
+
+<li>A Linux or FreeBSD kernel.</li>
+
+<li>Optionally, a NFS server, for providing the disk partitions
+that will be mounted if Linux or FreeBSD is being booted.</li>
+
+<li>Optionally, a RAM disk contained in the loaded image. This can
+be the initial RAM disk if desired.</li>
+
+<li>Software tools for building the download image, and tools for
+debugging.</li>
+</ul>
+</blockquote>
diff --git a/style.css b/style.css
new file mode 100644 (file)
index 0000000..8a381f3
--- /dev/null
+++ b/style.css
@@ -0,0 +1,15 @@
+body {
+ background-color: #BFCBD9;
+ color: #000000;
+}
+ul.c11 {color: #0F3161; font-family: Arial, Helvetica, sans-serif}
+div.c10 {color: #BFCBD9; font-family: Arial, Helvetica, sans-serif; text-align: right}
+span.c9 {color: #0F3161; font-family: Arial, Helvetica, sans-serif}
+a.c8 {color: #0F3161; font-family: Arial, Helvetica, sans-serif}
+p.c7 {color: #0F3161; font-family: Arial, Helvetica, sans-serif}
+h2.c6 {color: #0F3161; font-family: Arial, Helvetica, sans-serif}
+a.c5 {color: #FA5053; font-family: Arial, Helvetica, sans-serif}
+div.c4 {text-align: right}
+a.c3 {color: #BFCBD9; font-family: Arial, Helvetica, sans-serif}
+div.c2 {color: #0F3161; font-family: Arial; font-size: 200%; text-align: left}
+h2.c1 {color: #BFCBD9; font-family: Arial, Helvetica, sans-serif}