http://gimel.esc.cam.ac.uk/james/rpld/src/rpld-1.2.tar.gz
authorMichael Brown <mcb30@dolphin.home>
Mon, 10 Mar 2008 23:49:12 +0000 (23:49 +0000)
committerMichael Brown <mcb30@dolphin.home>
Mon, 10 Mar 2008 23:49:12 +0000 (23:49 +0000)
41 files changed:
INSTALL [new file with mode: 0644]
LICENCE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
ana.c [new file with mode: 0644]
client.c [new file with mode: 0644]
client.h [new file with mode: 0644]
config.c [new file with mode: 0644]
doc/rpld.1 [new file with mode: 0644]
doc/rpld.8 [new file with mode: 0644]
doc/rpld.conf.5 [new file with mode: 0644]
linux-ps.c [new file with mode: 0644]
linux-ps.h [new file with mode: 0644]
llc.c [new file with mode: 0644]
llc.h [new file with mode: 0644]
nics/Makefile [new file with mode: 0644]
nics/Makefile,v [new file with mode: 0644]
nics/dm9102/Makefile [new file with mode: 0644]
nics/dm9102/Makefile,v [new file with mode: 0644]
nics/dm9102/README [new file with mode: 0644]
nics/dm9102/dmfix [new file with mode: 0755]
nics/dm9102/dmfix.S [new file with mode: 0644]
nics/dm9102/dmfix.S,v [new file with mode: 0644]
nics/dm9102/dmfix.o [new file with mode: 0644]
nics/dm9102/dmfix.s [new file with mode: 0644]
project.h [new file with mode: 0644]
protocol.c [new file with mode: 0644]
prototypes.h [new file with mode: 0644]
rpl.c [new file with mode: 0644]
rpl.h [new file with mode: 0644]
rpld.1 [new file with mode: 0644]
rpld.c [new file with mode: 0644]
rpld.conf.man [new file with mode: 0644]
rpld.conf.sample [new file with mode: 0644]
rpld.man [new file with mode: 0644]
rpld_conf.lex [new file with mode: 0644]
rpld_conf.tab.c [new file with mode: 0644]
rpld_conf.tab.h [new file with mode: 0644]
rpld_conf.y [new file with mode: 0644]
rpld_conf.yy.c [new file with mode: 0644]
util.c [new file with mode: 0644]

diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..e39ccd1
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,31 @@
+***********************************************************
+RPLD comes with no warranty not even an implied warranty.
+
+By using rpld, you agree to the terms and conditions set
+forth in the LICENCE file which can be found at the top level of
+the rpld distribution.
+***********************************************************
+
+Compilation:
+       Currently rpld is known to compile on the following platforms
+       
+       Linux 2.0.x (*)
+       Linux 2.1.x (*)
+       Linux 2.2.x
+
+(*)    You will get a console message saying "can't find module net-pf-17"
+       which you can ignore.
+
+       To compile rpld, you MUST DO "make depend" and then "make".
+       To compile the utilities/patches/fixes for the ever burgeoning list of
+       network cards type "make nics", you will need a recent version of the
+       bin86 package. I suggest you use the one from the ELKS project.
+
+Installation:
+
+       install rpld in you system binaries directory, and copy 
+       /etc/rpld.conf.sample to /etc/rpld.conf and edit it.
+
+       run rpld somewhere in your init scripts.
+
+
diff --git a/LICENCE b/LICENCE
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/LICENCE
@@ -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/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..f086138
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,276 @@
+# 
+# /*************************************************
+# *     rpld - an IBM style RIPL server            *
+# *************************************************/
+# 
+# /* Copyright (c) 1999, James McKenzie.
+#  *                      All rights reserved
+#  * Copyright (c) 1998, Christopher Lightfoot.
+#  *                      All rights reserved
+#  *
+#  * By using this file, you agree to the terms and conditions set
+#  * forth in the LICENCE file which can be found at the top level of
+#  * the rpld distribution.
+#  *
+#  * IBM is a trademark of IBM corp.
+#  *
+#  */
+
+#
+# $Id: Makefile,v 1.13 2000/07/16 13:18:12 root Exp root $
+#
+# $Log: Makefile,v $
+# Revision 1.13  2000/07/16 13:18:12  root
+# #
+#
+# Revision 1.1  2000/07/16 13:16:42  root
+# #
+#
+# Revision 1.14  1999/09/15 13:46:58  root
+# #
+#
+# Revision 1.13  1999/09/15 00:36:29  root
+# #
+#
+# Revision 1.12  1999/09/14 21:45:17  root
+# #
+#
+# Revision 1.11  1999/09/14 21:38:41  root
+# #
+#
+# Revision 1.10  1999/09/14 21:36:03  root
+# #
+#
+# Revision 1.9  1999/09/14 21:32:13  root
+# #
+#
+# Revision 1.8  1999/09/14 21:26:00  root
+# #
+#
+# Revision 1.7  1999/09/14 21:16:25  root
+# #
+#
+# Revision 1.6  1999/09/14 21:14:38  root
+# #
+#
+# Revision 1.5  1999/09/14 21:13:14  root
+# #
+#
+# Revision 1.4  1999/09/14 17:18:27  root
+# #
+#
+# Revision 1.3  1999/09/14 17:12:39  root
+# #
+#
+# Revision 1.2  1999/09/14 16:17:16  root
+# #
+#
+# Revision 1.1  1999/09/13 12:36:20  root
+# #
+#
+#
+
+# EDITME: this is the delay between transmitted packets in us 
+# you may need to edit this if your clients are slow 
+# if a client drops a packet it will typically wait 1s and then 
+# issue a retransmit request causing a delay. 
+# do make clean after changing this
+
+DEFINES=-DPACKET_DELAY=0
+
+# where do you want all this stuff
+
+DESTDIR=/usr
+
+# Stuff
+CC      = gcc
+INCLUDES = 
+CFLAGS   = -O ${INCLUDES} ${DEFINES}
+LIBS     =
+LDFLAGS  =
+
+# Where to find yacc and lex
+YACC=yacc
+LEX=lex
+
+# Where to find BSD compatible install
+INSTALL=install
+
+################# NO USER SERVICABLE PARTS BELOW HERE
+
+VERSION=1.2
+
+COFLAGS = -l
+
+default:do-it-all
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+do-it-all: all
+       @echo " " Now type make install to install rpld
+       @echo " " or make nics to assemble the adapter utilities
+       @echo " " or make capture to capture RPL traffic
+       @echo " " or make replay to analyse captured RPL traffic
+       @echo " " or make realtime to capture and analyse RPL traffic
+else
+do-it-all: depend
+       @echo " " Now type make again to build rpld
+endif
+
+BINDIR= ${DESTDIR}/sbin
+NROFF=  groff -Tascii -a
+MANDOC= -mandoc
+INSTALL=install
+BINOWN= root
+BINGRP= kmem
+BINMODE=4555
+
+MANOWN= bin
+MANGRP= bin
+MANMODE=444
+
+MANROOT=${DESTDIR}/man/man
+MAN8=   ${MANROOT}8
+MAN8EXT=8
+MAN8SRC=man
+MAN5=   ${MANROOT}5
+MAN5EXT=5
+MAN5SRC=man
+
+PROTOSRC = protocol.c linux-ps.c rpld.c util.c rpl.c llc.c client.c config.c
+HSRCS=rpl.h project.h rpl.h linux-ps.h llc.h client.h 
+
+CSRCS=${PROTOSRC} 
+
+YSRCS=rpld_conf.y
+LSRCS=rpld_conf.lex
+MANSRCS=rpld.man rpld.conf.man
+
+ALLSRCS=${CSRCS}
+
+RCSCFILES=${CSRCS} ${HSRCS}
+RCSFILES=${RCSCFILES} ${YSRCS} ${LSRCS} ${MANSRCS} ana.c
+
+
+PROTOH=prototypes.h
+
+PROG=rpld
+
+OBJS=${CSRCS:%.c=%.o} ${YSRCS:%.y=%.yy.o} ${LSRCS:%.lex=%.tab.o}
+
+YGUFF=${YSRCS:%.y=%.yy.c} ${LSRCS:%.lex=%.tab.c} ${LSRCS:%.lex=%.tab.h}
+
+all:${PROG} ana doc
+
+
+
+
+install: install-prog install-docs
+       @echo " " you can find a sample configuration file
+       @echo " " in this directory called rpld.conf.sample
+       @echo " " your config file should be placed in /etc/rpld.conf
+
+MEN=rpld.conf.5 rpld.8
+TXTMEN=${MEN:%=doc/%}
+
+doc:${MEN} 
+
+doc/rpld.8:rpld.man
+       ${NROFF} ${MANDOC} $< > $@
+doc/rpld.conf.5:rpld.conf.man
+       ${NROFF} ${MANDOC} $< > $@
+
+%.${MAN8EXT}:%.${MAN8SRC}
+       cp $< $@
+
+%.${MAN5EXT}:%.${MAN5SRC}
+       cp $< $@
+
+install-prog:${PROG}
+       ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} ${PROG} ${BINDIR}
+
+install-docs: doc
+       ${INSTALL} -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} rpld.${MAN8EXT} ${MAN8}/rpld.${MAN8EXT}
+       ${INSTALL} -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} rpld.conf.${MAN5EXT} ${MAN5}/rpld.conf.${MAN5EXT}
+
+ana:ana.c
+
+realtime: ana
+       tcpdump -l -x -s 2048 ether[14]=0xfc and ether[15]=0xfc | ana
+
+capture: 
+       tcpdump -x -s 2048 ether[14]=0xfc and ether[15]=0xfc -w capture.dat
+
+replay: ana capture.dat
+       tcpdump -x -r capture.dat | ana
+
+
+nics: nics.doesntexist
+
+nics.doesntexist:
+       ${MAKE} -C nics
+
+${PROG}:${OBJS}
+       ${CC} ${CFLAGS} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBS}
+
+clean: nodep
+       /bin/rm -rf ${OBJS} *% *~ *.o *.BAK core a.out ${PROG}
+       /bin/rm -rf ${YSRCS:%.y=%.yy.c} ${LSRCS:%.lex=%.tab.c}
+       /bin/rm -rf ${LSRCS:%.lex=%.tab.h}
+       /bin/rm -rf ana capture.dat
+       /bin/rm -rf nics.stamp
+       /bin/rm -rf ${MEN} Makefile.bak
+       ${MAKE} -C nics clean
+
+proto: ${PROTOSRCS} ${HSRCS} ${LSRCS:%.lex=%.tab.h}
+       echo -n > ${PROTOH}
+       for i in ${PROTOSRC}; do cproto $$i | grep -v inline >> ${PROTOH}  ; done
+
+
+
+depend: ${RCSFILES} ${YSRCS:%.y=%.tab.h} 
+       makedepend -f- ${INCLUDES} ${ALLSRCS} > .depend
+
+nodep:
+       /bin/rm -rf .depend
+
+tidy:
+       ci -l -m\# ${RCSFILES}
+       indent -ts0 -i2 ${RCSCFILES}
+       ci -l -m\# ana.c
+       indent -ts0 -i2 ana.c
+       /bin/rm -rf nics.stamp
+       ${MAKE} -C nics tidy
+       ci -l -m\# Makefile
+
+checkin:
+       ci -m\# ${RCSFILES}
+checkout:
+       ci -l ${RCSFILES}
+
+MYDIR=rpld-${VERSION}
+
+distrib: 
+       ${MAKE} tidy
+       ${MAKE} proto
+       ${MAKE} doc
+       ${MAKE} clean
+       ${MAKE} yguff
+       ${MAKE} ${TXTMEN}
+       ${MAKE} -C nics
+       cd ..; tar cvfzX ${MYDIR}/DISTRIB/${MYDIR}.tar.gz ${MYDIR}/.xclude ${MYDIR}
+
+yguff:${YGUFF}
+       
+
+%.tab.c:%.y
+       ${YACC} -d -b ${@:%.tab.c=%} $<
+
+%.tab.h:%.y
+       ${YACC} -d -b ${@:%.tab.h=%} $<
+
+%.yy.c:%.lex
+       ${LEX} -o$@ $<
+
+config.o: rpld_conf.tab.h
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7849e65
--- /dev/null
+++ b/README
@@ -0,0 +1,63 @@
+***********************************************************
+RPLD comes with no warranty not even an implied warranty.
+
+By using rpld, you agree to the terms and conditions set
+forth in the LICENCE file which can be found at the top level of
+the rpld distribution.
+***********************************************************
+
+You should read the man pages for rpld(1) and rpld.conf(5) available as text
+in the doc directory.
+
+RPLD implements the IBM RIPL protocol, used to network boot some machines. It
+DOES NOT implement the Novell style RPL/IPX protocol.  If your are not sure
+which protocol you are using see the section "Troubleshooting".
+
+Config file:
+rpld by default looks at the file /etc/rpld.conf. The format of this file is
+as follows (see also rpld.conf.sample):
+
+   At the top level only HOST blocks are allowed, inside the host block you
+   can have FILE blocks, and Ethernet, execute, blocksize, framesize
+   directives.  FILE blocks can contain path, load, offset, length and linux
+   directives.  Each host may have multiple file BLOCKS in which case the
+   BLOCKS will be downloaded in inverse order.
+
+BUGS/FEATURES:
+
+rpld speaks reverse engineered RPL from a very small number of RPL servers 
+and clients (currently one of each).
+
+Linux doesn't have mainstream LLC-1 sockets support. rpld gets LLC-1 packets
+through a PF_PACKET socket, which may impose an unacceptable load on the
+system.
+
+It only runs on Linux.
+
+Some boot ROMs pretend not to see packets if (blocksize % 4) != 0
+
+Troubleshooting:
+
+The default packet transmit rate of flat out may cause problems on old network
+cards or 100Mb networks. Edit project.h and change the definition of 
+PACKET_DELAY. The server gets no acknowledgement from the clients so it can
+only detect a dropped packet when the client times out (typically 1s) and 
+requests a retransmit.
+
+You can dump all RPL packets on your network using tcpdump:
+
+  # tcpdump -x -s 2048 ether[14]=0xfc and ether[15]=0xfc
+
+Also included in the distribution is a program called ana, ana is a horrid
+piece of kludgey C code which will read the output of tcpdump and decode RPL
+packets. The Makefile has some targets which may be helpful. Type "make
+realtime" to capture and decode packets in real time (NB: a feature of ana is
+that the most recently received packet will not be printed until other packet
+arrives).  Alternatively you can do "make capture" and "make replay" to
+analyze packets off-line. We reverse engineered the protocol so it's very
+likely we've not implemented a whole bunch of stuff. If you have problems send
+us your capture.dat files.
+
+The authors can be contacted at <james@fishsoup.dhs.org> and
+                                <chris@ex-parrot.com>
+
diff --git a/ana.c b/ana.c
new file mode 100644 (file)
index 0000000..f23a2ca
--- /dev/null
+++ b/ana.c
@@ -0,0 +1,270 @@
+#include <stdio.h>
+#include <strings.h>
+
+static char *rcsid = "$Id: ana.c,v 1.3 2000/07/16 13:18:10 root Exp $";
+
+/* 
+ * $Log: ana.c,v $
+ * Revision 1.3  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.2  1999/09/13 12:37:06  root
+ * #
+ *
+ * Revision 1.1  1999/09/13 12:36:18  root
+ * #
+ *
+ * Revision 1.4  1999/09/02 09:59:02  root
+ * #
+ *
+ * Revision 1.3  1999/09/02 09:58:02  root
+ * #
+ *
+ */
+
+
+unsigned char pbuf[4096];
+int plen;
+char buf[1024];
+
+get_packet ()
+{
+  char *ptr, *pptr;
+
+  plen = 0;
+
+  while (!feof (stdin) && *buf == '\t')
+    {
+      fgets (buf, sizeof (buf) - 1, stdin);
+    }
+  while (!feof (stdin) && *buf != '\t')
+    {
+      buf[strlen (buf) - 1] = 0;
+      puts (buf);
+      fgets (buf, sizeof (buf) - 1, stdin);
+    }
+  if (feof (stdin))
+    return;
+
+  sscanf (buf, "%x", &plen);
+
+  pptr = pbuf;
+
+
+  while (!feof (stdin) && *buf == '\t')
+    {
+      ptr = buf;
+
+      while (!isxdigit (*ptr))
+        ptr++;
+      while (*ptr)
+        {
+          char hex[3];
+
+          bcopy (ptr, hex, 3);
+          hex[2] = 0;
+          ptr++;
+          ptr++;
+
+          sscanf (hex, "%x", pptr);
+          pptr++;
+
+          while (*ptr && !isxdigit (*ptr))
+            ptr++;
+        }
+
+
+      fgets (buf, sizeof (buf) - 1, stdin);
+    }
+
+}
+
+int
+pull_short (unsigned char *c)
+{
+  int ret;
+  ret = *c;
+  c++;
+  ret <<= 8;
+  ret += *c;
+  return (ret);
+}
+unsigned int
+pull_long (unsigned char *c)
+{
+  unsigned int ret;
+
+  ret = *c;
+  c++;
+  ret <<= 8;
+  ret += *c;
+  c++;
+  ret <<= 8;
+  ret += *c;
+  c++;
+  ret <<= 8;
+  ret += *c;
+
+  return (ret);
+}
+
+dump_hex (unsigned char *pp, int pl)
+{
+  while (pl--)
+    {
+      printf (" %02x", *(pp++));
+    }
+}
+
+dump_hexa (unsigned char *pp, int pl)
+{
+  while (pl--)
+    {
+      int j = *pp;
+      if ((j < ' ') || (j > 126))
+        j = '.';
+      printf (" %02x%c", *pp, j);
+      pp++;
+    }
+}
+
+ana_token (int s, unsigned char *pp, int pl)
+{
+  int i;
+  printf ("    Token 0x%04x:", s);
+  switch (s)
+    {
+    case 0x4003:
+      printf (" The mighty zero: %d\n", pull_long (pp));
+      return;
+    case 0x4006:
+      printf (" My MAC addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+              pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]);
+      return;
+    case 0x4007:
+      printf (" My SAP addr: %02x\n", pp[0]);
+      return;
+    case 0x4009:
+      printf (" Frame len: %d\n", pull_short (pp));
+      return;
+    case 0x400b:
+      printf (" The small zero: %d\n", *pp);
+      return;
+    case 0x400c:
+      printf (" Your MAC addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+              pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]);
+      return;
+    case 0x4011:
+      printf (" Block number: %d\n", pull_long (pp));
+      return;
+    case 0x4018:
+      printf (" data block: (ommitted %d bytes of guff)\n", pl);
+      return;
+    case 0xc005:
+      printf (" IDENT: ");
+      dump_hexa (pp, pl);
+      printf ("\n");
+      return;
+    case 0xc014:
+      printf (" addr block: Load @ 0x%08x, Run @ 0x%08x, Flags: 0x%02x",
+              pull_long (pp), pull_long (pp + 4), pp[8]);
+      switch (pp[8])
+        {
+        case 0x20:
+          printf (" (More to come)");
+          break;
+        case 0xc0:
+          printf (" (All done, execute)");
+          break;
+        default:
+          printf (" ?");
+        }
+
+      printf ("\n");
+      return;
+    default:
+      printf (" ?: ");
+      dump_hex (pp, pl);
+      printf ("\n");
+
+    }
+
+}
+
+int
+ana_frag (unsigned char *pp, int pl)
+{
+  int s;
+
+  while (pl > 0)
+    {
+
+      s = pull_short (pp);
+
+      if (s & 0xc000)
+        {
+          ana_token (s, pp + 2, pl - 2);
+          return;
+        }
+      else
+        {
+          ana_frag (pp + 2, s - 2);
+          pp += s;
+          pl -= s;
+        }
+
+    }
+
+}
+
+
+
+
+main ()
+{
+  int i, s;
+  char *pptr;
+  *buf = '\t';
+
+  while (!feof (stdin))
+    {
+      get_packet ();
+
+      pptr = pbuf;
+      pptr += 2;                /*Length */
+      plen -= 2;
+
+      printf ("  Pack Type:");
+      switch (pull_short (pptr))
+        {
+        case 0x1:
+          printf (" FIND:");
+          break;
+        case 0x2:
+          printf (" FOUND:");
+          break;
+        case 0x10:
+          printf (" SEND.FILE.REQUEST:");
+          break;
+        case 0x20:
+          printf (" FILE.DATA.RESPONSE:");
+          break;
+        default:
+          printf (" 0x%04x ?:", pull_short (pptr));
+        }
+      printf (" Length=%d\n", plen);
+      pptr += 2;
+      plen -= 2;
+
+      s = ana_frag (pptr, plen);
+
+
+      printf ("\n\n");
+    }
+
+  exit (0);
+
+}
diff --git a/client.c b/client.c
new file mode 100644 (file)
index 0000000..a884d8c
--- /dev/null
+++ b/client.c
@@ -0,0 +1,330 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: client.c,v 1.11 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: client.c,v $
+ * Revision 1.11  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.10  1999/09/14 17:12:38  root
+ * #
+ *
+ * Revision 1.9  1999/09/14 17:12:05  root
+ * #
+ *
+ * Revision 1.8  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.7  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.6  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+#include "project.h"
+
+struct client *clients = NULL;
+
+void
+cache_locally (struct clfile *f)
+{
+  int fd;
+  int len;
+
+  fd = open (f->path, O_RDONLY);
+
+  if (fd < 0)
+    {
+      syslog (LOG_ERR, "can't open %s:%m", f->path);
+      return;
+    }
+
+  len = f->length;
+
+  if (len < 0)
+    {
+      len = lseek (fd, 0, SEEK_END);
+      lseek (fd, 0, SEEK_SET);
+    }
+
+  f->data = malloc (len);
+  f->length = len;
+
+  lseek (fd, f->offset, SEEK_SET);
+  read (fd, f->data, len);
+
+  f->offset = 0;
+
+  close (fd);
+
+  free (f->path);
+  f->path = NULL;
+}
+
+/* Cache the last client */
+struct client *
+find_client_by_mac (unsigned char *mac)
+{
+  struct client *pc = NULL, *c = clients;
+
+  while (c)
+    {
+
+      if (memcmp (mac, c->mac, ETH_ALEN) == 0)
+        {
+          if (pc)
+            {                   /*Short circuit for next time */
+              pc->next = c->next;
+              c->next = clients;
+              clients = c;
+            }
+          return (c);
+        }
+
+      pc = c;
+      c = c->next;
+    }
+
+  return (NULL);
+}
+
+void
+client_calc_offsets (struct client *c)
+{
+  struct clfile *f;
+  int bn = 0;
+  int len;
+  int fd;
+  int blocks;
+
+  f = c->files;
+
+  while (f)
+    {
+
+      f->sblock = bn;
+
+      if (f->path)
+        {
+          fd = open (f->path, O_RDONLY);
+          if (fd < 0)
+            {
+              syslog (LOG_ERR, "can't open %s:%m", f->path);
+              return;
+            }
+          len = f->length;
+          if (len < 0)
+            {
+              len = lseek (fd, 0, SEEK_END);
+              len -= f->offset;
+            }
+          close (fd);
+        }
+      else
+        {
+          len = f->length;
+        }
+
+#ifdef DEBUG
+      printf ("%s is %d bytes long gives", f->path, len);
+#endif
+      blocks = len / (c->blocklen);
+      len = len - (blocks * c->blocklen);
+
+      if (len == 0)
+        blocks--;
+
+      bn += blocks;
+      f->eblock = bn;
+
+#ifdef DEBUG
+      printf (" %d blocks [%d,%d]\n", blocks, f->sblock, f->eblock);
+#endif
+
+      bn++;
+
+      f = f->next;
+
+    }
+
+}
+
+
+#define NOTINRANGE(l,v,h) (((v)<(l)) || ((v)>(h)))
+void
+client_get_block (struct client *c, struct rpl_packet *p)
+{
+  struct clfile *f;
+  int toread;
+  int offset;
+
+  f = c->file;
+
+  if ((!f) || (NOTINRANGE (f->sblock, c->blocknum, f->eblock)))
+    {
+      if ((f) && (f->f))
+        {
+          fclose (f->f);
+          f->f = NULL;
+        }
+      f = c->files;
+      while (f && (f->eblock < c->blocknum))
+        f = f->next;
+
+      if (!f)
+        {
+          syslog (LOG_ERR, "this shouldn't happen oops!");
+          return;
+        }
+
+      if (f->path)
+        {
+          f->f = fopen (f->path, "r");
+          if (!f->f)
+            {
+              c->file = NULL;
+
+              syslog (LOG_ERR, "failed to open %s ", f->path);
+              return;
+            }
+
+        }
+
+      c->file = f;
+    }
+
+
+  offset = (c->blocklen) * (c->blocknum - f->sblock);
+
+  if (f->length > 0)
+    {
+      toread = f->length - offset;
+      if (toread > c->blocklen)
+        toread = c->blocklen;
+    }
+  else
+    {
+      toread = c->blocklen;
+    }
+
+  if (f->path)
+    {                           /* A real file */
+      fseek (f->f, offset + f->offset, SEEK_SET);
+      p->datalen = fread (p->data, 1, toread, f->f);
+      if ((p->datalen != toread) && (c->blocknum != f->eblock))
+        {
+          syslog (LOG_ERR, "short read on %s", f->path);
+        }
+    }
+  else
+    {                           /*cached */
+      bcopy (f->data + offset, p->data, toread);
+      p->datalen = toread;
+    }
+
+  p->addr.load = f->load_addr + offset;
+
+}
+
+int
+client_last_block (struct client *c)
+{
+  struct clfile *f;
+  f = c->file;
+
+  if ((!f) || (NOTINRANGE (f->sblock, c->blocknum, f->eblock)))
+    {
+      if ((f) && (f->f))
+        {
+          fclose (f->f);
+          f->f = NULL;
+        }
+      c->file = NULL;
+      f = c->files;
+      while (f && (f->eblock < c->blocknum))
+        f = f->next;
+
+      if (!f)
+        {
+          syslog (LOG_ERR, "this shouldn't happen oops!");
+          return 1;             /*Infact past the last block */
+        }
+    }
+
+  if (!(f->next) && (f->eblock == c->blocknum))
+    {
+      return 1;
+    }
+
+
+  return 0;
+}
+
+void
+client_flush_cache (struct client *c)
+{
+
+  struct clfile *f;
+  f = c->file;
+
+  if ((f) && (f->f))
+    {
+      fclose (f->f);
+      f->f = NULL;
+      c->file = NULL;
+    }
+
+}
+
+clients_check_status ()
+{
+  struct client *c = clients;
+
+  downloading = 0;
+
+  while (c)
+    {
+      if (c->state == ST_FILEDATA)
+        downloading++;
+      c = c->next;
+    }
+
+}
+
+client_dispatch (struct nit *n)
+{
+  struct client *c = clients;
+
+  while (c)
+    {
+      if (c->state == ST_FILEDATA)
+        {
+          file_data_frame (n, c);
+        }
+      c = c->next;
+
+    }
+
+}
diff --git a/client.h b/client.h
new file mode 100644 (file)
index 0000000..f17355a
--- /dev/null
+++ b/client.h
@@ -0,0 +1,82 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+/*
+ * $Id: client.h,v 1.6 2000/07/16 13:18:10 root Exp root $
+ *
+ * $Log: client.h,v $
+ * Revision 1.6  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.5  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.4  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.3  1999/09/13 11:04:13  root
+ * \#
+ *  
+ */
+
+
+
+
+#define ST_START       0
+#define ST_FIND                1
+#define ST_FOUND       2
+#define ST_SENDFILE    3
+#define ST_FILEDATA    4
+#define ST_DONE                5
+
+struct clfile
+  {
+    char *path;
+    unsigned char *data;
+
+    int offset;
+    int length;
+
+    u32 load_addr;
+
+    int sblock, eblock;
+    struct clfile *next;
+
+    FILE *f;
+  };
+
+struct client
+  {
+    int state;
+
+    u8 mac[ETH_ALEN];
+    int framelen;
+    int blocknum;
+    int blocklen;
+
+
+    u32 run_addr;
+
+    struct clfile *files;
+    struct clfile *file;
+
+    struct client *next;
+  };
diff --git a/config.c b/config.c
new file mode 100644 (file)
index 0000000..3527dbd
--- /dev/null
+++ b/config.c
@@ -0,0 +1,135 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: config.c,v 1.5 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: config.c,v $
+ * Revision 1.5  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.4  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.3  1999/09/13 11:08:34  root
+ * \#
+ *
+ * Revision 1.2  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.1  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+#include "project.h"
+
+#include "rpld_conf.tab.h"
+
+extern FILE *yyin;
+
+void
+do_linux_kernel (struct client *c, struct clfile *f)
+{
+  struct clfile *bootsect, *kernel;
+  int loaderlen;
+
+#define VMLINUZ_LOADLEN_OFFSET 497
+
+/* The book says we should load top downwards so 
+ * we init bottom upwards ie fr is the second stage 
+ * bootloader at 0x92000 */
+
+/* Firstly we need to load the bootsector to work out stuff */
+  bootsect = (struct clfile *) malloc (sizeof (struct clfile));
+  bzero (bootsect, sizeof (struct clfile));
+
+  bootsect->path = strdup (f->path);
+  bootsect->offset = 0;
+  bootsect->length = 0x200;
+  bootsect->load_addr = 0x90000;
+
+  cache_locally (bootsect);
+
+  if (!bootsect->data)
+    {
+      fprintf (stderr, "Couldn't open %s for reading\n", f->path);
+      exit (1);
+    }
+  if (bootsect->length < 0x200)
+    {
+      fprintf (stderr, "Only read %d bytes from %s\n", bootsect->length, f->path);
+      exit (1);
+    }
+
+  /* FIXME: here we should add a pointer to the kernel parameter string */
+  /* and allocate a clfile structure to hold it */
+
+  loaderlen = (bootsect->data[VMLINUZ_LOADLEN_OFFSET]) ?
+    (0x200 * (bootsect->data[VMLINUZ_LOADLEN_OFFSET])) : 0x800;
+
+
+  kernel = (struct clfile *) malloc (sizeof (struct clfile));
+  bzero (kernel, sizeof (struct clfile));
+
+  kernel->path = strdup (f->path);
+  kernel->offset = loaderlen + 0x200;
+  kernel->length = -1;
+  kernel->load_addr = 0x10000;
+
+  kernel->next = c->files;
+  c->files = kernel;
+
+  /* Tag in the bootsector */
+  bootsect->next = kernel;
+  c->files = bootsect;
+
+
+  /* Now set up f the secondary bootloader */
+
+  f->offset = 0x200;
+  f->length = loaderlen;
+  f->load_addr = 0x90200;
+
+}
+
+
+void
+parse_config ()
+{
+  FILE *file;
+
+  file = fopen (CONFIG_FILE, "r");
+
+  if (!file)
+    {
+      fprintf (stderr, "Cannot open config file %s\n", CONFIG_FILE);
+      exit (1);
+    }
+
+  yyin = file;
+
+  yyparse ();
+
+  fclose (file);
+
+
+}
diff --git a/doc/rpld.1 b/doc/rpld.1
new file mode 100644 (file)
index 0000000..bbf0015
--- /dev/null
@@ -0,0 +1,49 @@
+<beginning of page>
+RPLD.CONF ( 5 ) UNIX Programmer's Manual RPLD.CONF ( 5 )
+NAME                 
+ rpld <-> an RPL/RIPL remote boot server
+SYNOPSIS                 
+ rpld
+WARRANTY                 
+ rpld DOES NOT come with ANY WARRANTY, NOT even an IMPLIED WARRANTY.
+DESCRIPTION                 
+ rpld will net-boot IBM style RPL boot ROMs. Communication between the
+ client and the server is done in LLC-1 ui/C frames with the source and
+ destination SAP both being 0xfc. On booting the client transmits a FIND
+ frame containing the client's MAC address, adapter type and frame length.
+ The server replies with a FOUND frame containing the server's MAC address
+ and a possibly smaller frame length. The client issues a SEND.FILE.RE<hy>
+ QUEST frame requesting the first block of the boot file. The server then
+ issues a sequence of FILE.DATA.RESPONSE frames with increasing block num<hy>
+ bers. The FILE.DATA.RESPONSE frames contain a load address and an execute
+ address and a flag. If the client fails to receive a FILE.DATA.RESPONSE
+ frame within a certain period it sends another SEND.FILE.REQUEST frame
+ requesting the block which follows the last block that was successfully
+ received. On the last FILE.DATA.RESPONSE frame the server sets a special
+ value of the flags which cause the client to transfer execution to the
+ execute address specified in the frame.
+ The server starts by reading the configuration file in /etc/rpld.conf,
+ see rpld.conf(5), After the configuration file has been read, it opens
+ the system's default network interface and listens for RPL frames. The
+ server recalculates the length of all the files to be downloaded every
+ time it receives a SEND.FILE.REQUEST frame.
+BUGS                 
+  Solenopsis invicta Buren
+  rpld (probably) doesn't support the new bzImage format correctly.
+  rpld doesn't reload the first 512 bytes of Linux kernels automatically.
+  There is no way to make rpld re-read its configuration file.
+  rpld needs to meet more network cards.
+NOTES                 
+ IBM is a trademark of IBM Corp.
+FILES                 
+ /usr/sbin/rpld 
+ /etc/rpld.conf 
+ /rplboot 
+SEE  ALSO               
+ rpld.conf(5),
+ bootpd(1),
+ dhcpd(1),
+ http://bullard.esc.cam.ac.uk/~james/rpld;
+AUTHORS  AND  COPYRIGHT             
+ (c) 1999 James McKenzie, and Christopher Lightfoot. All rights reserved.
+ Linux  Sep 14, 1999 1
diff --git a/doc/rpld.8 b/doc/rpld.8
new file mode 100644 (file)
index 0000000..48f47e0
--- /dev/null
@@ -0,0 +1,50 @@
+<beginning of page>
+RPLD ( 8 ) UNIX System Manager's Manual RPLD ( 8 )
+NAME                 
+ rpld <-> an RPL/RIPL remote boot server
+SYNOPSIS                 
+ rpld
+WARRANTY                 
+ rpld DOES NOT come with ANY WARRANTY, NOT even an IMPLIED WARRANTY.
+DESCRIPTION                 
+ rpld will net-boot IBM style RPL boot ROMs. Communication between the
+ client and the server is done in LLC-1 ui/C frames with the source and
+ destination SAP both being 0xfc. On booting the client transmits a FIND
+ frame containing the client's MAC address, adapter type and frame length.
+ The server replies with a FOUND frame containing the server's MAC address
+ and a possibly smaller frame length. The client issues a SEND.FILE.RE<hy>
+ QUEST frame requesting the first block of the boot file. The server then
+ issues a sequence of FILE.DATA.RESPONSE frames with increasing block num<hy>
+ bers. The FILE.DATA.RESPONSE frames contain a load address and an execute
+ address and a flag. If the client fails to receive a FILE.DATA.RESPONSE
+ frame within a certain period it sends another SEND.FILE.REQUEST frame
+ requesting the block which follows the last block that was successfully
+ received. On the last FILE.DATA.RESPONSE frame the server sets a special
+ value of the flags which cause the client to transfer execution to the
+ execute address specified in the frame.
+ The server starts by reading the configuration file in /etc/rpld.conf,
+ see rpld.conf(5), After the configuration file has been read, it opens
+ the system's default network interface and listens for RPL frames. The
+ server recalculates the length of all the files to be downloaded every
+ time it receives a SEND.FILE.REQUEST frame.
+BUGS                 
+  Solenopsis invicta Buren
+  rpld (probably) doesn't support the new bzImage format correctly.
+  rpld doesn't reload the first 512 octets of Linux kernels automatical<hy>
+ ly.
+  There is no way to make rpld re-read its configuration file.
+  rpld needs to meet more network adapters.
+NOTES                 
+ IBM is a trademark of IBM Corp.
+FILES                 
+ /usr/sbin/rpld 
+ /etc/rpld.conf 
+ /rplboot 
+SEE  ALSO               
+ rpld.conf(5),
+ bootpd(1),
+ dhcpd(1),
+ http://bullard.esc.cam.ac.uk/~james/rpld;
+AUTHORS  AND  COPYRIGHT             
+ (c) 1999 James McKenzie, and Christopher Lightfoot. All rights reserved.
+ Linux  Sep 14, 1999 1
diff --git a/doc/rpld.conf.5 b/doc/rpld.conf.5
new file mode 100644 (file)
index 0000000..89cc9ec
--- /dev/null
@@ -0,0 +1,159 @@
+<beginning of page>
+RPLD.CONF ( 5 ) UNIX Programmer's Manual RPLD.CONF ( 5 )
+NAME                 
+ rpld.conf <-> rpld configuration file
+DESCRIPTION                 
+ The rpld.conf file is the configuration file for the rpld(1) program. It
+ consists of a number of HOST blocks of the form:
+ HOST {
+  ...
+ };
+ Within the HOST blocks there can be ethernet, execute, framesize and
+ blocksize directives and FILE blocks. FILE blocks are of the form:
+  FILE {
+   ...
+  };
+ Within FILE blocks there can be path, offset, length, load and linux di<hy>
+ rectives. Directives are of the form
+  foo = something;
+ or
+  bar;
+ and are detailed below. Comments are allowed in the configuration file
+ and can either be in C-form (i.e. starting with /* and ending with */) or
+ C++ form (starting with // and ending at the line break).
+DIRECTIVES                 
+ Directives are of the form
+  foo = something;
+ or
+  bar;
+ If something is a string it should be entered between quotes. Numbers are
+ assumed to be decimal unless preceded by 0x in which case they are inter<hy>
+ preted in hexadecimal. MAC addresses should be given as 6 octets in hex<hy>
+ adecimal without the leading 0x. The octets should be separated by
+ colons.
+  number = 131;
+  hexnumber = 0x7382;
+  macaddr = 08:00:02:43:21:22;
+  string = "fish soup";
+ blocksize
+ This directive sets the maximum size in octets of data that is trans<hy>
+ mitted in each FILE.DATA.RESPONSE frame that the server sends. The
+ block size should be at least 48 octets smaller than the frame size.
+ After the client negotiates a frame size the block size is checked and
+ if it is no longer 48 octets smaller than frame size it is adjusted ac<hy>
+ cordingly. Some buggy boot ROMs will fail if block size is not a multi<hy>
+ ple of four, accordingly you should be aware of the situation that
+ could arise if the client was to negotiate the block size down to some<hy>
+ thing that wasn't a multiple of four.
+  blocksize = 528;
+<beginning of page>
+ ethernet
+ This directive sets the MAC address of the client referenced in this
+ HOST block. It should be formatted as six octets separated by colons.
+ e.g..
+  ethernet = 00:60:6e:33:4f:2c;
+ execute
+ This directive sets the execute address that control is transferred to
+ when downloading has finished. It should be a number in either decimal
+ or hexadecimal.
+  execute = 0x92000;
+ It is not clear whether or not the client's Ethernet adapter is or
+ should be shut down prior to the transfer of control. This may cause
+ problems on systems where the Ethernet adapter in the client can do DMA
+ directly into host memory. As the adapter may continue writing to the
+ buffers that the boot ROM set up, it may be necessary to download a
+ small program to reset the Ethernet adapter. See code under the nics/
+ directory in the source distribution for examples.
+ framesize
+ This directive sets the maximum size of the frames that the server uses
+ to communicate with the client. The actual frame size used is negotiat<hy>
+ ed between the client and the server, the server will force the client
+ to use this value if it requests a larger one. The maximum frame size
+ that Ethernet can support is 1500, and this is the default value.
+  framesize = 576;
+ length
+ This directive sets the number of octets transmitted to the client for
+ this FILE block. If this directive is not specified the server trans<hy>
+ mits data until an end of file condition occurs.
+  length = 4096;
+ would send 4096 octets from the file.
+ linux
+ This directive takes no argument. It indicates to rpld(1) that the file
+ specified in the path directive is a Linux kernel image. rpld(1) then
+ analyses the kernel image and generates three FILE blocks corresponding
+ to the primary boot loader, secondary boot loader, and data portions of
+ the image. It then sets a default execute address which points to the
+ secondary boot loader which is loaded at 0x90200. The execute address
+ may be over-ridden with an execute directive which appears AFTER the
+ FILE block.
+  linux;
+ rpld(1) may have problems with bzImage kernels.
+ load
+ This directive sets the load address for this FILE block. Data is read
+ from offset octets into the file at copied to the client starting at
+ the address specified by the load directive. The FILE block
+ FILE {
+  path = "/rplboot/fish";
+  offset = 512;
+  length = 4096;
+  load = 0x90200;
+ };
+ would load 4096 octets from the file /rplboot/fish starting 512 octets
+ into the file into the client's memory starting at address 0x90200. (so
+<beginning of page>
+ the 513th byte of the file will load to address 0x90200)
+ offset
+ This directive sets the offset for this FILE block. Data is read from
+ offset octets into the file at copied to the client starting at the ad<hy>
+ dress specified by the load directive.
+  offset = 512;
+ path
+ This directive sets the path to the file that is to be downloaded. The
+ file must exist, and is examined at startup and on reception of
+ SEND.FILE.REQUEST frames.
+  path = "/rplboot/fish";
+NOTES                 
+ The server downloads the FILE blocks in the inverse order to that in
+ which they were specified. Boot ROMs typically prefer the blocks to ar<hy>
+ rive in decreasing load address, so you should specify them in increasing
+ load address. The server recalculates the length of all the files speci<hy>
+ fied on reception of a SEND.FILE.REQUEST frame. If the file changes size
+ during downloading the server will attempt to read to the original length
+ of the file. If it encounters an end of file condition empty FILE DATA
+ FRAMES will be sent. For Linux kernel images the first sector of the ker<hy>
+ nel image will only be read from disk when rpld is started. The first
+ sector contains information such as the default root device and the
+ length of secondary boot loader. You should therefore restart rpld if
+ you change the version of the kernel you are downloading. The order of
+ directives is important: the execute directive, if present, should always
+ come after the linux directive.
+Example                 
+ A complete example file using every directive:
+ // Sample rpld.conf file
+ /* (c) 1999 James McKenzie and
+  * Christopher Lightfoot
+  * All rights reserved.
+  */
+ HOST {
+  ethernet=08:00:02:32:1e:fc;
+   FILE {
+   path="/rplboot/vmlinuz";
+   linux;
+  };
+  FILE {
+   path="/rplboot/vesarom.img";
+   offset=0x200;
+   length=0x400;
+   load=0x92000;
+  };
+  execute=0x92000;
+ };
+FILES                 
+ /etc/rpld.conf The rpld(1) configuration file.
+SEE  ALSO               
+ rpld(1),  bootpd(1),  dhcpd(1), 
+ http://bullard.esc.cam.ac.uk/~james/rpld; 
+AUTHORS  AND  COPYRIGHT             
+<beginning of page>
+ (c) 1999 James McKenzie, and Christopher Lightfoot. All rights reserved.
+ Linux  Sep 14, 1999 4
diff --git a/linux-ps.c b/linux-ps.c
new file mode 100644 (file)
index 0000000..02efe66
--- /dev/null
@@ -0,0 +1,223 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: linux-ps.c,v 1.6 2000/07/16 13:18:10 root Exp root $";
+
+/* 
+ * $Log: linux-ps.c,v $
+ * Revision 1.6  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.5  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.4  1999/09/11 16:52:15  root
+ * \#
+ *
+ * Revision 1.3  1999/09/11 16:34:50  root
+ * \#
+ *
+ * Revision 1.2  1999/09/10 22:06:43  root
+ * \#
+ *
+ * Revision 1.1  1999/09/10 17:32:26  root
+ * \#
+ *
+ * Revision 1.1  1999/05/17 21:53:33  root
+ * Initial revision
+ *
+ */
+
+/*
+ * CAUTION THIS CODE COMES WITH NO WARARNTY IT IS COPYRIGHT 1999 BY
+ * James McKenzie All rights reserved. GPL applies
+ */
+
+
+#include "project.h"
+
+#undef __GLIBC__
+#include <linux/socket.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/if_packet.h>
+#include <linux/route.h>
+#define __GLIBC__
+
+
+
+static void
+get_hwaddr (unsigned char *name, unsigned char *addr)
+{
+  struct ifreq ifr;
+  int fd = socket (AF_INET, SOCK_DGRAM, 0);
+
+  if (fd < 0)
+    {
+      syslog (LOG_ERR, "socket:%m");
+      return;
+    }
+  bcopy (name, &ifr.ifr_name, sizeof (ifr.ifr_name));
+
+
+  /* find my own hardware address */
+  if (ioctl (fd, SIOCGIFHWADDR, &ifr) < 0)
+    {
+      close (fd);
+      syslog (LOG_ERR, "ioctl(SIOCGIFHWADDR):%m");
+      exit (-1);
+    }
+  close (fd);
+
+
+  bcopy (&ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+
+}
+
+void
+nit_close (struct nit *n)
+{
+  if (!n)
+    return;
+
+  close (n->fd);
+  free (n->name);
+
+/*FIXME: we should demulticast at this point but we need to have some 
+ *mechanism for detecting if anyone else wants it
+ */
+
+  free (n);
+}
+
+struct nit *
+nit_open (char *name)
+{
+  struct nit *n;
+  struct sockaddr sa;
+  int fd;
+
+  if (!name)
+    name = "eth0";
+
+  fd = socket (PF_PACKET, SOCK_PACKET, htons (ETH_P_ALL));
+
+  if (fd < 0)
+    fd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL));
+
+  if (fd < 0)
+    {
+      syslog (LOG_ERR, "socket:%m");
+      return (NULL);
+    }
+
+  bzero (&sa, sizeof (sa));
+  sa.sa_family = AF_INET;
+  memcpy (&sa.sa_data, name, sizeof (sa.sa_data));
+
+  if (bind (fd, &sa, sizeof (sa)) < 0)
+    {
+      close (fd);
+      syslog (LOG_ERR, "bind:%m");
+      return (NULL);
+    }
+
+
+  n = (struct nit *) malloc (sizeof (struct nit));
+
+  n->fd = fd;
+  n->name = (char *) malloc (MAX_NAME_LEN);
+  bzero (n->name, MAX_NAME_LEN);
+
+  strcpy (n->name, name);
+  get_hwaddr (n->name, n->mac);
+
+  return (n);
+}
+
+void
+nit_send_frame (struct nit *n, unsigned char *frame, int len)
+{
+  struct sockaddr sa;
+  struct msghdr msg;
+  struct iovec iov;
+
+  bzero (&msg, sizeof (msg));
+  bzero (&sa, sizeof (sa));
+
+  sa.sa_family = AF_INET;
+  strncpy (sa.sa_data, n->name, sizeof (sa.sa_data));
+
+  if (sendto (n->fd, frame, len, 0, &sa, sizeof (sa)) < 0)
+    syslog (LOG_ERR, "sendto: %m");
+
+  return;
+
+}
+
+
+void
+nit_multicast (struct nit *n, unsigned char *mcaddr)
+{
+  struct ifreq ifr;
+  int fd = socket (AF_INET, SOCK_DGRAM, 0);
+
+  strncpy (ifr.ifr_name, n->name, sizeof (ifr.ifr_name));
+
+  ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+
+  bcopy (mcaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+  if (ioctl (fd, SIOCADDMULTI, &ifr) < 0)
+    {
+      close (fd);
+      syslog (LOG_ERR, "ioctl(SIOCADDMULTI):%m");
+    }
+}
+
+int
+nit_read_packet (struct nit *n, char *buf, int len, struct timeval *tv)
+{
+  fd_set rfds;
+  int ret;
+
+  FD_ZERO (&rfds);
+  FD_SET (n->fd, &rfds);
+
+
+  ret = select ((n->fd) + 1, &rfds, NULL, NULL, tv);
+
+  if (ret < 0)
+    return (ret);
+
+  if (FD_ISSET ((n->fd), &rfds))
+    {
+
+      ret = read (n->fd, buf, len);
+
+      return (ret);
+    }
+  else
+    {
+      return (0);
+    }
+
+}
diff --git a/linux-ps.h b/linux-ps.h
new file mode 100644 (file)
index 0000000..7142e08
--- /dev/null
@@ -0,0 +1,47 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+/*
+ * $Id: linux-ps.h,v 1.3 2000/07/16 13:18:10 root Exp root $
+ *
+ * $Log: linux-ps.h,v $
+ * Revision 1.3  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.2  1999/09/13 12:36:18  root
+ * #
+ *
+ * Revision 1.1  1999/09/13 11:17:35  root
+ * \#
+ *  
+ */
+
+
+#define MAX_NAME_LEN 1024
+
+struct nit
+  {
+    int fd;
+    char *name;
+    unsigned char mac[6];
+  };
+
+#define nit_mac(n)     ((n)->mac)
diff --git a/llc.c b/llc.c
new file mode 100644 (file)
index 0000000..f630818
--- /dev/null
+++ b/llc.c
@@ -0,0 +1,86 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: llc.c,v 1.7 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: llc.c,v $
+ * Revision 1.7  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.6  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.5  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.4  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+
+
+#include "project.h"
+
+void
+send_llc_frame (struct nit *n, unsigned char dsap, unsigned char ssap, unsigned char *dmac, unsigned char *ibuf, int len)
+{
+  unsigned char buf[MAX_FRAME_LEN];
+  struct llchdr *h = (struct llchdr *) buf;
+
+  bcopy (dmac, h->h_dest, ETH_ALEN);
+  bcopy (nit_mac (n), h->h_source, ETH_ALEN);
+
+  h->h_len = htons (len + LLC_SAP_LEN);
+
+  h->h_dsap = dsap;
+  h->h_ssap = ssap;
+  h->h_flags = LLC_UIC;
+
+  bcopy (ibuf, buf + LLC_HDR_LEN, len);
+
+  len += LLC_HDR_LEN;
+  nit_send_frame (n, buf, len);
+}
+
+void
+llc_recv_packet (struct nit *n, unsigned char *buf, int len)
+{
+  struct llchdr *h = (struct llchdr *) buf;
+  int llclen;
+
+  if ((h->h_dsap == RPL_SAP) && (h->h_ssap == RPL_SAP))
+    {
+
+#ifdef DEBUG
+      printf ("dest: %s ", ethtoa (&h->h_dest));
+      printf ("source: %s ", ethtoa (&h->h_source));
+      llclen = ntohs (h->h_len);
+      printf ("len: 0x%04x ", llclen);
+      printf ("dsap:%02x ssap:%02x flags:%02x \n", h->h_dsap, h->h_ssap, h->h_flags);
+#endif
+
+      rpl_packet_recvd (n, buf + LLC_HDR_LEN, llclen - LLC_SAP_LEN);
+
+    }
+
+}
diff --git a/llc.h b/llc.h
new file mode 100644 (file)
index 0000000..b8da555
--- /dev/null
+++ b/llc.h
@@ -0,0 +1,56 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+/*
+ * $Id: llc.h,v 1.6 2000/07/16 13:18:10 root Exp root $
+ *
+ * $Log: llc.h,v $
+ * Revision 1.6  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.5  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.4  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.3  1999/09/13 11:04:13  root
+ * \#
+ *  
+ */
+
+#define RPL_SAP 0xfc
+
+#define LLC_HDR_LEN 17
+#define LLC_SAP_LEN 3
+
+#define LLC_UIC     0x3
+
+/* The LLC-1 headers as it comes off the wire */
+struct llchdr
+  {
+    unsigned char h_dest[ETH_ALEN];
+    unsigned char h_source[ETH_ALEN];
+    unsigned short h_len;
+    unsigned char h_dsap;
+    unsigned char h_ssap;
+    unsigned char h_flags;
+  };
diff --git a/nics/Makefile b/nics/Makefile
new file mode 100644 (file)
index 0000000..14ac73d
--- /dev/null
@@ -0,0 +1,28 @@
+# 
+# /*************************************************
+# *     rpld - an IBM style RIPL server            *
+# *************************************************/
+# 
+# /* Copyright (c) 1999, James McKenzie.
+#  *                      All rights reserved
+#  * Copyright (c) 1999, Christopher Lightfoot.
+#  *                      All rights reserved
+#  *
+#  * By using this file, you agree to the terms and conditions set
+#  * forth in the LICENCE file which can be found at the top level of
+#  * the rpld distribution.
+#  *
+#  * IBM is a trademark of IBM corp.
+#  *
+#  */
+
+SUBDIRS=dm9102
+
+default:
+       for i in $(SUBDIRS); do ${MAKE} -C $$i ; done
+clean:
+       for i in $(SUBDIRS); do ${MAKE} -C $$i clean ; done
+tidy:
+       for i in $(SUBDIRS); do ${MAKE} -C $$i tidy ; done
+       ci -l -m\# Makefile
+
diff --git a/nics/Makefile,v b/nics/Makefile,v
new file mode 100644 (file)
index 0000000..518bc96
--- /dev/null
@@ -0,0 +1,52 @@
+head   1.1;
+access;
+symbols;
+locks
+       root:1.1; strict;
+comment        @# @;
+
+
+1.1
+date   2000.07.16.13.16.42;    author root;    state Exp;
+branches;
+next   ;
+
+
+desc
+@@
+
+
+1.1
+log
+@#
+@
+text
+@# 
+# /*************************************************
+# *     rpld - an IBM style RIPL server            *
+# *************************************************/
+# 
+# /* Copyright (c) 1999, James McKenzie.
+#  *                      All rights reserved
+#  * Copyright (c) 1999, Christopher Lightfoot.
+#  *                      All rights reserved
+#  *
+#  * By using this file, you agree to the terms and conditions set
+#  * forth in the LICENCE file which can be found at the top level of
+#  * the rpld distribution.
+#  *
+#  * IBM is a trademark of IBM corp.
+#  *
+#  */
+
+SUBDIRS=dm9102
+
+default:
+       for i in $(SUBDIRS); do ${MAKE} -C $$i ; done
+clean:
+       for i in $(SUBDIRS); do ${MAKE} -C $$i clean ; done
+tidy:
+       for i in $(SUBDIRS); do ${MAKE} -C $$i tidy ; done
+       ci -l -m\# Makefile
+
+@
diff --git a/nics/dm9102/Makefile b/nics/dm9102/Makefile
new file mode 100644 (file)
index 0000000..294e071
--- /dev/null
@@ -0,0 +1,60 @@
+# 
+# /*************************************************
+# *     rpld - an IBM style RIPL server            *
+# *************************************************/
+# 
+# /* Copyright (c) 1999, James McKenzie.
+#  *                      All rights reserved
+#  * Copyright (c) 1999, Christopher Lightfoot.
+#  *                      All rights reserved
+#  *
+#  * By using this file, you agree to the terms and conditions set
+#  * forth in the LICENCE file which can be found at the top level of
+#  * the rpld distribution.
+#  *
+#  * IBM is a trademark of IBM corp.
+#  *
+#  */
+
+#
+# $Id: Makefile,v 1.1 2000/07/16 13:16:41 root Exp $
+#
+# $Log: Makefile,v $
+# Revision 1.1  2000/07/16 13:16:41  root
+# #
+#
+# Revision 1.3  1999/09/14 17:18:27  root
+# #
+#
+# Revision 1.2  1999/09/14 17:12:38  root
+# #
+#
+# Revision 1.1  1999/09/14 16:17:15  root
+# #
+#
+# Revision 1.1  1999/09/13 12:36:20  root
+# #
+#
+#
+
+AS86=/software/src/bin86/as/as86 -0 -a 
+LD86=ld86 -s -d
+
+dmfix:dmfix.o
+       $(LD86) -o $@ $<
+
+dmfix.o: dmfix.s
+       $(AS86) -o $@ $<
+
+dmfix.s: dmfix.S 
+       $(CPP) -traditional $< -o $@
+
+clean:
+       /bin/rm -rf dmfix dmfix.s dmfix.o
+
+tidy:
+       ci -m\# -l dmfix.S
+       ci -m\# -l Makefile
+
+install: dmfix
+       cp dmfix /rplboot
diff --git a/nics/dm9102/Makefile,v b/nics/dm9102/Makefile,v
new file mode 100644 (file)
index 0000000..563ccc9
--- /dev/null
@@ -0,0 +1,81 @@
+head   1.1;
+access;
+symbols;
+locks
+       root:1.1; strict;
+comment        @# @;
+
+
+1.1
+date   2000.07.16.13.16.41;    author root;    state Exp;
+branches;
+next   ;
+
+
+desc
+@@
+
+
+1.1
+log
+@#
+@
+text
+@# 
+# /*************************************************
+# *     rpld - an IBM style RIPL server            *
+# *************************************************/
+# 
+# /* Copyright (c) 1999, James McKenzie.
+#  *                      All rights reserved
+#  * Copyright (c) 1999, Christopher Lightfoot.
+#  *                      All rights reserved
+#  *
+#  * By using this file, you agree to the terms and conditions set
+#  * forth in the LICENCE file which can be found at the top level of
+#  * the rpld distribution.
+#  *
+#  * IBM is a trademark of IBM corp.
+#  *
+#  */
+
+#
+# $Id: Makefile,v 1.3 1999/09/14 17:18:27 root Exp $
+#
+# $Log: Makefile,v $
+# Revision 1.3  1999/09/14 17:18:27  root
+# #
+#
+# Revision 1.2  1999/09/14 17:12:38  root
+# #
+#
+# Revision 1.1  1999/09/14 16:17:15  root
+# #
+#
+# Revision 1.1  1999/09/13 12:36:20  root
+# #
+#
+#
+
+AS86=/software/src/bin86/as/as86 -0 -a 
+LD86=ld86 -s -d
+
+dmfix:dmfix.o
+       $(LD86) -o $@@ $<
+
+dmfix.o: dmfix.s
+       $(AS86) -o $@@ $<
+
+dmfix.s: dmfix.S 
+       $(CPP) -traditional $< -o $@@
+
+clean:
+       /bin/rm -rf dmfix dmfix.s dmfix.o
+
+tidy:
+       ci -m\# -l dmfix.S
+       ci -m\# -l Makefile
+
+install: dmfix
+       cp dmfix /rplboot
+@
diff --git a/nics/dm9102/README b/nics/dm9102/README
new file mode 100644 (file)
index 0000000..083300c
--- /dev/null
@@ -0,0 +1,17 @@
+dmfix - DAVICOM Fast Ethernet killer
+
+Copyright (c) 1999, James McKenzie.
+                     All rights reserved
+Copyright (c) 1999, Christopher Lightfoot.
+                      All rights reserved
+
+By using this file, you agree to the terms and conditions set
+forth in the LICENCE file which can be found at the top level of
+the rpld distribution.
+
+This code fixes a problem with the DAVICOM DM9102 Fast ethernet chip and
+boot ROM. The chip is left scribbling over memory at 0x96000 when the
+ROM transfers controll to the RPL image. This code hunts out the DM9102
+and resets it. Once the chip is reset it transfers control to 9020:0000,
+which is typically the linux 2ndary boot loader.
+
diff --git a/nics/dm9102/dmfix b/nics/dm9102/dmfix
new file mode 100755 (executable)
index 0000000..14b6341
Binary files /dev/null and b/nics/dm9102/dmfix differ
diff --git a/nics/dm9102/dmfix.S b/nics/dm9102/dmfix.S
new file mode 100644 (file)
index 0000000..d74a6f1
--- /dev/null
@@ -0,0 +1,333 @@
+! Davicom Bootloader fixup, switches off the DAVICOM fast ethernet chip
+! before transfering control to the RPL'd image, so that the chip
+! doesn't scribble all over it while it relocates
+!
+! This image needs 2k of memory, and can be loaded anywhere, after
+! it does its stuff it does jmp 0x9020:0x0
+!
+! 
+!
+! $Id: dmfix.S,v 1.1 2000/07/16 13:16:40 root Exp $ll rights reserved
+!
+!  Copyright (c) 1999, James McKenzie.
+!                       All rights reserved
+!  Copyright (c) 1999, Christopher Lightfoot.
+!                       All rights reserved
+! 
+!  By using this file, you agree to the terms and conditions set
+!  forth in the LICENCE file which can be found at the top level of
+!  the rpld distribution.
+! 
+!  DAVICOM is a trademark of DAVICOM semiconductor inc.
+! 
+!
+!
+! $Log: dmfix.S,v $
+! Revision 1.1  2000/07/16 13:16:40  root
+! #
+!
+! Revision 1.4  1999/09/14 17:18:27  root
+! #
+!
+! Revision 1.3  1999/09/13 12:32:26  root
+! #
+!
+! Revision 1.2  1999/09/12 05:07:29  root
+! *** empty log message ***
+!
+!
+
+! Offsets into the PCI config space
+#define PCI_VENDOR_ID                  0x00
+#define PCI_DEVICE_ID                  0x02
+#define PCI_HEADER_TYPE                0x0e
+#define PCI_BASE_ADDRESS_0             0x10
+
+!PCI constants
+#define PCI_BASE_ADDRESS_IO_MASK       0xfffc
+#define PCI_VENDOR_ID_DAVICOM          0x1282
+#define PCI_DEVICE_ID_DAVICOM_9102     0x9102
+
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+entry start
+start:
+       mov ax,cs
+       mov es,ax
+       mov ds,ax
+       mov ss,ax
+
+! Put the stack at us+2k
+       mov di,#0x800-12
+       mov sp,di
+
+! Say hello
+       lea si,hello
+       call prtstr
+       call print_nl
+
+       lea si,top
+       call prtstr
+       call print_nl
+
+! Scan the pci bus
+       mov byte (devfn),#0
+
+dev_loop:
+               mov bh, byte (devfn)            !Device number
+               mov bl,#PCI_VENDOR_ID           !Offset into config space
+               mov cl, byte (bus)              !Bus number
+               call pci_read_config_word
+
+               cmp ax,#0xffff
+               beq dull
+               cmp ax,#0x0000
+               beq dull
+
+                       mov (vid),ax
+
+                       xor dh,dh       
+                       mov dl,byte (bus)
+       
+                       call print_2hex
+                       call print_sp   
+       
+                       mov dl, byte (devfn)
+                       sar dl,#3
+                       and dx,#0x1f
+       
+                       call print_2hex
+                       call print_sp
+       
+                       mov dl, byte (devfn)
+                       and dl,#7
+       
+                       call print_2hex
+                       call print_sp
+               
+                       mov dx,(vid)
+                       call print_hex
+                       call print_sp
+       
+                       mov bh, byte (devfn)    !Device number
+                       mov bl,#PCI_DEVICE_ID   !Offset into config space
+                       mov cl,byte (bus)       !Bus number
+                       call pci_read_config_word
+       
+                       mov (did),ax
+               
+                       mov dx,ax
+                       call print_hex
+                       call print_sp
+       
+                       mov bh, byte (devfn)  !Device number
+                       mov bl,#PCI_BASE_ADDRESS_0 !Offset into config space
+                       mov cl, byte (bus)      !Bus number
+                       call pci_read_config_word
+       
+                       and ax,#PCI_BASE_ADDRESS_IO_MASK
+                       mov (dad),ax
+       
+                       mov dx,ax
+                       call print_hex
+                       call print_sp
+       
+       
+                       cmp (vid),#PCI_VENDOR_ID_DAVICOM
+                       bne skipfix
+                       cmp (did),#PCI_DEVICE_ID_DAVICOM_9102
+                       bne skipfix
+       
+                               mov dx,(dad) !Hit the Reset bit
+                               in eax,dx
+                               or eax,#1
+                               out dx,eax
+               
+                               lea si,fixed
+                               call prtstr
+       
+skipfix:
+       
+       
+                       mov bh, byte (devfn)    !Device number
+                       mov bl,#PCI_HEADER_TYPE !Offset into config space
+                       mov cl,byte (bus)       !Bus number
+                       call pci_read_config_byte
+       
+                       and al,#0x80
+                       cmp al,#0x80
+                       beq multi
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+multi:
+
+                       call print_nl
+
+dull:
+
+
+               inc byte (devfn)
+               mov dl, byte (devfn)
+               cmp dl,#0
+               beq dev_loop_skip
+                       br dev_loop
+dev_loop_skip:
+
+       lea si,done
+       call prtstr
+       call print_nl
+
+! Hand over control to the linux 2ndary boot loader
+       jmp 0x9020:0x0
+
+
+! bh contains device_fn
+! bl conatins offset
+! cl contains the bus number
+
+
+pci_read_config_word: 
+       push bx
+       and bl,#0xfc
+       mov ch,#0x80
+
+       mov (controldword),bx
+       mov (controldword+2),cx
+
+       mov eax,(controldword)
+       mov dx,#0xcf8
+       out dx,eax
+
+       pop dx
+       and dx,#0x2
+       add dx,#0xcfc
+
+       in ax,dx
+       ret
+
+pci_read_config_byte: 
+       push bx
+       and bl,#0xfc
+       mov ch,#0x80
+
+       mov (controldword),bx
+       mov (controldword+2),cx
+
+       mov eax,(controldword)
+       mov dx,#0xcf8
+       out dx,eax
+
+       pop dx
+       and dx,#0x3
+       add dx,#0xcfc
+
+       in al,dx
+       ret
+
+
+prtstr: 
+               lodsb
+               and     al,al
+               jz      fin
+               call    prtchr
+        jmp     prtstr
+fin:    ret
+
+prtchr: push    ax
+        push    cx
+        xor     bh,bh
+        mov     cx,#0x01
+        mov     ah,#0x0e
+        int     0x10
+        pop     cx
+        pop     ax
+        ret
+
+print_hex:
+        mov     cx, #4          ! 4 hex digits
+print_digit:
+        rol     dx, #4          ! rotate so that lowest 4 bits are used
+        mov     ax, #0xe0f      ! ah = request, al = mask for nybble
+        and     al, dl
+        add     al, #0x90       ! convert al to ascii hex (four instructions)
+        daa
+        adc     al, #0x40
+        daa
+        int     0x10
+        loop    print_digit
+        ret
+
+print_2hex:
+        mov     cx, #2          ! 2 hex digits
+print_2digit:
+        rol     dx, #4          ! rotate so that lowest 4 bits are used
+        mov     ax, #0xe0f      ! ah = request, al = mask for nybble
+        and     al, dl
+        add     al, #0x90       ! convert al to ascii hex (four instructions)
+        daa
+        adc     al, #0x40
+        daa
+        int     0x10
+        loop    print_2digit
+        ret
+
+print_sp:
+        mov     ax, #0xe20      ! SP
+        int     0x10
+        ret
+
+print_nl:
+        mov     ax, #0xe0d      ! CR
+        int     0x10
+        mov     al, #0xa        ! LF
+        int     0x10
+        ret
+
+davicom_base:
+       .word   0x0
+bus:
+       .byte   0x0
+devfn:
+       .byte   0x0
+
+controldword:
+       .word 0
+       .word 0
+vid:
+       .word 0
+did:
+       .word 0
+dad:   
+       .word 0
+
+hello:    .ascii  "DAVICOM killer (c) 1999 James McKenzie <james@fishsoup.dhs.org>"
+                db      0x00
+
+top:   .ascii "Bs Sl Fn VID  DID  Window 0 base"
+       db 0x00
+fixed:         .ascii "- FIXED"
+       db 0x00
+
+done:   .ascii "Transfering control to linux secondary boot loader"
+       db 0x00
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
+
diff --git a/nics/dm9102/dmfix.S,v b/nics/dm9102/dmfix.S,v
new file mode 100644 (file)
index 0000000..5a92ffe
--- /dev/null
@@ -0,0 +1,354 @@
+head   1.1;
+access;
+symbols;
+locks
+       root:1.1; strict;
+comment        @# @;
+
+
+1.1
+date   2000.07.16.13.16.40;    author root;    state Exp;
+branches;
+next   ;
+
+
+desc
+@@
+
+
+1.1
+log
+@#
+@
+text
+@! Davicom Bootloader fixup, switches off the DAVICOM fast ethernet chip
+! before transfering control to the RPL'd image, so that the chip
+! doesn't scribble all over it while it relocates
+!
+! This image needs 2k of memory, and can be loaded anywhere, after
+! it does its stuff it does jmp 0x9020:0x0
+!
+! 
+!
+! $Id: dmfix.S,v 1.4 1999/09/14 17:18:27 root Exp $ll rights reserved
+!
+!  Copyright (c) 1999, James McKenzie.
+!                       All rights reserved
+!  Copyright (c) 1999, Christopher Lightfoot.
+!                       All rights reserved
+! 
+!  By using this file, you agree to the terms and conditions set
+!  forth in the LICENCE file which can be found at the top level of
+!  the rpld distribution.
+! 
+!  DAVICOM is a trademark of DAVICOM semiconductor inc.
+! 
+!
+!
+! $Log: dmfix.S,v $
+! Revision 1.4  1999/09/14 17:18:27  root
+! #
+!
+! Revision 1.3  1999/09/13 12:32:26  root
+! #
+!
+! Revision 1.2  1999/09/12 05:07:29  root
+! *** empty log message ***
+!
+!
+
+! Offsets into the PCI config space
+#define PCI_VENDOR_ID                  0x00
+#define PCI_DEVICE_ID                  0x02
+#define PCI_HEADER_TYPE                0x0e
+#define PCI_BASE_ADDRESS_0             0x10
+
+!PCI constants
+#define PCI_BASE_ADDRESS_IO_MASK       0xfffc
+#define PCI_VENDOR_ID_DAVICOM          0x1282
+#define PCI_DEVICE_ID_DAVICOM_9102     0x9102
+
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+entry start
+start:
+       mov ax,cs
+       mov es,ax
+       mov ds,ax
+       mov ss,ax
+
+! Put the stack at us+2k
+       mov di,#0x800-12
+       mov sp,di
+
+! Say hello
+       lea si,hello
+       call prtstr
+       call print_nl
+
+       lea si,top
+       call prtstr
+       call print_nl
+
+! Scan the pci bus
+       mov byte (devfn),#0
+
+dev_loop:
+               mov bh, byte (devfn)            !Device number
+               mov bl,#PCI_VENDOR_ID           !Offset into config space
+               mov cl, byte (bus)              !Bus number
+               call pci_read_config_word
+
+               cmp ax,#0xffff
+               beq dull
+               cmp ax,#0x0000
+               beq dull
+
+                       mov (vid),ax
+
+                       xor dh,dh       
+                       mov dl,byte (bus)
+       
+                       call print_2hex
+                       call print_sp   
+       
+                       mov dl, byte (devfn)
+                       sar dl,#3
+                       and dx,#0x1f
+       
+                       call print_2hex
+                       call print_sp
+       
+                       mov dl, byte (devfn)
+                       and dl,#7
+       
+                       call print_2hex
+                       call print_sp
+               
+                       mov dx,(vid)
+                       call print_hex
+                       call print_sp
+       
+                       mov bh, byte (devfn)    !Device number
+                       mov bl,#PCI_DEVICE_ID   !Offset into config space
+                       mov cl,byte (bus)       !Bus number
+                       call pci_read_config_word
+       
+                       mov (did),ax
+               
+                       mov dx,ax
+                       call print_hex
+                       call print_sp
+       
+                       mov bh, byte (devfn)  !Device number
+                       mov bl,#PCI_BASE_ADDRESS_0 !Offset into config space
+                       mov cl, byte (bus)      !Bus number
+                       call pci_read_config_word
+       
+                       and ax,#PCI_BASE_ADDRESS_IO_MASK
+                       mov (dad),ax
+       
+                       mov dx,ax
+                       call print_hex
+                       call print_sp
+       
+       
+                       cmp (vid),#PCI_VENDOR_ID_DAVICOM
+                       bne skipfix
+                       cmp (did),#PCI_DEVICE_ID_DAVICOM_9102
+                       bne skipfix
+       
+                               mov dx,(dad) !Hit the Reset bit
+                               in eax,dx
+                               or eax,#1
+                               out dx,eax
+               
+                               lea si,fixed
+                               call prtstr
+       
+skipfix:
+       
+       
+                       mov bh, byte (devfn)    !Device number
+                       mov bl,#PCI_HEADER_TYPE !Offset into config space
+                       mov cl,byte (bus)       !Bus number
+                       call pci_read_config_byte
+       
+                       and al,#0x80
+                       cmp al,#0x80
+                       beq multi
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+multi:
+
+                       call print_nl
+
+dull:
+
+
+               inc byte (devfn)
+               mov dl, byte (devfn)
+               cmp dl,#0
+               beq dev_loop_skip
+                       br dev_loop
+dev_loop_skip:
+
+       lea si,done
+       call prtstr
+       call print_nl
+
+! Hand over control to the linux 2ndary boot loader
+       jmp 0x9020:0x0
+
+
+! bh contains device_fn
+! bl conatins offset
+! cl contains the bus number
+
+
+pci_read_config_word: 
+       push bx
+       and bl,#0xfc
+       mov ch,#0x80
+
+       mov (controldword),bx
+       mov (controldword+2),cx
+
+       mov eax,(controldword)
+       mov dx,#0xcf8
+       out dx,eax
+
+       pop dx
+       and dx,#0x2
+       add dx,#0xcfc
+
+       in ax,dx
+       ret
+
+pci_read_config_byte: 
+       push bx
+       and bl,#0xfc
+       mov ch,#0x80
+
+       mov (controldword),bx
+       mov (controldword+2),cx
+
+       mov eax,(controldword)
+       mov dx,#0xcf8
+       out dx,eax
+
+       pop dx
+       and dx,#0x3
+       add dx,#0xcfc
+
+       in al,dx
+       ret
+
+
+prtstr: 
+               lodsb
+               and     al,al
+               jz      fin
+               call    prtchr
+        jmp     prtstr
+fin:    ret
+
+prtchr: push    ax
+        push    cx
+        xor     bh,bh
+        mov     cx,#0x01
+        mov     ah,#0x0e
+        int     0x10
+        pop     cx
+        pop     ax
+        ret
+
+print_hex:
+        mov     cx, #4          ! 4 hex digits
+print_digit:
+        rol     dx, #4          ! rotate so that lowest 4 bits are used
+        mov     ax, #0xe0f      ! ah = request, al = mask for nybble
+        and     al, dl
+        add     al, #0x90       ! convert al to ascii hex (four instructions)
+        daa
+        adc     al, #0x40
+        daa
+        int     0x10
+        loop    print_digit
+        ret
+
+print_2hex:
+        mov     cx, #2          ! 2 hex digits
+print_2digit:
+        rol     dx, #4          ! rotate so that lowest 4 bits are used
+        mov     ax, #0xe0f      ! ah = request, al = mask for nybble
+        and     al, dl
+        add     al, #0x90       ! convert al to ascii hex (four instructions)
+        daa
+        adc     al, #0x40
+        daa
+        int     0x10
+        loop    print_2digit
+        ret
+
+print_sp:
+        mov     ax, #0xe20      ! SP
+        int     0x10
+        ret
+
+print_nl:
+        mov     ax, #0xe0d      ! CR
+        int     0x10
+        mov     al, #0xa        ! LF
+        int     0x10
+        ret
+
+davicom_base:
+       .word   0x0
+bus:
+       .byte   0x0
+devfn:
+       .byte   0x0
+
+controldword:
+       .word 0
+       .word 0
+vid:
+       .word 0
+did:
+       .word 0
+dad:   
+       .word 0
+
+hello:    .ascii  "DAVICOM killer (c) 1999 James McKenzie <james@@fishsoup.dhs.org>"
+                db      0x00
+
+top:   .ascii "Bs Sl Fn VID  DID  Window 0 base"
+       db 0x00
+fixed:         .ascii "- FIXED"
+       db 0x00
+
+done:   .ascii "Transfering control to linux secondary boot loader"
+       db 0x00
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
+
+@
diff --git a/nics/dm9102/dmfix.o b/nics/dm9102/dmfix.o
new file mode 100644 (file)
index 0000000..5829ff4
Binary files /dev/null and b/nics/dm9102/dmfix.o differ
diff --git a/nics/dm9102/dmfix.s b/nics/dm9102/dmfix.s
new file mode 100644 (file)
index 0000000..7b2847e
--- /dev/null
@@ -0,0 +1,334 @@
+# 1 "dmfix.S"
+! Davicom Bootloader fixup, switches off the DAVICOM fast ethernet chip
+! before transfering control to the RPL'd image, so that the chip
+! doesn't scribble all over it while it relocates
+!
+! This image needs 2k of memory, and can be loaded anywhere, after
+! it does its stuff it does jmp 0x9020:0x0
+!
+! 
+!
+! $Id: dmfix.S,v 1.1 2000/07/16 13:16:40 root Exp $ll rights reserved
+!
+!  Copyright (c) 1999, James McKenzie.
+!                       All rights reserved
+!  Copyright (c) 1999, Christopher Lightfoot.
+!                       All rights reserved
+! 
+!  By using this file, you agree to the terms and conditions set
+!  forth in the LICENCE file which can be found at the top level of
+!  the rpld distribution.
+! 
+!  DAVICOM is a trademark of DAVICOM semiconductor inc.
+! 
+!
+!
+! $Log: dmfix.S,v $
+! Revision 1.1  2000/07/16 13:16:40  root
+! #
+!
+! Revision 1.4  1999/09/14 17:18:27  root
+! #
+!
+! Revision 1.3  1999/09/13 12:32:26  root
+! #
+!
+! Revision 1.2  1999/09/12 05:07:29  root
+! *** empty log message ***
+!
+!
+
+! Offsets into the PCI config space
+
+
+
+
+
+!PCI constants
+
+
+
+
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+entry start
+start:
+       mov ax,cs
+       mov es,ax
+       mov ds,ax
+       mov ss,ax
+
+! Put the stack at us+2k
+       mov di,#0x800-12
+       mov sp,di
+
+! Say hello
+       lea si,hello
+       call prtstr
+       call print_nl
+
+       lea si,top
+       call prtstr
+       call print_nl
+
+! Scan the pci bus
+       mov byte (devfn),#0
+
+dev_loop:
+               mov bh, byte (devfn)            !Device number
+               mov bl,#0x00            !Offset into config space
+               mov cl, byte (bus)              !Bus number
+               call pci_read_config_word
+
+               cmp ax,#0xffff
+               beq dull
+               cmp ax,#0x0000
+               beq dull
+
+                       mov (vid),ax
+
+                       xor dh,dh       
+                       mov dl,byte (bus)
+       
+                       call print_2hex
+                       call print_sp   
+       
+                       mov dl, byte (devfn)
+                       sar dl,#3
+                       and dx,#0x1f
+       
+                       call print_2hex
+                       call print_sp
+       
+                       mov dl, byte (devfn)
+                       and dl,#7
+       
+                       call print_2hex
+                       call print_sp
+               
+                       mov dx,(vid)
+                       call print_hex
+                       call print_sp
+       
+                       mov bh, byte (devfn)    !Device number
+                       mov bl,#0x02    !Offset into config space
+                       mov cl,byte (bus)       !Bus number
+                       call pci_read_config_word
+       
+                       mov (did),ax
+               
+                       mov dx,ax
+                       call print_hex
+                       call print_sp
+       
+                       mov bh, byte (devfn)  !Device number
+                       mov bl,#0x10 !Offset into config space
+                       mov cl, byte (bus)      !Bus number
+                       call pci_read_config_word
+       
+                       and ax,#0xfffc
+                       mov (dad),ax
+       
+                       mov dx,ax
+                       call print_hex
+                       call print_sp
+       
+       
+                       cmp (vid),#0x1282
+                       bne skipfix
+                       cmp (did),#0x9102
+                       bne skipfix
+       
+                               mov dx,(dad) !Hit the Reset bit
+                               in eax,dx
+                               or eax,#1
+                               out dx,eax
+               
+                               lea si,fixed
+                               call prtstr
+       
+skipfix:
+       
+       
+                       mov bh, byte (devfn)    !Device number
+                       mov bl,#0x0e !Offset into config space
+                       mov cl,byte (bus)       !Bus number
+                       call pci_read_config_byte
+       
+                       and al,#0x80
+                       cmp al,#0x80
+                       beq multi
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+                               inc byte (devfn)
+multi:
+
+                       call print_nl
+
+dull:
+
+
+               inc byte (devfn)
+               mov dl, byte (devfn)
+               cmp dl,#0
+               beq dev_loop_skip
+                       br dev_loop
+dev_loop_skip:
+
+       lea si,done
+       call prtstr
+       call print_nl
+
+! Hand over control to the 1 2ndary boot loader
+       jmp 0x9020:0x0
+
+
+! bh contains device_fn
+! bl conatins offset
+! cl contains the bus number
+
+
+pci_read_config_word: 
+       push bx
+       and bl,#0xfc
+       mov ch,#0x80
+
+       mov (controldword),bx
+       mov (controldword+2),cx
+
+       mov eax,(controldword)
+       mov dx,#0xcf8
+       out dx,eax
+
+       pop dx
+       and dx,#0x2
+       add dx,#0xcfc
+
+       in ax,dx
+       ret
+
+pci_read_config_byte: 
+       push bx
+       and bl,#0xfc
+       mov ch,#0x80
+
+       mov (controldword),bx
+       mov (controldword+2),cx
+
+       mov eax,(controldword)
+       mov dx,#0xcf8
+       out dx,eax
+
+       pop dx
+       and dx,#0x3
+       add dx,#0xcfc
+
+       in al,dx
+       ret
+
+
+prtstr: 
+               lodsb
+               and     al,al
+               jz      fin
+               call    prtchr
+        jmp     prtstr
+fin:    ret
+
+prtchr: push    ax
+        push    cx
+        xor     bh,bh
+        mov     cx,#0x01
+        mov     ah,#0x0e
+        int     0x10
+        pop     cx
+        pop     ax
+        ret
+
+print_hex:
+        mov     cx, #4          ! 4 hex digits
+print_digit:
+        rol     dx, #4          ! rotate so that lowest 4 bits are used
+        mov     ax, #0xe0f      ! ah = request, al = mask for nybble
+        and     al, dl
+        add     al, #0x90       ! convert al to ascii hex (four instructions)
+        daa
+        adc     al, #0x40
+        daa
+        int     0x10
+        loop    print_digit
+        ret
+
+print_2hex:
+        mov     cx, #2          ! 2 hex digits
+print_2digit:
+        rol     dx, #4          ! rotate so that lowest 4 bits are used
+        mov     ax, #0xe0f      ! ah = request, al = mask for nybble
+        and     al, dl
+        add     al, #0x90       ! convert al to ascii hex (four instructions)
+        daa
+        adc     al, #0x40
+        daa
+        int     0x10
+        loop    print_2digit
+        ret
+
+print_sp:
+        mov     ax, #0xe20      ! SP
+        int     0x10
+        ret
+
+print_nl:
+        mov     ax, #0xe0d      ! CR
+        int     0x10
+        mov     al, #0xa        ! LF
+        int     0x10
+        ret
+
+davicom_base:
+       .word   0x0
+bus:
+       .byte   0x0
+devfn:
+       .byte   0x0
+
+controldword:
+       .word 0
+       .word 0
+vid:
+       .word 0
+did:
+       .word 0
+dad:   
+       .word 0
+
+hello:    .ascii  "DAVICOM killer (c) 1999 James McKenzie <james@fishsoup.dhs.org>"
+                db      0x00
+
+top:   .ascii "Bs Sl Fn VID  DID  Window 0 base"
+       db 0x00
+fixed:         .ascii "- FIXED"
+       db 0x00
+
+done:   .ascii "Transfering control to linux secondary boot loader"
+       db 0x00
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
+
diff --git a/project.h b/project.h
new file mode 100644 (file)
index 0000000..3e213ef
--- /dev/null
+++ b/project.h
@@ -0,0 +1,86 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+/*
+ * $Id: project.h,v 1.11 2000/07/16 13:18:10 root Exp root $
+ *
+ * $Log: project.h,v $
+ * Revision 1.11  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.10  1999/09/14 21:36:02  root
+ * #
+ *
+ * Revision 1.9  1999/09/13 12:37:05  root
+ * #
+ *
+ * Revision 1.8  1999/09/13 12:36:18  root
+ * #
+ *
+ * Revision 1.7  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.6  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.5  1999/09/13 11:04:13  root
+ * \#
+ *  
+ */
+
+/* EDITME: this is the delay between transmitted packets in us */
+/* you may need to edit this if your clients are slow */
+/* if a client drops a packet it will typically wait 1s and then */
+/* issue a retransmit request */
+
+#include <stdio.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+
+
+extern int downloading;
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+#define MAX_FRAME_LEN 1514
+
+#define MY_FRAME_LEN 1500
+#define MY_BLOCK_LEN 1440       /*quad word aligned */
+
+
+#define CONFIG_FILE "/etc/rpld.conf"
+
+#define NOTINRANGE(l,v,h) (((v)<(l)) || ((v)>(h)))
+
+#include "linux-ps.h"
+
+#include "llc.h"
+#include "rpl.h"
+#include "client.h"
+
+
+#include "prototypes.h"
diff --git a/protocol.c b/protocol.c
new file mode 100644 (file)
index 0000000..4b3b37e
--- /dev/null
@@ -0,0 +1,217 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: protocol.c,v 1.10 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: protocol.c,v $
+ * Revision 1.10  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.9  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.8  1999/09/13 11:08:34  root
+ * \#
+ *
+ * Revision 1.7  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.6  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+#include "project.h"
+
+/* Process the find frame and xmit a found frame */
+void
+find_frame (struct nit *n, struct rpl_packet *in)
+{
+  struct client *c;
+  struct rpl_packet out;
+
+  c = find_client_by_mac (in->mymac);
+
+  if (!c)
+    {
+      syslog (LOG_ERR, "unknown client %s", ethtoa (in->mymac));
+      return;
+    }
+
+  c->blocknum = 0;
+
+  out.type = RPL_PK_FOUND;
+
+  out.flags = RPL_FL_TMZ | RPL_FL_TSZ | RPL_FL_YOUMAC | RPL_FL_MYMAC | RPL_FL_FRAMELEN | RPL_FL_WHOAMI | RPL_FL_SAP;
+
+  out.themightyzero = in->themightyzero;
+  out.thesmallzero = 0;
+  out.whoami = 0;
+
+  if (in->framelen < c->framelen)
+    {
+      c->framelen = in->framelen;
+    }
+
+  if ((c->blocklen + LLC_RPL_OVERHEAD) > c->framelen)
+    {
+      c->blocklen = c->framelen - LLC_RPL_OVERHEAD;
+      c->blocklen &= ~0x7;
+    }
+
+  c->framelen = out.framelen = (in->framelen > c->framelen) ? c->framelen : in->framelen;
+  out.sap = RPL_SAP;
+
+  bcopy (in->mymac, out.youmac, ETH_ALEN);
+  bcopy (nit_mac (n), out.mymac, ETH_ALEN);
+
+  c->state = ST_FIND;
+
+  rpl_send_packet (n, c->mac, &out);
+
+  c->state = ST_FOUND;
+
+}
+
+
+file_data_frame (struct nit *n, struct client *c)
+{
+  struct rpl_packet out;
+  int i;
+
+  u32 addr = 0x10000;
+
+  if (c->state != ST_FILEDATA)
+    return;
+
+  out.flags = RPL_FL_BLOCK | RPL_FL_ADDR | RPL_FL_DATA;
+  out.type = RPL_PK_FILEDATA;
+
+  out.block = c->blocknum;
+
+  client_get_block (c, &out);
+
+  out.addr.run = c->run_addr;
+
+#ifdef DEBUG
+  printf ("block %5d, %4d bytes to 0x%08x\n", c->blocknum,
+          out.datalen, out.addr.load);
+#endif
+
+  if (client_last_block (c))
+    {
+      out.addr.flags = RPL_AD_FLAGS_DONE;
+      c->state = ST_DONE;
+#ifdef DEBUG
+      printf ("Last block - transfering control to 0x%08x\n", c->run_addr);
+#endif
+      clients_check_status ();
+    }
+  else
+    {
+      out.addr.flags = RPL_AD_FLAGS_MORE;
+    }
+
+
+
+  rpl_send_packet (n, c->mac, &out);
+  c->blocknum++;
+
+  return (i);
+}
+
+void
+send_file_frame (struct nit *n, struct rpl_packet *in)
+{
+  struct client *c;
+  struct rpl_packet out;
+
+  c = find_client_by_mac (in->mymac);
+
+  if (!c)
+    {
+      printf ("Unknown client\n");
+      return;
+    }
+
+  c->state = ST_SENDFILE;
+
+  c->blocknum = in->block;
+  c->framelen = in->framelen;
+
+  syslog (LOG_ERR, "client %s requested block %d", ethtoa (c->mac), c->blocknum);
+
+  client_calc_offsets (c);
+
+  c->state = ST_FILEDATA;
+
+  clients_check_status ();      /* This will upgrade our condition to downloading */
+
+/*
+   while (c->state == ST_FILEDATA)
+   {
+   file_data_frame (n, c);
+   usleep (1000);
+   }
+ */
+
+
+}
+
+/* rpl.c call this after it's interpreted a packet from the nic */
+void
+rpl_packet_recvd_callback (struct nit *n, struct rpl_packet *p)
+{
+  switch (p->type)
+    {
+    case RPL_PK_FIND:
+
+      if ((p->flags & RPL_FIND_FLAGS) == RPL_FIND_FLAGS)
+        {
+          find_frame (n, p);
+        }
+      else
+        {
+          syslog (LOG_ERR, "Incomplete FIND frame 0x%x vs 0x%x\n",
+                  p->flags, RPL_FIND_FLAGS);
+        }
+    case RPL_PK_FOUND:         /*We're not a client */
+      break;
+    case RPL_PK_SENDFILE:
+      if ((p->flags & RPL_SEND_FILE_FLAGS) == RPL_SEND_FILE_FLAGS)
+        {
+          send_file_frame (n, p);
+        }
+      else
+        {
+          syslog (LOG_ERR, "Incomplete SEND.FILE.REQUEST frame 0x%x vs 0x%x\n",
+                  p->flags, RPL_SEND_FILE_FLAGS);
+        }
+      break;
+    case RPL_PK_FILEDATA:      /*We're not a client */
+      break;
+    default:
+      syslog (LOG_ERR, "Unknown RPL packet type 0x%04x\n", p->type);
+
+    }
+
+}
diff --git a/prototypes.h b/prototypes.h
new file mode 100644 (file)
index 0000000..1fb02ce
--- /dev/null
@@ -0,0 +1,41 @@
+/* protocol.c */
+void find_frame(struct nit *n, struct rpl_packet *in);
+int file_data_frame(struct nit *n, struct client *c);
+void send_file_frame(struct nit *n, struct rpl_packet *in);
+void rpl_packet_recvd_callback(struct nit *n, struct rpl_packet *p);
+/* linux-ps.c */
+void nit_close(struct nit *n);
+struct nit *nit_open(char *name);
+void nit_send_frame(struct nit *n, unsigned char *frame, int len);
+void nit_multicast(struct nit *n, unsigned char *mcaddr);
+int nit_read_packet(struct nit *n, char *buf, int len, struct timeval *tv);
+/* rpld.c */
+int main(int argc, char **argv);
+/* util.c */
+unsigned char *ethtoa(void *in);
+void daemonize(void);
+/* rpl.c */
+int write_char(unsigned char *ptr, u8 v);
+int write_short(unsigned char *ptr, u16 v);
+int write_long(unsigned char *ptr, u32 v);
+int put_char(unsigned char *ptr, u16 token, u8 value);
+int put_short(unsigned char *ptr, u16 token, u16 value);
+int put_long(unsigned char *ptr, u16 token, u32 value);
+int put_mac(unsigned char *ptr, u16 token, unsigned char *mac);
+void rpl_send_packet(struct nit *n, unsigned char *d, struct rpl_packet *p);
+void rpl_packet_recvd(struct nit *n, unsigned char *pptr, int plen);
+/* llc.c */
+void send_llc_frame(struct nit *n, unsigned char dsap, unsigned char ssap, unsigned char *dmac, unsigned char *ibuf, int len);
+void llc_recv_packet(struct nit *n, unsigned char *buf, int len);
+/* client.c */
+void cache_locally(struct clfile *f);
+struct client *find_client_by_mac(unsigned char *mac);
+void client_calc_offsets(struct client *c);
+void client_get_block(struct client *c, struct rpl_packet *p);
+int client_last_block(struct client *c);
+void client_flush_cache(struct client *c);
+int clients_check_status(void);
+int client_dispatch(struct nit *n);
+/* config.c */
+void do_linux_kernel(struct client *c, struct clfile *f);
+void parse_config(void);
diff --git a/rpl.c b/rpl.c
new file mode 100644 (file)
index 0000000..ef37bc8
--- /dev/null
+++ b/rpl.c
@@ -0,0 +1,419 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+
+static char rcsid[] = "$Id: rpl.c,v 1.8 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: rpl.c,v $
+ * Revision 1.8  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.7  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.6  1999/09/13 11:08:34  root
+ * \#
+ *
+ * Revision 1.5  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.4  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+#include "project.h"
+
+/* Code for recursively disembling packets */
+
+static void
+rpl_token (struct rpl_packet *p, int s, unsigned char *pp, int pl)
+{
+  int i;
+  switch (s)
+    {
+    case RPL_TK_TMZ:
+      if (pl < 4)
+        return;
+      p->flags |= RPL_FL_TMZ;
+      p->themightyzero = ntohl (*(u32 *) pp);
+      return;
+    case RPL_TK_MYMAC:
+      if (pl < ETH_ALEN)
+        return;
+      p->flags |= RPL_FL_MYMAC;
+      bcopy (pp, p->mymac, ETH_ALEN);
+      return;
+    case RPL_TK_SAP:
+      /*FIXME: */
+      p->flags |= RPL_FL_SAP;
+      return;
+    case RPL_TK_FRAMELEN:
+      if (pl < 2)
+        return;
+      p->flags |= RPL_FL_FRAMELEN;
+      p->framelen = ntohs (*(u16 *) pp);
+      return;
+    case RPL_TK_WHOAMI:
+      if (pl < 2)
+        return;
+      p->flags |= RPL_FL_WHOAMI;
+      p->whoami = ntohs (*(u16 *) pp);
+      return;
+    case RPL_TK_TSZ:
+      if (pl < 1)
+        return;
+      p->flags |= RPL_FL_TSZ;
+      p->thesmallzero = *pp;
+      return;
+    case RPL_TK_YOUMAC:
+      if (pl < ETH_ALEN)
+        return;
+      p->flags |= RPL_FL_YOUMAC;
+      bcopy (pp, p->youmac, ETH_ALEN);
+      return;
+    case RPL_TK_BLOCK:
+      if (pl < 4)
+        return;
+      p->flags |= RPL_FL_BLOCK;
+      p->block = ntohl (*(u32 *) pp);
+      return;
+    case RPL_TK_DATA:
+      if (NOTINRANGE (1, pl, MAX_DATA_LEN))
+        return;
+      p->flags |= RPL_FL_DATA;
+      bcopy (pp, p->data, pl);
+      p->datalen = pl;
+      return;
+    case RPL_TK_IDENT:
+      if (NOTINRANGE (1, pl, MAX_IDENT_LEN))
+        return;
+      p->flags |= RPL_FL_IDENT;
+      bcopy (pp, p->ident, pl);
+      p->identlen = pl;
+      return;
+    case RPL_FL_ADDR:
+      if (pl < 9)
+        return;
+      p->flags |= RPL_FL_ADDR;
+      p->addr.load = ntohl (*(u32 *) pp);
+      p->addr.run = ntohl (*(u32 *) (pp + 4));
+      p->addr.flags = pp[8];
+      return;
+    default:
+      syslog (LOG_ERR, "Unknown token: 0x%04x", s);
+    }
+
+}
+
+static void
+rpl_frag (struct rpl_packet *p, unsigned char *pp, int pl)
+{
+  int s;
+
+  while (pl > 0)
+    {
+
+      if (pl < 2)
+        return;
+      s = ntohs (*(u16 *) pp);
+
+      if (!s)
+        {
+          syslog (LOG_ERR, "Unexpected end of packet", s);
+          return;
+
+        }
+      if (RPL_IS_TOKEN (s))
+        {
+          rpl_token (p, s, pp + 2, pl - 2);
+          return;
+        }
+      else
+        {
+          rpl_frag (p, pp + 2, s - 2);
+          pp += s;
+          pl -= s;
+        }
+
+    }
+
+}
+
+/* Code for assembling packets */
+int
+write_char (unsigned char *ptr, u8 v)
+{
+  *ptr = v;
+  return (1);
+}
+int
+write_short (unsigned char *ptr, u16 v)
+{
+  *((u16 *) ptr) = htons (v);
+  return (2);
+}
+int
+write_long (unsigned char *ptr, u32 v)
+{
+  *((u32 *) ptr) = htonl (v);
+  return (4);
+}
+
+int
+put_char (unsigned char *ptr, u16 token, u8 value)
+{
+  int len = 0, i;
+  i = write_short (ptr, 0x2 + 0x2 + 0x1);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, token);
+  ptr += i;
+  len += i;
+  i = write_char (ptr, value);
+  ptr += i;
+  len += i;
+  return (len);
+}
+int
+put_short (unsigned char *ptr, u16 token, u16 value)
+{
+  int len = 0, i;
+  i = write_short (ptr, 0x2 + 0x2 + 0x2);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, token);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, value);
+  ptr += i;
+  len += i;
+  return (len);
+}
+int
+put_long (unsigned char *ptr, u16 token, u32 value)
+{
+  int len = 0, i;
+  i = write_short (ptr, 0x2 + 0x2 + 0x4);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, token);
+  ptr += i;
+  len += i;
+  i = write_long (ptr, value);
+  ptr += i;
+  len += i;
+  return (len);
+}
+int
+put_mac (unsigned char *ptr, u16 token, unsigned char *mac)
+{
+  int len = 0, i;
+  i = write_short (ptr, 0x2 + 0x2 + 0x6);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, token);
+  ptr += i;
+  len += i;
+  bcopy (mac, ptr, ETH_ALEN);
+  ptr += ETH_ALEN;
+  len += ETH_ALEN;
+  return (len);
+}
+
+static void
+send_found_frame (struct nit *n, unsigned char *dmac, struct rpl_packet *out)
+{
+  unsigned char buf[MAX_FRAME_LEN], *ptr;
+  int len, i;
+
+  if (out->flags != RPL_FOUND_FLAGS)
+    {
+
+      syslog (LOG_ERR, "FOUND packet: doesn't match RE case %x!=%x",
+              out->flags, RPL_FOUND_FLAGS);
+      return;
+    }
+
+  ptr = buf;
+  len = 0;
+
+  i = write_short (ptr, 0x0);
+  ptr += i;
+  len += i;                     /*length */
+  i = write_short (ptr, out->type);
+  ptr += i;
+  len += i;                     /*type */
+
+  i = put_long (ptr, RPL_TK_TMZ, out->themightyzero);
+  ptr += i;
+  len += i;
+  i = put_char (ptr, RPL_TK_TSZ, out->thesmallzero);
+  ptr += i;
+  len += i;
+  i = put_mac (ptr, RPL_TK_YOUMAC, out->youmac);
+  ptr += i;
+  len += i;
+  i = put_mac (ptr, RPL_TK_MYMAC, out->mymac);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, 0x10);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, 0x08);
+  ptr += i;
+  len += i;
+  i = put_short (ptr, RPL_TK_FRAMELEN, out->framelen);
+  ptr += i;
+  len += i;
+  i = put_short (ptr, RPL_TK_WHOAMI, out->whoami);
+  ptr += i;
+  len += i;
+  i = put_char (ptr, RPL_TK_SAP, out->sap);
+  ptr += i;
+  len += i;
+
+  ptr = buf;
+  write_short (ptr, len);       /*length */
+
+  send_llc_frame (n, RPL_SAP, RPL_SAP, dmac, buf, len);
+
+}
+
+
+static void
+send_file_data_frame (struct nit *n, unsigned char *dmac, struct rpl_packet *out)
+{
+  unsigned char buf[MAX_FRAME_LEN], *ptr;
+  int len, i;
+
+  if (out->flags != RPL_FILE_DATA_FLAGS)
+    {
+      syslog (LOG_ERR, "FILE.DATA packet: doesn't match RE case %x!=%x",
+              out->flags, RPL_FILE_DATA_FLAGS);
+      return;
+    }
+
+  ptr = buf;
+  len = 0;
+
+  i = write_short (ptr, 0x0);
+  ptr += i;
+  len += i;                     /*length */
+  i = write_short (ptr, out->type);
+  ptr += i;
+  len += i;                     /*type */
+
+  i = put_long (ptr, RPL_TK_BLOCK, out->block);
+  ptr += i;
+  len += i;
+
+  i = write_short (ptr, 0x2 + 0x2 + 0x9);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, RPL_TK_ADDR);
+  ptr += i;
+  len += i;
+  i = write_long (ptr, out->addr.load);
+  ptr += i;
+  len += i;
+  i = write_long (ptr, out->addr.run);
+  ptr += i;
+  len += i;
+  i = write_char (ptr, out->addr.flags);
+  ptr += i;
+  len += i;
+
+  i = write_short (ptr, 0x2 + 0x2 + out->datalen);
+  ptr += i;
+  len += i;
+  i = write_short (ptr, RPL_TK_DATA);
+  ptr += i;
+  len += i;
+  bcopy (out->data, ptr, out->datalen);
+  ptr += out->datalen;
+  len += out->datalen;
+
+
+  ptr = buf;
+  write_short (ptr, len);       /*length */
+
+  send_llc_frame (n, RPL_SAP, RPL_SAP, dmac, buf, len);
+
+
+}
+
+void
+rpl_send_packet (struct nit *n, unsigned char *d, struct rpl_packet *p)
+{
+
+  switch (p->type)
+    {
+    case RPL_PK_FOUND:
+      send_found_frame (n, d, p);
+      break;
+    case RPL_PK_FILEDATA:
+      send_file_data_frame (n, d, p);
+      break;
+    default:
+      syslog (LOG_ERR, "rpl_send_packet: unknown packet type 0x%04x", p->type);
+    }
+}
+
+/* The llc code calls this whenever it gets a valid rpl packet */
+void
+rpl_packet_recvd (struct nit *n, unsigned char *pptr, int plen)
+{
+
+  struct rpl_packet p;
+  int elen;
+
+  if (plen < 6)
+    return;
+
+  elen = ntohs (*(u16 *) pptr);
+
+  if (elen != plen)
+    {
+      syslog (LOG_ERR, "received lengths disagree %d vs %d", elen, plen);
+    }
+
+  if (elen > plen)
+    elen = plen;
+
+  pptr += 2;                    /*Length */
+  elen -= 2;
+
+  if (elen < 2)
+    return;
+  p.type = ntohs (*(u16 *) pptr);
+
+  pptr += 2;
+  elen -= 2;
+
+  p.flags = 0;
+
+  rpl_frag (&p, pptr, elen);    /*Analyse the packet */
+
+  rpl_packet_recvd_callback (n, &p);  /*Pass it up to the protocol layer */
+
+}
diff --git a/rpl.h b/rpl.h
new file mode 100644 (file)
index 0000000..813639a
--- /dev/null
+++ b/rpl.h
@@ -0,0 +1,127 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+
+/*
+ * $Id: rpl.h,v 1.9 2000/07/16 13:18:10 root Exp $
+ *
+ * $Log: rpl.h,v $
+ * Revision 1.9  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.8  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.7  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.6  1999/09/13 11:04:13  root
+ * \#
+ *
+ * Revision 1.5  1999/09/13 11:04:13  root
+ * \#
+ *  
+ */
+
+
+typedef unsigned int u32;
+typedef unsigned short int u16;
+typedef unsigned char u8;
+
+
+#define LLC_RPL_OVERHEAD 0x30
+
+#define RPL_SAP                0xfc
+
+#define RPL_PK_FIND    0x0001
+#define RPL_PK_FOUND   0x0002
+#define RPL_PK_SENDFILE        0x0010
+#define RPL_PK_FILEDATA        0x0020
+
+#define RPL_IS_TOKEN(a) (a & 0xc000)
+
+#define RPL_TK_TMZ     0x4003
+#define RPL_TK_MYMAC   0x4006
+#define RPL_TK_SAP     0x4007
+#define RPL_TK_FRAMELEN 0x4009
+#define RPL_TK_WHOAMI  0x400a
+#define RPL_TK_TSZ     0x400b
+#define RPL_TK_YOUMAC  0x400c
+#define RPL_TK_BLOCK   0x4011
+#define RPL_TK_DATA    0x4018
+#define RPL_TK_IDENT           0xc005
+#define RPL_TK_ADDR    0xc014
+
+#define RPL_FL_TMZ     (1L << 0)
+#define RPL_FL_MYMAC   (1L << 1)
+#define RPL_FL_SAP     (1L << 2)
+#define RPL_FL_FRAMELEN (1L << 3)
+#define RPL_FL_WHOAMI  (1L << 4)
+#define RPL_FL_TSZ     (1L << 5)
+#define RPL_FL_YOUMAC  (1L << 6)
+#define RPL_FL_BLOCK   (1L << 7)
+#define RPL_FL_DATA    (1L << 8)
+#define RPL_FL_IDENT   (1L << 9)
+#define RPL_FL_ADDR    (1L << 10)
+
+#define RPL_AD_FLAGS_MORE      0x20
+#define RPL_AD_FLAGS_DONE      0xc0
+
+#define RPL_FIND_FLAGS (RPL_FL_FRAMELEN|RPL_FL_MYMAC|RPL_FL_IDENT|RPL_FL_TMZ)
+
+#define RPL_FOUND_FLAGS (RPL_FL_TMZ | RPL_FL_TSZ | RPL_FL_YOUMAC | RPL_FL_MYMAC | RPL_FL_FRAMELEN | RPL_FL_WHOAMI | RPL_FL_SAP)
+
+#define RPL_SEND_FILE_FLAGS (RPL_FL_BLOCK | RPL_FL_FRAMELEN | RPL_FL_MYMAC)
+
+#define RPL_FILE_DATA_FLAGS (RPL_FL_BLOCK | RPL_FL_ADDR | RPL_FL_DATA)
+
+struct addr_block
+  {
+    u32 load;
+    u32 run;
+    u32 flags;
+  };
+
+#define MAX_DATA_LEN MAX_FRAME_LEN
+#define MAX_IDENT_LEN MAX_FRAME_LEN
+
+struct rpl_packet
+  {
+    int flags;
+
+    int type;
+
+    u32 themightyzero;
+    u8 mymac[ETH_ALEN];
+    u8 sap;
+    u16 framelen;
+    u16 whoami;
+    u16 thesmallzero;
+    u8 youmac[ETH_ALEN];
+    u32 block;
+    u8 data[MAX_DATA_LEN];
+    int datalen;
+
+    u8 ident[MAX_IDENT_LEN];
+    int identlen;
+
+    struct addr_block addr;
+  };
diff --git a/rpld.1 b/rpld.1
new file mode 100644 (file)
index 0000000..b86c3a8
--- /dev/null
+++ b/rpld.1
@@ -0,0 +1,118 @@
+.\" 
+.\"/*************************************************
+.\"*     rpld - an IBM style RIPL server            *
+.\"*************************************************/
+.\"
+.\"Copyright (c) 1999, James McKenzie.
+.\"                     All rights reserved
+.\"Copyright (c) 1998, Christopher Lightfoot.
+.\"                     All rights reserved
+.\"
+.\"By using this file, you agree to the terms and conditions set
+.\"forth in the LICENSE file which can be found at the top level of
+.\"the rpld distribution.
+.\"
+.\"IBM is a trademark of IBM Corp.
+.\"
+.\"
+.\"
+.\" $Id: rpld.man,v 1.8 1999/09/15 00:25:57 root Exp root $;
+.\"
+.\" $Log: rpld.man,v $
+.\" Revision 1.8  1999/09/15 00:25:57  root
+.\" #
+.\"
+.\" Revision 1.7  1999/09/15 00:22:07  root
+.\" #
+.\"
+.\" Revision 1.6  1999/09/15 00:14:29  root
+.\" #
+.\"
+.\" Revision 1.5  1999/09/14 21:43:30  root
+.\" #
+.\"
+.\" Revision 1.4  1999/09/14 21:37:08  root
+.\" #
+.\"
+.\" Revision 1.3  1999/09/14 21:32:12  root
+.\" #
+.\"
+.\" Revision 1.2  1999/09/14 21:25:59  root
+.\" #
+.\"
+.\" Revision 1.1  1999/09/14 21:00:47  root
+.\" #
+.\"
+.\" Revision 1.1  1999/09/14 17:19:37  root
+.\" Initial revision
+.\"
+.\";
+.Dd Sep 14, 1999
+.Dt RPLD.CONF 5
+.Os Linux
+.Sh NAME
+.Nm rpld
+.Nd an RPL/RIPL remote boot server
+.Sh SYNOPSIS
+.Nm rpld
+.Sh WARRANTY
+.Nm rpld 
+DOES NOT come with ANY WARRANTY, NOT even an IMPLIED WARRANTY.
+.Sh DESCRIPTION
+.Nm rpld 
+will net-boot IBM style RPL boot ROMs. Communication between the client and the
+server is done in LLC-1 ui/C frames with the source and destination SAP both 
+being 0xfc. On booting the client transmits a FIND frame containing the client's
+MAC address, adapter type and frame length. The server replies with a FOUND frame
+containing the server's MAC address and a possibly smaller frame length. The
+client issues a SEND.FILE.REQUEST frame requesting the first block of the boot
+file. The server then issues a sequence of FILE.DATA.RESPONSE frames with 
+increasing block numbers. The FILE.DATA.RESPONSE frames contain a load address
+and an execute address and a flag. If the client fails to receive a  
+FILE.DATA.RESPONSE frame within a certain period it sends another 
+SEND.FILE.REQUEST frame requesting the block which follows the last block that
+was successfully received. On the last FILE.DATA.RESPONSE frame the server
+sets a special value of the flags which cause the client to transfer execution
+to the execute address specified in the frame.
+.Pp
+The server starts by reading the configuration file in /etc/rpld.conf,
+see 
+.Pa rpld.conf(5),
+After the configuration file has been read, it opens the system's
+default network interface and listens for RPL frames.
+The server recalculates the length of all the files to be downloaded every time
+it receives a SEND.FILE.REQUEST frame. 
+.Sh BUGS
+.Bl -tag -width 0 -compact
+.It
+Solenopsis invicta Buren 
+.It
+rpld (probably) doesn't support the new bzImage format correctly.
+.It
+rpld doesn't reload the first 512 octets of Linux kernels automatically.
+.It
+There is no way to make rpld re-read its configuration file.
+.It
+rpld 
+needs to meet more network cards.
+.Sh NOTES
+.Pp
+IBM is a trademark of IBM Corp.
+.Sh FILES
+.Bl -tag -width /etc/rpld.conf -compact
+.Pp
+.It Pa /usr/sbin/rpld
+.It Pa /etc/rpld.conf
+.It Pa /rplboot
+.El
+.Sh SEE ALSO
+.Pp
+.Bl -tag -width 0 -compact
+.It Pa rpld\.conf(5),
+.It Pa bootpd(1),
+.It Pa dhcpd(1),
+.It Pa http://bullard.esc.cam.ac.uk/~james/rpld;
+.El
+.Sh AUTHORS AND COPYRIGHT
+.Pp
+(c) 1999 James McKenzie, and Christopher Lightfoot. All rights reserved.
diff --git a/rpld.c b/rpld.c
new file mode 100644 (file)
index 0000000..c6a9ba4
--- /dev/null
+++ b/rpld.c
@@ -0,0 +1,125 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: rpld.c,v 1.10 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: rpld.c,v $
+ * Revision 1.10  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.9  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.8  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.7  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+#include "project.h"
+
+static unsigned char RPL_MC_ADDR[ETH_ALEN] =
+{0x3, 0x0, 0x2, 0x0, 0x0, 0x0};
+
+int downloading = 0;
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  unsigned char buf[MAX_FRAME_LEN];
+  struct llchdr *h = (struct llchdr *) buf;
+  struct timeval last;
+
+  struct nit *n;
+
+  openlog ("rpld", LOG_PID, LOG_DAEMON);
+
+  parse_config ();
+
+  daemonize ();
+
+  n = nit_open (NULL);
+
+  if (!n)
+    {
+      syslog (LOG_ERR, "failed to initalize nit");
+      return (-1);
+    }
+
+  nit_multicast (n, RPL_MC_ADDR);
+
+  syslog (LOG_ERR, "my hw addr = %s", ethtoa (nit_mac (n)));
+
+
+  gettimeofday (&last, NULL);
+
+
+  while (1)
+    {
+      int len;
+      struct timeval tv;
+
+      if (downloading)
+        {
+          tv.tv_sec = 0;
+          tv.tv_usec = PACKET_DELAY;
+        }
+      else
+        {
+          tv.tv_sec = 10;
+          tv.tv_usec = 0;
+        }
+
+      len = nit_read_packet (n, buf, sizeof (buf), &tv);
+
+
+      if ((len > LLC_HDR_LEN) && (ntohs (h->h_len) <= 1514))
+        {                       /*Short circuit most packets */
+          llc_recv_packet (n, buf, len);
+        }
+
+      if (downloading)
+        {
+          gettimeofday (&tv, NULL);
+
+          len = tv.tv_usec;
+          len += 1000000;
+          len -= last.tv_usec;
+          len %= 1000000;
+
+          if (len > 1000)
+            {
+              client_dispatch (n);
+              gettimeofday (&last, NULL);
+
+            }
+        }
+    }
+
+  nit_close (n);
+
+  return 0;
+}
diff --git a/rpld.conf.man b/rpld.conf.man
new file mode 100644 (file)
index 0000000..2c75344
--- /dev/null
@@ -0,0 +1,281 @@
+.\" 
+.\"/*************************************************
+.\"*     rpld - an IBM style RIPL server            *
+.\"*************************************************/
+.\"
+.\"Copyright (c) 1999, James McKenzie.
+.\"                     All rights reserved
+.\"Copyright (c) 1998, Christopher Lightfoot.
+.\"                     All rights reserved
+.\"
+.\"By using this file, you agree to the terms and conditions set
+.\"forth in the LICENSE file which can be found at the top level of
+.\"the rpld distribution.
+.\"
+.\"IBM is a trademark of IBM Corp.
+.\"
+.\"
+.\"
+.\" $Id: rpld.conf.man,v 1.3 2000/07/16 13:18:10 root Exp root $;
+.\"
+.\" $Log: rpld.conf.man,v $
+.\" Revision 1.3  2000/07/16 13:18:10  root
+.\" #
+.\"
+.\" Revision 1.1  2000/07/16 13:16:33  root
+.\" #
+.\"
+.\" Revision 1.7  1999/09/15 14:29:10  root
+.\" #
+.\"
+.\" Revision 1.6  1999/09/15 01:22:18  root
+.\" #
+.\"
+.\" Revision 1.5  1999/09/15 00:36:29  root
+.\" #
+.\"
+.\" Revision 1.4  1999/09/15 00:22:07  root
+.\" #
+.\"
+.\" Revision 1.3  1999/09/15 00:14:29  root
+.\" #
+.\"
+.\" Revision 1.2  1999/09/14 21:25:59  root
+.\" #
+.\"
+.\" Revision 1.1  1999/09/14 21:00:47  root
+.\" #
+.\"
+.\" Revision 1.1  1999/09/14 17:19:37  root
+.\" Initial revision
+.\"
+.\";
+.Dd Sep 14, 1999
+.Dt RPLD.CONF 5
+.Os Linux
+.Sh NAME
+.Nm rpld.conf
+.Nd rpld configuration file
+.Sh DESCRIPTION
+The 
+.Xr rpld.conf
+file is the configuration file for the
+.Pa rpld(1)
+program.
+It consists of a number of HOST blocks of the form:
+.Bd -literal -ffset indent
+HOST {
+     ...
+};
+
+.Ed
+Within the HOST blocks there can be 
+ethernet, execute, framesize  and blocksize directives and FILE blocks.
+FILE blocks are of the form:
+.Bd -literal -ffset indent
+       FILE {
+            ...
+       };
+
+.Ed
+Within FILE blocks there can be path, offset, length, load and linux directives.
+Directives are of the form
+.Bd -literal -ffset indent
+       foo = something;
+or
+.Bd -literal -ffset indent
+       bar;
+
+.Ed
+and are detailed below. Comments are allowed in the configuration file and
+can either be in C-form (i.e. starting with /* and ending with */) or C++ form
+(starting with // and ending at the line break).
+.Pp
+.Sh DIRECTIVES
+.Pp
+Directives are of the form 
+.Bd -literal -ffset indent
+       foo = something;
+or
+.Bd -literal -ffset indent
+       bar;
+
+.Ed
+If something is a string it should be entered between quotes. Numbers are
+assumed to be decimal unless preceded by 0x in which case they are interpreted
+in hexadecimal. MAC addresses should be given as 6 octets in hexadecimal without
+the leading 0x. The octets should be separated by colons.
+.Bd -literal -ffset indent
+       number = 131;
+       hexnumber = 0x7382;
+       macaddr = 08:00:02:43:21:22;
+       string = "fish soup";
+
+.Ed
+.Bl -tag -width 0 -compact
+.It Pa blocksize
+This directive sets the maximum size in octets of data that is transmitted in
+each
+FILE.DATA.RESPONSE frame that the server sends. The block size should
+be at least 48 octets smaller than the frame size. After the client negotiates
+a frame size the block size is checked and if it is no longer 48 octets smaller
+than frame size it is adjusted accordingly. Some buggy boot ROMs will fail
+if block size is not a multiple of four, accordingly you should be aware of the
+situation that could arise if the client was to negotiate the block size down
+to something that wasn't a multiple of four.
+.Bd -literal -ffset indent
+       blocksize = 528;
+
+.Ed
+.It Pa ethernet
+This directive sets the MAC address of the client referenced
+in this HOST block. It should be formatted as six octets separated by colons. e.g..
+.Bd -literal -ffset indent
+       ethernet = 00:60:6e:33:4f:2c;
+
+.Ed
+.It Pa execute
+This directive sets the execute address that control is transferred to when 
+downloading has finished. It should be a number in either decimal or hexadecimal.
+.Bd -literal -ffset indent
+       execute = 0x92000;
+
+.Ed
+It is not clear whether or not the client's Ethernet adapter is or should be shut down
+prior to the transfer of control. This may cause problems on systems where the
+Ethernet adapter in the client can do DMA directly into host memory. As the adapter may 
+continue writing to the buffers that the boot ROM set up, it may be necessary
+to download a small program to reset the Ethernet adapter. See code under the
+.Pa nics/
+directory in the source distribution for examples.
+.It Pa framesize
+This directive sets the maximum size of the frames that the server uses to
+communicate with the client. The actual frame size used is negotiated between
+the client and the server, the server will force the client to use this value
+if it requests a larger one. The maximum frame size that Ethernet can support is
+1500, and this is the default value.
+.Bd -literal -ffset indent
+       framesize = 576;
+
+.Ed
+.It Pa length
+This directive sets the number of octets transmitted to the client for this
+FILE block. If this directive is not specified the server transmits data 
+until an end of file condition occurs.
+.Bd -literal -ffset indent
+       length = 4096;
+
+.Ed
+would send 4096 octets from the file.
+.It Pa linux
+This directive takes no argument. It indicates to 
+.Xr rpld 1
+that the file specified in the path directive is a Linux kernel image. 
+.Xr rpld 1
+then analyses the kernel image and generates three FILE blocks corresponding
+to the primary boot loader, secondary boot loader, and data portions of the image.
+It then sets a default execute address which points to the secondary boot loader
+which is loaded at 0x90200. The execute address may be over-ridden with an execute
+directive which appears AFTER the FILE block. 
+.Bd -literal -ffset indent
+       linux;
+
+.Ed
+.Xr rpld 1
+may have problems with bzImage kernels.
+.It Pa load
+This directive sets the load address for this FILE block. Data is read from 
+.Pa offset
+octets into the file at copied to the client starting at the address
+specified by the load directive. The FILE block
+.Bd -literal -ffset indent
+FILE {
+       path = "/rplboot/fish";
+       offset = 512;
+       length = 4096;
+       load = 0x90200;
+};
+
+.Ed
+would load 4096 octets from the file 
+.Pa /rplboot/fish
+starting 512 octets into the file into the
+client's memory starting 
+at address 0x90200. (so the 513th byte of the file will load to address 0x90200)
+.It Pa offset
+This directive sets the offset for this FILE block. Data is read from 
+.Pa offset
+octets into the file at copied to the client starting at the address
+specified by the load directive.
+.Bd -literal -ffset indent
+       offset = 512;
+
+.Ed
+.It Pa path
+This directive sets the path to the file that is to be downloaded. The file
+must exist, and is examined at startup and on reception of SEND.FILE.REQUEST
+frames.
+.Bd -literal -ffset indent
+       path = "/rplboot/fish";
+
+.Ed
+.El
+.Sh NOTES
+.Pp
+The server downloads the FILE blocks in the inverse order to that in which
+they were specified. Boot ROMs typically prefer the blocks to arrive in
+decreasing load address, so you should specify them in increasing load address.
+The server recalculates the length of all the files specified on reception of
+a SEND.FILE.REQUEST frame. If the file changes size during downloading
+the server will attempt to read to the original length of the file. If it 
+encounters an end of file condition empty FILE DATA FRAMES will be sent. For Linux
+kernel images the first sector of the kernel image will only be read from
+disk when rpld is started. The first sector contains information such as the
+default root device and the length of secondary boot loader.
+You should therefore restart rpld if you change the version
+of the kernel you are downloading. The order of directives is important: the
+execute directive, if present, should always come after the 
+.Pa linux
+directive. 
+
+.Sh Example
+.Pp
+A complete example file using every directive:
+.Bd -literal -ffset indent
+// Sample rpld.conf file 
+/* (c) 1999 James McKenzie and
+ *          Christopher Lightfoot
+ *          All rights reserved.
+ */
+
+HOST {
+       ethernet=08:00:02:32:1e:fc;
+       FILE {
+               path="/rplboot/vmlinuz";
+               linux;
+       };
+       FILE {
+               path="/rplboot/vesarom.img";
+               offset=0x200;
+               length=0x400;
+               load=0x92000;
+       };
+       execute=0x92000;
+};
+
+.Ed
+.Sh FILES
+.Bl -tag -width /etc/rpld.conf -compact
+.It Pa /etc/rpld.conf
+The
+.Xr rpld 1
+configuration file.
+.El
+.Sh SEE ALSO
+.Xr rpld 1 ,
+.Xr bootpd 1 ,
+.Xr dhcpd 1 ,
+.Xr http://bullard.esc.cam.ac.uk/~james/rpld ;
+.Sh AUTHORS AND COPYRIGHT
+.Pp
+(c) 1999 James McKenzie, and Christopher Lightfoot. All rights reserved.
diff --git a/rpld.conf.sample b/rpld.conf.sample
new file mode 100644 (file)
index 0000000..c1dd5c3
--- /dev/null
@@ -0,0 +1,123 @@
+// A Sample rpld configuration file
+/* 
+ * Note both c++ and c style comments are accepted
+ */
+
+/* A host block for a Solaris(TM) client */
+/* Note the order is reversed from Sun's rpld(1M) */ 
+HOST
+{
+       ethernet = 00:60:6e:33:4f:2c;    // This is the mac address of the client
+
+       FILE
+       {
+               path = "/rplboot/10.93.43.2/inetboot";
+               load = 0x8000;
+       };
+
+       FILE
+       {
+               path = "/rplboot/10.93.43.2/glue.com";
+               load = 0x35000;
+       };
+
+       FILE
+       {
+               path = "/rplboot/10.93.43.2/hw.com";
+               load = 0x45000;
+       };
+
+       execute = 0x35000;
+
+// Framesize is the maximum frame size that rpld will use.
+// this can be negociated down by the client. The default is 1500
+
+       framesize = 1500;
+
+// Blocksize is the maximum size of data blocks sent to the
+// client. Some clients ignore packets with blocksize not
+// divisable by 4. The default is 1440. The client can
+// also negociate this down. blocksize should be < (framesize-48)
+
+       blocksize = 1440;
+};
+
+/*
+ * A host block for a linux client 
+ * rpld is able to read and understand linux kernel images 
+ * and load them appropriately 
+ */
+
+HOST
+{
+       ethernet = 00:60:6e:36:f9:91;
+
+       FILE
+       {
+               path = "/rplboot/tea/vmlinuz";
+               linux;  //The linux directive sets the execute addr
+                       //But it can be overridden later
+       };
+// NB: Some bootroms leave shared memory network cards initialized and
+// spewing data over some poor innocent peice of memory (so that they
+// can load a PXE stub or other horrors later, Intel has a bootrom API)
+// In this case you need a small program to konk the network card firmly
+// into the off state before you transfer control.
+
+/*
+       FILE
+       {
+               path = "/rplboot/tea/dmfix";
+               load=0x92000;
+       };
+// dmfix needs to execute first and then transfer control to the linux
+// kernel at 0x90200
+
+       execute=0x92000;        
+*/
+
+};
+
+
+// The following example shows how to load memtest86, you could use
+// the linux directive but this shows explicitly what happens
+
+
+HOST {
+       ethernet = 08:00:02:32:1e:fc;
+
+       // Last step load the rest of the kernel starting
+       // at bootloader length + sector length=0xa00
+       // To 0x10000
+       FILE {
+               path="/rplboot/memtest86.bin";
+               offset=0xa00;
+               load=0x10000;
+       };      
+
+       // Middle step, load the secondary boot loader at 0x90200
+       // The secondary boot loader is typically 4 512 byte blocks
+       // However in needn't be; the 497th byte of the kernel contains
+       // the size of the bootloader in 512 byte blocks. If zero then
+       // it is actually 0x800 (4 blocks)
+       FILE {
+               path="/rplboot/memtest86.bin";
+               offset=0x200;           
+               length=0x800;
+               load=0x90200;
+       };
+
+       // First step load the setup sector (not actually executed)
+       // but is used to determine file sizes.
+
+       FILE {
+               path="/rplboot/memtest86.bin";
+               length=0x200;   
+               load=0x90000;
+       };
+
+       // Jump into the secondary boot loader
+       execute=0x90200;
+
+};
+
diff --git a/rpld.man b/rpld.man
new file mode 100644 (file)
index 0000000..c26ebd1
--- /dev/null
+++ b/rpld.man
@@ -0,0 +1,130 @@
+.\" 
+.\"/*************************************************
+.\"*     rpld - an IBM style RIPL server            *
+.\"*************************************************/
+.\"
+.\"Copyright (c) 1999, James McKenzie.
+.\"                     All rights reserved
+.\"Copyright (c) 1998, Christopher Lightfoot.
+.\"                     All rights reserved
+.\"
+.\"By using this file, you agree to the terms and conditions set
+.\"forth in the LICENSE file which can be found at the top level of
+.\"the rpld distribution.
+.\"
+.\"IBM is a trademark of IBM Corp.
+.\"
+.\"
+.\"
+.\" $Id: rpld.man,v 1.6 2000/07/16 13:18:10 root Exp root $;
+.\"
+.\" $Log: rpld.man,v $
+.\" Revision 1.6  2000/07/16 13:18:10  root
+.\" #
+.\"
+.\" Revision 1.1  2000/07/16 13:16:33  root
+.\" #
+.\"
+.\" Revision 1.10  1999/09/15 01:22:18  root
+.\" #
+.\"
+.\" Revision 1.9  1999/09/15 00:36:29  root
+.\" #
+.\"
+.\" Revision 1.8  1999/09/15 00:25:57  root
+.\" #
+.\"
+.\" Revision 1.7  1999/09/15 00:22:07  root
+.\" #
+.\"
+.\" Revision 1.6  1999/09/15 00:14:29  root
+.\" #
+.\"
+.\" Revision 1.5  1999/09/14 21:43:30  root
+.\" #
+.\"
+.\" Revision 1.4  1999/09/14 21:37:08  root
+.\" #
+.\"
+.\" Revision 1.3  1999/09/14 21:32:12  root
+.\" #
+.\"
+.\" Revision 1.2  1999/09/14 21:25:59  root
+.\" #
+.\"
+.\" Revision 1.1  1999/09/14 21:00:47  root
+.\" #
+.\"
+.\" Revision 1.1  1999/09/14 17:19:37  root
+.\" Initial revision
+.\"
+.\";
+.Dd Sep 14, 1999
+.Dt RPLD 8
+.Os Linux
+.Sh NAME
+.Nm rpld
+.Nd an RPL/RIPL remote boot server
+.Sh SYNOPSIS
+.Nm rpld
+.Sh WARRANTY
+.Nm rpld 
+DOES NOT come with ANY WARRANTY, NOT even an IMPLIED WARRANTY.
+.Sh DESCRIPTION
+.Nm rpld 
+will net-boot IBM style RPL boot ROMs. Communication between the client and the
+server is done in LLC-1 ui/C frames with the source and destination SAP both 
+being 0xfc. On booting the client transmits a FIND frame containing the client's
+MAC address, adapter type and frame length. The server replies with a FOUND frame
+containing the server's MAC address and a possibly smaller frame length. The
+client issues a SEND.FILE.REQUEST frame requesting the first block of the boot
+file. The server then issues a sequence of FILE.DATA.RESPONSE frames with 
+increasing block numbers. The FILE.DATA.RESPONSE frames contain a load address
+and an execute address and a flag. If the client fails to receive a  
+FILE.DATA.RESPONSE frame within a certain period it sends another 
+SEND.FILE.REQUEST frame requesting the block which follows the last block that
+was successfully received. On the last FILE.DATA.RESPONSE frame the server
+sets a special value of the flags which cause the client to transfer execution
+to the execute address specified in the frame.
+.Pp
+The server starts by reading the configuration file in /etc/rpld.conf,
+see 
+.Pa rpld.conf(5),
+After the configuration file has been read, it opens the system's
+default network interface and listens for RPL frames.
+The server recalculates the length of all the files to be downloaded every time
+it receives a SEND.FILE.REQUEST frame. 
+.Sh BUGS
+.Bl -tag -width 0 -compact
+.It
+Solenopsis invicta Buren 
+.It
+rpld (probably) doesn't support the new bzImage format correctly.
+.It
+rpld doesn't reload the first 512 octets of Linux kernels automatically.
+.It
+There is no way to make rpld re-read its configuration file.
+.It
+rpld 
+needs to meet more network adapters.
+.Sh NOTES
+.Pp
+IBM is a trademark of IBM Corp.
+.Sh FILES
+.Bl -tag -width /etc/rpld.conf -compact
+.Pp
+.It Pa /usr/sbin/rpld
+.It Pa /etc/rpld.conf
+.It Pa /rplboot
+.El
+.Sh SEE ALSO
+.Pp
+.Bl -tag -width 0 -compact
+.It Pa rpld\.conf(5),
+.It Pa bootpd(1),
+.It Pa dhcpd(1),
+.It Pa http://bullard.esc.cam.ac.uk/~james/rpld;
+.El
+.Sh AUTHORS AND COPYRIGHT
+.Pp
+(c) 1999 James McKenzie, and Christopher Lightfoot. All rights reserved.
diff --git a/rpld_conf.lex b/rpld_conf.lex
new file mode 100644 (file)
index 0000000..e09726c
--- /dev/null
@@ -0,0 +1,139 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+/*
+ *  Lexer for RPLD conf files
+ *
+ *  $Log: rpld_conf.lex,v $
+ *  Revision 1.4  2000/07/16 13:18:10  root
+ *  #
+ *
+ *  Revision 1.1  2000/07/16 13:16:33  root
+ *  #
+ *
+ *  Revision 1.3  1999/09/13 11:17:35  root
+ *  \#
+ *
+ *  Revision 1.2  1999/09/13 11:08:34  root
+ *  \#
+ *
+ *  Revision 1.1  1999/09/13 11:04:13  root
+ *  \#
+ *
+ *  Revision 1.10  1999/09/12 19:08:24  chris
+ *  Another attempt at C comments.
+ *
+ *  Revision 1.9  1999/09/12 17:38:45  chris
+ *  Implemented proper MAC reading.
+ *
+ *  Revision 1.8  1999/09/12 03:27:43  chris
+ *  Changes to enable error reporting in yacc grammar.
+ *
+ *  Revision 1.7  1999/09/11 19:30:26  chris
+ *  Fixed hex number support.
+ *
+ *  Revision 1.6  1999/09/11 19:25:06  chris
+ *  No major changes.
+ *
+ *  Revision 1.5  1999/09/11 19:24:23  chris
+ *  Removed support for C-style comments, inserted support for C++ ones. Comment support actually works now
+ *
+ *  Revision 1.4  1999/09/11 19:02:25  chris
+ *  Fixed bug in comment support.
+ *
+ *  Revision 1.3  1999/09/11 19:00:43  chris
+ *  Added support for comments.
+ *
+ *  Revision 1.2  1999/09/11 18:57:31  chris
+ *  Initial revision.
+ *
+ *  
+ */
+
+%x     COMMENT
+
+%{
+static char rcsid[]="$Id: rpld_conf.lex,v 1.4 2000/07/16 13:18:10 root Exp root $";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rpld_conf.tab.h"
+
+
+// line number
+int lineno = 1;
+
+// function to convert hex digits to a MAC address
+void strtomac(char *s, char *mac);
+
+void strtomac(char *s, char *mac)
+{
+       // mac address *must* be in form 00:11:22:33:44:55
+       int i;
+
+       for (i = 0; i < 6; i++) *(mac + i) = (unsigned char)strtol(s + i * 3, NULL, 16);
+}
+
+
+%}
+ws     [ \t]+
+nl     \n
+hb     [0-9A-Fa-f][0-9A-Fa-f]
+
+%%
+
+{ws}                   ;
+{nl}                   { lineno++; }
+
+\/\/.*                 ;
+
+"/*"                   BEGIN COMMENT;
+<COMMENT>.     |
+<COMMENT>\n            ;
+<COMMENT>"*/"          BEGIN INITIAL;
+
+[{]                    { return BLOCK_START; }
+
+[}]                    { return BLOCK_END; }
+
+{hb}:{hb}:{hb}:{hb}:{hb}:{hb}  { strtomac(yytext, (yylval.mac_address)); return MACADDR; }
+
+0x[0-9A-Fa-f]+ {
+                               yylval.number = strtol(yytext + 2, NULL, 16);
+                               return NUMBER;
+                       }
+
+[0-9]+                 {
+                               int i; i = strtol(yytext, NULL, 10);
+                               yylval.number = i; return NUMBER;
+                       }
+
+[A-Za-z\-_]+           { yylval.name = strdup(yytext); return NAME; }
+
+\"[A-Za-z0-9.:/\-_ ]*\"        { yylval.text = strdup(yytext + 1); *(yylval.text + strlen(yylval.text) - 1) = 0; return TEXT;}
+
+.                      { return yytext[0]; }
+
+%%
+
+
+int yywrap()
+{
+       return 1;
+}
+
diff --git a/rpld_conf.tab.c b/rpld_conf.tab.c
new file mode 100644 (file)
index 0000000..613f122
--- /dev/null
@@ -0,0 +1,667 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar  1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 65 "rpld_conf.y"
+
+static char rcsid[]="$Id: rpld_conf.y,v 1.3 2000/07/16 13:18:10 root Exp root $";
+
+#include "project.h"
+
+/* state machine stuff*/
+
+typedef enum {START, BLOCK_START, BLOCK_END, ASSERTION, ASSIGNMENT} THING ;
+typedef enum {INIT, GLOBALBLOCK, HOSTBLOCK, FILEBLOCK} STATE ;
+
+/*void process_thing(THING thing, char *name, int type, YYSTYPE *pvalue);*/
+
+#line 81 "rpld_conf.y"
+typedef union {
+               long number;
+               char *name;
+               char *text;
+               char mac_address[6];
+       } YYSTYPE;
+#line 32 "rpld_conf.tab.c"
+#define BLOCK_START 257
+#define BLOCK_END 258
+#define NAME 259
+#define TEXT 260
+#define NUMBER 261
+#define MACADDR 262
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    0,    1,    1,    2,    2,    3,    3,    3,    4,
+    4,    4,    4,    4,
+};
+short yylen[] = {                                         2,
+    2,    3,    3,    2,    2,    1,    1,    2,    3,    1,
+    3,    3,    3,    1,
+};
+short yydefred[] = {                                      0,
+    6,    0,    0,    0,    0,    5,    0,    1,    4,    0,
+    7,   14,    0,    0,    2,    0,    3,    0,    8,   11,
+   12,   13,    9,
+};
+short yydgoto[] = {                                       3,
+   12,    5,   13,   14,
+};
+short yysindex[] = {                                   -244,
+    0, -254, -244,  -55,  -59,    0,  -50,    0,    0,  -60,
+    0,    0, -251,  -45,    0, -250,    0,  -43,    0,    0,
+    0,    0,    0,
+};
+short yyrindex[] = {                                      0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,  -42,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,
+};
+short yygindex[] = {                                      0,
+    2,    0,    0,    5,
+};
+#define YYTABLESIZE 200
+short yytable[] = {                                      11,
+   16,    4,    6,    8,    7,    1,   17,   10,   15,   20,
+   21,   22,    1,   19,    2,   23,   10,   18,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    6,    1,    9,   10,
+};
+short yycheck[] = {                                      59,
+   61,    0,  257,   59,    3,  257,  258,  259,   59,  260,
+  261,  262,  257,   59,  259,   59,   59,   13,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  257,  257,  258,  259,
+};
+#define YYFINAL 3
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 262
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0,"'='",0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"BLOCK_START","BLOCK_END",
+"NAME","TEXT","NUMBER","MACADDR",
+};
+char *yyrule[] = {
+"$accept : block_list",
+"block_list : block ';'",
+"block_list : block_list block ';'",
+"block : block_start statement_list BLOCK_END",
+"block : block_start BLOCK_END",
+"block_start : NAME BLOCK_START",
+"block_start : BLOCK_START",
+"statement_list : ';'",
+"statement_list : statement ';'",
+"statement_list : statement_list statement ';'",
+"statement : NAME",
+"statement : NAME '=' TEXT",
+"statement : NAME '=' NUMBER",
+"statement : NAME '=' MACADDR",
+"statement : block",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 114 "rpld_conf.y"
+
+//
+// ERROR REPORTING
+//
+
+// the lineno variable from our parser
+extern int lineno;
+
+// the yytext variable from lex for error reporting
+extern char* yytext;
+
+void yyerror(char *s)
+{
+       fprintf(stderr, "rpld: config line %d: %s near `%s'\n", lineno, s, yytext);
+}
+
+//
+// CONFIGURATION PROCESSOR
+//
+
+// This is the bit that actually does the work
+
+#define strsame(a, b)  (!strcmp((a), (b)))
+/*
+struct global_parameters
+{
+
+} g_params;
+*/
+
+struct clientinfo
+{
+       int have_mac;
+       int have_run_addr;
+       int have_files;
+       // optional
+       int have_framesize;
+       int have_blocksize;
+};
+
+struct clfileinfo
+{
+       int have_path;
+       int have_load_addr;
+       // optional
+       int have_offset;
+       int have_length;
+};
+
+extern struct client *clients;
+
+// hideous, we need to cope with a semicolon after this
+//#define THROW_ERROR(a)       do { yyerror((a)); exit(1); } while(0)
+#define THROW_ERROR(a) do { fprintf(stderr, "rpld: config line %d: %s near `%s'\n", lineno, (a), name); exit(1); } while(0)
+
+void process_thing(THING thing, char *name, int type, YYSTYPE *pvalue)
+{
+       static STATE state;
+       static struct client *pc;
+       static struct clientinfo ci;
+       static struct clfile *pcf;
+       static struct clfileinfo cfi;
+
+       switch(thing)
+       {
+       // boot the state machine
+       case START:
+               state = INIT;
+               break;
+
+       //
+       // Blocks, which contain related options
+       //
+       
+       // start of a block
+       case BLOCK_START:
+               // in initial state, move to GLOBALBLOCK or HOSTBLOCK
+               if (state == INIT) {
+                       if (strsame(name, "GLOBAL")) {
+                               state = GLOBALBLOCK;
+                               break;
+                       } else if (strsame(name, "HOST") || strsame(name, "CLIENT")) {
+                               // construct a new client entity
+                               pc = (struct client*)malloc(sizeof(struct client));
+                               bzero(pc, sizeof(struct client));
+                               // reset info about what options have been set for this client
+                               bzero(&ci, sizeof(ci));
+
+                               pc->blocklen=MY_BLOCK_LEN;
+                               pc->framelen=MY_FRAME_LEN;
+                               
+                               state = HOSTBLOCK;
+                               break;
+                       } else THROW_ERROR("Unknown top-level parameter block");
+               }
+               // in a HOST block, this must be a FILE
+               else if (state == HOSTBLOCK) {
+                       if (strsame(name, "FILE")) {
+                               // construct a new file entity
+                               pcf = (struct clfile*)malloc(sizeof(struct clfile));
+                               bzero(pcf, sizeof(struct clfile));
+                               pcf->length=-1;
+                               // reset info about options set for this file
+                               bzero(&cfi, sizeof(cfi));
+                               
+                               state = FILEBLOCK;
+                               break;
+                       } else THROW_ERROR("Only a FILE parameter block can be included in a HOST block");
+               }
+               // fuck knows
+               else
+               {
+                       yyerror("Unknown parameter block");
+                       exit(1);
+               }
+               break;
+
+       // end of a block, we should have a bunch of info now
+       case BLOCK_END:
+               // end GLOBAL block
+               if (state == GLOBALBLOCK) {
+                       // no more global params, at least for the moment
+               }
+               // end HOST block
+               else if (state == HOSTBLOCK) {
+                       // should have a complete host specification
+                       if (!ci.have_mac) THROW_ERROR("Must specify an ethernet (MAC) address for host");
+                       else if (!ci.have_run_addr) THROW_ERROR("Must specify an initial execute address for host");
+                       else if (!ci.have_files) THROW_ERROR("Must specify at least one file to load for host");
+
+                       // OK, should have an entire host spec, so copy it in
+                       pc->next = clients;
+                       clients = pc;
+
+                       // finished this host spec
+                       state = INIT;
+                       break;
+               }
+               // end FILE block
+               else if (state == FILEBLOCK) {
+                       // should have a complete file specification
+                       if (!cfi.have_path) THROW_ERROR("Must specify a path for file");
+                       else if (!cfi.have_load_addr) THROW_ERROR("Must specify a load address for file");
+
+                       // have an entire file spec, copy it into the host spec
+                       pcf->next = pc->files;
+                       pc->files = pcf;
+
+                       ci.have_files = 1;
+
+                       // done
+                       state = HOSTBLOCK;
+                       break;
+               }
+
+       //
+       // The various things that go inside blocks
+       //
+       
+       case ASSERTION:
+               if (state == GLOBALBLOCK) {
+                       // no global assertions ATM
+                       THROW_ERROR("Unknown directive");
+               } else if (state == HOSTBLOCK) {
+                       // no host assertions ATM
+                       THROW_ERROR("Unknown directive");
+               } else if (state == FILEBLOCK) {
+                       if (strsame(name,"linux")) {
+                               if (!cfi.have_path) THROW_ERROR("A path to a
+valid kernel must precede linux");
+
+                               do_linux_kernel(pc,pcf);
+                               cfi.have_load_addr=1;
+                               cfi.have_offset=1;
+                               cfi.have_length=1;
+                               ci.have_run_addr=1;
+                       } else{
+                       THROW_ERROR("Unknown directive");
+                       }
+               } else THROW_ERROR("Unknown directive");
+               break;
+
+       case ASSIGNMENT:
+               if (state == GLOBALBLOCK) {
+                       // no global assignments ATM
+                       THROW_ERROR("Unknown directive");
+               } else if (state == HOSTBLOCK) {
+                       // ethernet address
+                       if (strsame(name, "ethernet") || strsame(name, "mac")) {
+                               if (type != MACADDR) THROW_ERROR("Directive must be followed by an ethernet address");
+                               else if (ci.have_mac) THROW_ERROR("Repeated directive");
+
+                               // set MAC address
+                               bcopy(pvalue->mac_address,pc->mac,ETH_ALEN);
+                               ci.have_mac = 1;
+                       }
+                       // execute address
+                       else if (strsame(name, "execute") || strsame(name, "run")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (ci.have_run_addr==2) THROW_ERROR("Repeated directive");
+
+                               // set address
+                               pc->run_addr = pvalue->number;
+                               ci.have_run_addr = 2;
+                       }
+                       else if (strsame(name, "blocksize")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
+                               else if (ci.have_blocksize) THROW_ERROR("Repeated directive");
+
+                               // set address
+                               pc->blocklen = pvalue->number;
+                               ci.have_blocksize = 1;
+                       }
+                       else if (strsame(name, "framesize")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
+                               else if (ci.have_framesize) THROW_ERROR("Repeated directive");
+
+                               // set size
+                               pc->framelen = pvalue->number;
+                               ci.have_framesize = 1;
+                       }
+                       else THROW_ERROR("Unknown directive");
+               } else if (state == FILEBLOCK) {
+                       // path
+                       if (strsame(name, "path")) {
+                               if (type != TEXT) THROW_ERROR("Directive must be followed by a filename");
+                               else if (cfi.have_path) THROW_ERROR("Repeated directive");
+
+                               // set filename
+                               pcf->path = pvalue->text;
+                               cfi.have_path = 1;
+                       }
+                       // load address
+                       else if (strsame(name, "load")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (cfi.have_load_addr) THROW_ERROR("Repeated directive");
+
+                               // set load address
+                               pcf->load_addr = pvalue->number;
+                               cfi.have_load_addr = 1;
+                       }
+                       // offset
+                       else if (strsame(name, "offset")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (cfi.have_offset) THROW_ERROR("Repeated directive");
+
+                               // set offset
+                               pcf->offset = pvalue->number;
+                               cfi.have_offset = 1;
+                       }
+                       // length
+                       else if (strsame(name, "length")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (cfi.have_length) THROW_ERROR("Repeated directive");
+
+                               // set length
+                               pcf->length = pvalue->number;
+                               cfi.have_length = 1;
+                       }
+                       else THROW_ERROR("Unknown directive");
+               }
+               break;
+
+               default: THROW_ERROR("Mistake");
+       }
+       
+
+}
+#line 439 "rpld_conf.tab.c"
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    register int yym, yyn, yystate;
+#if YYDEBUG
+    register char *yys;
+    extern char *getenv();
+
+    if (yys = getenv("YYDEBUG"))
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if (yyn = yydefred[yystate]) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yyss + yystacksize - 1)
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#ifdef lint
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yyss + yystacksize - 1)
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 3:
+#line 96 "rpld_conf.y"
+{ process_thing(BLOCK_END, "", 0, NULL); }
+break;
+case 4:
+#line 97 "rpld_conf.y"
+{ process_thing(BLOCK_END, "", 0, NULL); }
+break;
+case 5:
+#line 99 "rpld_conf.y"
+{ process_thing(BLOCK_START, yyvsp[-1].name, 0, NULL); }
+break;
+case 6:
+#line 100 "rpld_conf.y"
+{ process_thing(BLOCK_START, "", 0, NULL); }
+break;
+case 10:
+#line 107 "rpld_conf.y"
+{ process_thing(ASSERTION, yyvsp[0].name, 0, NULL); }
+break;
+case 11:
+#line 108 "rpld_conf.y"
+{ process_thing(ASSIGNMENT, yyvsp[-2].name, TEXT, &yyvsp[0]); }
+break;
+case 12:
+#line 109 "rpld_conf.y"
+{ process_thing(ASSIGNMENT, yyvsp[-2].name, NUMBER, &yyvsp[0]); }
+break;
+case 13:
+#line 110 "rpld_conf.y"
+{ process_thing(ASSIGNMENT, yyvsp[-2].name, MACADDR, &yyvsp[0]); }
+break;
+#line 612 "rpld_conf.tab.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yyss + yystacksize - 1)
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
diff --git a/rpld_conf.tab.h b/rpld_conf.tab.h
new file mode 100644 (file)
index 0000000..9489079
--- /dev/null
@@ -0,0 +1,13 @@
+#define BLOCK_START 257
+#define BLOCK_END 258
+#define NAME 259
+#define TEXT 260
+#define NUMBER 261
+#define MACADDR 262
+typedef union {
+               long number;
+               char *name;
+               char *text;
+               char mac_address[6];
+       } YYSTYPE;
+extern YYSTYPE yylval;
diff --git a/rpld_conf.y b/rpld_conf.y
new file mode 100644 (file)
index 0000000..ece011d
--- /dev/null
@@ -0,0 +1,381 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+/*
+ *     YACC grammar for RPLD conf file parser
+ *
+ * $Log: rpld_conf.y,v $
+ * Revision 1.3  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.2  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.1  1999/09/13 11:04:13  root
+ * \#
+ *
+ * Revision 1.10  1999/09/12 19:45:03  chris
+ * *** empty log message ***
+ *
+ * Revision 1.9  1999/09/12 19:14:07  chris
+ * Error messages now report name of last token scanned, instead of current yytext.
+ *
+ * Revision 1.8  1999/09/12 17:39:01  chris
+ * Configuration file now correctly builds structures; various minor problems fixed.
+ *
+ * Revision 1.7  1999/09/12 04:21:29  chris
+ * Wrote back-end to parser.
+ *
+ * Revision 1.6  1999/09/12 03:27:35  chris
+ * Added better error reporting.
+ *
+ * Revision 1.5  1999/09/12 01:05:00  chris
+ * Supports detecting start and end of blocks.
+ *
+ * Revision 1.4  1999/09/12 00:58:02  chris
+ * Added named block syntax.
+ *
+ * Revision 1.3  1999/09/11 19:00:51  chris
+ * Added support for nested blocks.
+ *
+ * Revision 1.2  1999/09/11 18:53:41  chris
+ * Added a comment to say what the file does.
+ *
+ *
+ */
+
+%{
+
+static char rcsid[]="$Id: rpld_conf.y,v 1.3 2000/07/16 13:18:10 root Exp root $";
+
+#include "project.h"
+
+// state machine stuff
+
+typedef enum {START, BLOCK_START, BLOCK_END, ASSERTION, ASSIGNMENT} THING ;
+typedef enum {INIT, GLOBALBLOCK, HOSTBLOCK, FILEBLOCK} STATE ;
+
+//void process_thing(THING thing, char *name, int type, YYSTYPE *pvalue);
+
+%}
+
+%token BLOCK_START BLOCK_END NAME TEXT NUMBER MACADDR
+
+%union {
+               long number;
+               char *name;
+               char *text;
+               char mac_address[6];
+       }
+
+%start block_list
+
+%%
+
+block_list:    block ';'
+       |       block_list block ';'
+       ;
+
+block:         block_start statement_list BLOCK_END    { process_thing(BLOCK_END, "", 0, NULL); }
+       |       block_start BLOCK_END   { process_thing(BLOCK_END, "", 0, NULL); }
+
+block_start:   NAME BLOCK_START        { process_thing(BLOCK_START, $1.name, 0, NULL); }
+       |       BLOCK_START             { process_thing(BLOCK_START, "", 0, NULL); }
+
+statement_list:        ';'
+       |       statement ';'
+       |       statement_list statement ';'
+
+
+statement:     NAME                    { process_thing(ASSERTION, $1.name, 0, NULL); }
+       |       NAME '=' TEXT           { process_thing(ASSIGNMENT, $1.name, TEXT, &$3); }
+       |       NAME '=' NUMBER         { process_thing(ASSIGNMENT, $1.name, NUMBER, &$3); }
+       |       NAME '=' MACADDR        { process_thing(ASSIGNMENT, $1.name, MACADDR, &$3); }
+       |       block
+
+%%
+
+//
+// ERROR REPORTING
+//
+
+// the lineno variable from our parser
+extern int lineno;
+
+// the yytext variable from lex for error reporting
+extern char* yytext;
+
+void yyerror(char *s)
+{
+       fprintf(stderr, "rpld: config line %d: %s near `%s'\n", lineno, s, yytext);
+}
+
+//
+// CONFIGURATION PROCESSOR
+//
+
+// This is the bit that actually does the work
+
+#define strsame(a, b)  (!strcmp((a), (b)))
+/*
+struct global_parameters
+{
+
+} g_params;
+*/
+
+struct clientinfo
+{
+       int have_mac;
+       int have_run_addr;
+       int have_files;
+       // optional
+       int have_framesize;
+       int have_blocksize;
+};
+
+struct clfileinfo
+{
+       int have_path;
+       int have_load_addr;
+       // optional
+       int have_offset;
+       int have_length;
+};
+
+extern struct client *clients;
+
+// hideous, we need to cope with a semicolon after this
+//#define THROW_ERROR(a)       do { yyerror((a)); exit(1); } while(0)
+#define THROW_ERROR(a) do { fprintf(stderr, "rpld: config line %d: %s near `%s'\n", lineno, (a), name); exit(1); } while(0)
+
+void process_thing(THING thing, char *name, int type, YYSTYPE *pvalue)
+{
+       static STATE state;
+       static struct client *pc;
+       static struct clientinfo ci;
+       static struct clfile *pcf;
+       static struct clfileinfo cfi;
+
+       switch(thing)
+       {
+       // boot the state machine
+       case START:
+               state = INIT;
+               break;
+
+       //
+       // Blocks, which contain related options
+       //
+       
+       // start of a block
+       case BLOCK_START:
+               // in initial state, move to GLOBALBLOCK or HOSTBLOCK
+               if (state == INIT) {
+                       if (strsame(name, "GLOBAL")) {
+                               state = GLOBALBLOCK;
+                               break;
+                       } else if (strsame(name, "HOST") || strsame(name, "CLIENT")) {
+                               // construct a new client entity
+                               pc = (struct client*)malloc(sizeof(struct client));
+                               bzero(pc, sizeof(struct client));
+                               // reset info about what options have been set for this client
+                               bzero(&ci, sizeof(ci));
+
+                               pc->blocklen=MY_BLOCK_LEN;
+                               pc->framelen=MY_FRAME_LEN;
+                               
+                               state = HOSTBLOCK;
+                               break;
+                       } else THROW_ERROR("Unknown top-level parameter block");
+               }
+               // in a HOST block, this must be a FILE
+               else if (state == HOSTBLOCK) {
+                       if (strsame(name, "FILE")) {
+                               // construct a new file entity
+                               pcf = (struct clfile*)malloc(sizeof(struct clfile));
+                               bzero(pcf, sizeof(struct clfile));
+                               pcf->length=-1;
+                               // reset info about options set for this file
+                               bzero(&cfi, sizeof(cfi));
+                               
+                               state = FILEBLOCK;
+                               break;
+                       } else THROW_ERROR("Only a FILE parameter block can be included in a HOST block");
+               }
+               // fuck knows
+               else
+               {
+                       yyerror("Unknown parameter block");
+                       exit(1);
+               }
+               break;
+
+       // end of a block, we should have a bunch of info now
+       case BLOCK_END:
+               // end GLOBAL block
+               if (state == GLOBALBLOCK) {
+                       // no more global params, at least for the moment
+               }
+               // end HOST block
+               else if (state == HOSTBLOCK) {
+                       // should have a complete host specification
+                       if (!ci.have_mac) THROW_ERROR("Must specify an ethernet (MAC) address for host");
+                       else if (!ci.have_run_addr) THROW_ERROR("Must specify an initial execute address for host");
+                       else if (!ci.have_files) THROW_ERROR("Must specify at least one file to load for host");
+
+                       // OK, should have an entire host spec, so copy it in
+                       pc->next = clients;
+                       clients = pc;
+
+                       // finished this host spec
+                       state = INIT;
+                       break;
+               }
+               // end FILE block
+               else if (state == FILEBLOCK) {
+                       // should have a complete file specification
+                       if (!cfi.have_path) THROW_ERROR("Must specify a path for file");
+                       else if (!cfi.have_load_addr) THROW_ERROR("Must specify a load address for file");
+
+                       // have an entire file spec, copy it into the host spec
+                       pcf->next = pc->files;
+                       pc->files = pcf;
+
+                       ci.have_files = 1;
+
+                       // done
+                       state = HOSTBLOCK;
+                       break;
+               }
+
+       //
+       // The various things that go inside blocks
+       //
+       
+       case ASSERTION:
+               if (state == GLOBALBLOCK) {
+                       // no global assertions ATM
+                       THROW_ERROR("Unknown directive");
+               } else if (state == HOSTBLOCK) {
+                       // no host assertions ATM
+                       THROW_ERROR("Unknown directive");
+               } else if (state == FILEBLOCK) {
+                       if (strsame(name,"linux")) {
+                               if (!cfi.have_path) THROW_ERROR("A path to a
+valid kernel must precede linux");
+
+                               do_linux_kernel(pc,pcf);
+                               cfi.have_load_addr=1;
+                               cfi.have_offset=1;
+                               cfi.have_length=1;
+                               ci.have_run_addr=1;
+                       } else{
+                       THROW_ERROR("Unknown directive");
+                       }
+               } else THROW_ERROR("Unknown directive");
+               break;
+
+       case ASSIGNMENT:
+               if (state == GLOBALBLOCK) {
+                       // no global assignments ATM
+                       THROW_ERROR("Unknown directive");
+               } else if (state == HOSTBLOCK) {
+                       // ethernet address
+                       if (strsame(name, "ethernet") || strsame(name, "mac")) {
+                               if (type != MACADDR) THROW_ERROR("Directive must be followed by an ethernet address");
+                               else if (ci.have_mac) THROW_ERROR("Repeated directive");
+
+                               // set MAC address
+                               bcopy(pvalue->mac_address,pc->mac,ETH_ALEN);
+                               ci.have_mac = 1;
+                       }
+                       // execute address
+                       else if (strsame(name, "execute") || strsame(name, "run")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (ci.have_run_addr==2) THROW_ERROR("Repeated directive");
+
+                               // set address
+                               pc->run_addr = pvalue->number;
+                               ci.have_run_addr = 2;
+                       }
+                       else if (strsame(name, "blocksize")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
+                               else if (ci.have_blocksize) THROW_ERROR("Repeated directive");
+
+                               // set address
+                               pc->blocklen = pvalue->number;
+                               ci.have_blocksize = 1;
+                       }
+                       else if (strsame(name, "framesize")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
+                               else if (ci.have_framesize) THROW_ERROR("Repeated directive");
+
+                               // set size
+                               pc->framelen = pvalue->number;
+                               ci.have_framesize = 1;
+                       }
+                       else THROW_ERROR("Unknown directive");
+               } else if (state == FILEBLOCK) {
+                       // path
+                       if (strsame(name, "path")) {
+                               if (type != TEXT) THROW_ERROR("Directive must be followed by a filename");
+                               else if (cfi.have_path) THROW_ERROR("Repeated directive");
+
+                               // set filename
+                               pcf->path = pvalue->text;
+                               cfi.have_path = 1;
+                       }
+                       // load address
+                       else if (strsame(name, "load")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (cfi.have_load_addr) THROW_ERROR("Repeated directive");
+
+                               // set load address
+                               pcf->load_addr = pvalue->number;
+                               cfi.have_load_addr = 1;
+                       }
+                       // offset
+                       else if (strsame(name, "offset")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (cfi.have_offset) THROW_ERROR("Repeated directive");
+
+                               // set offset
+                               pcf->offset = pvalue->number;
+                               cfi.have_offset = 1;
+                       }
+                       // length
+                       else if (strsame(name, "length")) {
+                               if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
+                               else if (cfi.have_length) THROW_ERROR("Repeated directive");
+
+                               // set length
+                               pcf->length = pvalue->number;
+                               cfi.have_length = 1;
+                       }
+                       else THROW_ERROR("Unknown directive");
+               }
+               break;
+
+               default: THROW_ERROR("Mistake");
+       }
+       
+
+}
diff --git a/rpld_conf.yy.c b/rpld_conf.yy.c
new file mode 100644 (file)
index 0000000..0e5b3cb
--- /dev/null
@@ -0,0 +1,1708 @@
+#line 2 "rpld_conf.yy.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ *     if ( condition_holds )
+ *             yyless( 5 );
+ *     else
+ *             do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               *yy_cp = yy_hold_char; \
+               YY_RESTORE_YY_MORE_OFFSET \
+               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yytext_ptr = yy_bp; \
+       yyleng = (int) (yy_cp - yy_bp); \
+       yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 16
+#define YY_END_OF_BUFFER 17
+static yyconst short int yy_accept[50] =
+    {   0,
+        0,    0,    0,    0,   17,   15,    1,    2,   15,   13,
+       15,   12,   12,   13,    8,    9,    5,    6,    5,    1,
+        0,   14,   13,    4,    3,   12,    0,    0,   13,    7,
+        3,   12,    0,   11,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,   10,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    4,    1,    5,    1,    1,    1,    1,    1,    1,
+        1,    6,    1,    1,    7,    8,    9,   10,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   12,    1,    1,
+        1,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        1,    1,    1,    1,    7,    1,   13,   13,   13,   13,
+
+       13,   13,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,   14,
+        7,    7,   15,    1,   16,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[17] =
+    {   0,
+        1,    1,    2,    3,    3,    1,    4,    3,    3,    5,
+        5,    6,    7,    4,    1,    1
+    } ;
+
+static yyconst short int yy_base[66] =
+    {   0,
+        0,    0,   14,   15,   78,  101,   20,  101,   70,    0,
+       17,   17,   58,   25,  101,  101,  101,  101,   60,   38,
+       55,  101,    0,  101,    0,   45,   44,    0,   29,  101,
+        0,   23,    0,    0,    0,   25,    0,    0,   17,    0,
+        0,   13,    0,    0,    7,    0,    0,  101,  101,   42,
+       47,   51,   58,   61,   63,   66,   69,   72,   75,   78,
+       81,   84,   87,   90,   93
+    } ;
+
+static yyconst short int yy_def[66] =
+    {   0,
+       49,    1,   50,   50,   49,   49,   49,   49,   51,   52,
+       49,   49,   12,   49,   49,   49,   49,   49,   49,   49,
+       51,   49,   52,   49,   53,   54,   49,   55,   52,   49,
+       53,   49,   56,   55,   57,   49,   58,   59,   49,   60,
+       61,   49,   62,   63,   49,   64,   65,   49,    0,   49,
+       49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
+       49,   49,   49,   49,   49
+    } ;
+
+static yyconst short int yy_nxt[118] =
+    {   0,
+        6,    7,    8,    7,    9,    6,   10,    6,   11,   12,
+       13,    6,   14,   10,   15,   16,   18,   18,   46,   19,
+       19,   20,   24,   20,   43,   25,   26,   26,   40,   27,
+       28,   23,   32,   32,   27,   27,   37,   29,   23,   20,
+       33,   20,   17,   17,   17,   17,   17,   17,   17,   21,
+       21,   21,   21,   21,   23,   33,   33,   23,   31,   22,
+       31,   31,   31,   31,   31,   32,   32,   34,   30,   34,
+       35,   49,   35,   36,   22,   36,   38,   49,   38,   39,
+       49,   39,   41,   49,   41,   42,   49,   42,   44,   49,
+       44,   45,   49,   45,   47,   49,   47,   48,   49,   48,
+
+        5,   49,   49,   49,   49,   49,   49,   49,   49,   49,
+       49,   49,   49,   49,   49,   49,   49
+    } ;
+
+static yyconst short int yy_chk[118] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    3,    4,   45,    3,
+        4,    7,   11,    7,   42,   11,   12,   12,   39,   12,
+       12,   14,   32,   32,   14,   14,   36,   14,   14,   20,
+       29,   20,   50,   50,   50,   50,   50,   50,   50,   51,
+       51,   51,   51,   51,   52,   27,   26,   52,   53,   21,
+       53,   53,   53,   53,   53,   54,   54,   55,   19,   55,
+       56,   13,   56,   57,    9,   57,   58,    5,   58,   59,
+        0,   59,   60,    0,   60,   61,    0,   61,   62,    0,
+       62,   63,    0,   63,   64,    0,   64,   65,    0,   65,
+
+       49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
+       49,   49,   49,   49,   49,   49,   49
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "rpld_conf.lex"
+#define INITIAL 0
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+/*
+ *  Lexer for RPLD conf files
+ *
+ *  $Log: rpld_conf.lex,v $
+ *  Revision 1.4  2000/07/16 13:18:10  root
+ *  #
+ *
+ *  Revision 1.1  2000/07/16 13:16:33  root
+ *  #
+ *
+ *  Revision 1.3  1999/09/13 11:17:35  root
+ *  \#
+ *
+ *  Revision 1.2  1999/09/13 11:08:34  root
+ *  \#
+ *
+ *  Revision 1.1  1999/09/13 11:04:13  root
+ *  \#
+ *
+ *  Revision 1.10  1999/09/12 19:08:24  chris
+ *  Another attempt at C comments.
+ *
+ *  Revision 1.9  1999/09/12 17:38:45  chris
+ *  Implemented proper MAC reading.
+ *
+ *  Revision 1.8  1999/09/12 03:27:43  chris
+ *  Changes to enable error reporting in yacc grammar.
+ *
+ *  Revision 1.7  1999/09/11 19:30:26  chris
+ *  Fixed hex number support.
+ *
+ *  Revision 1.6  1999/09/11 19:25:06  chris
+ *  No major changes.
+ *
+ *  Revision 1.5  1999/09/11 19:24:23  chris
+ *  Removed support for C-style comments, inserted support for C++ ones. Comment support actually works now
+ *
+ *  Revision 1.4  1999/09/11 19:02:25  chris
+ *  Fixed bug in comment support.
+ *
+ *  Revision 1.3  1999/09/11 19:00:43  chris
+ *  Added support for comments.
+ *
+ *  Revision 1.2  1999/09/11 18:57:31  chris
+ *  Initial revision.
+ *
+ *  
+ */
+#define COMMENT 1
+
+#line 70 "rpld_conf.lex"
+static char rcsid[]="$Id: rpld_conf.lex,v 1.4 2000/07/16 13:18:10 root Exp root $";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rpld_conf.tab.h"
+
+
+// line number
+int lineno = 1;
+
+// function to convert hex digits to a MAC address
+void strtomac(char *s, char *mac);
+
+void strtomac(char *s, char *mac)
+{
+       // mac address *must* be in form 00:11:22:33:44:55
+       int i;
+
+       for (i = 0; i < 6; i++) *(mac + i) = (unsigned char)strtol(s + i * 3, NULL, 16);
+}
+
+
+#line 494 "rpld_conf.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( yy_current_buffer->yy_is_interactive ) \
+               { \
+               int c = '*', n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+                 && ferror( yyin ) ) \
+               YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+YY_DECL
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+
+#line 98 "rpld_conf.lex"
+
+
+#line 648 "rpld_conf.yy.c"
+
+       if ( yy_init )
+               {
+               yy_init = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yy_start )
+                       yy_start = 1;   /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! yy_current_buffer )
+                       yy_current_buffer =
+                               yy_create_buffer( yyin, YY_BUF_SIZE );
+
+               yy_load_buffer_state();
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yy_start;
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       if ( yy_accept[yy_current_state] )
+                               {
+                               yy_last_accepting_state = yy_current_state;
+                               yy_last_accepting_cpos = yy_cp;
+                               }
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 50 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       ++yy_cp;
+                       }
+               while ( yy_base[yy_current_state] != 101 );
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+               if ( yy_act == 0 )
+                       { /* have to back up */
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       yy_act = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+
+do_action:     /* This label is used only to access EOF actions. */
+
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+                       case 0: /* must back up */
+                       /* undo the effects of YY_DO_BEFORE_ACTION */
+                       *yy_cp = yy_hold_char;
+                       yy_cp = yy_last_accepting_cpos;
+                       yy_current_state = yy_last_accepting_state;
+                       goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 100 "rpld_conf.lex"
+;
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 101 "rpld_conf.lex"
+{ lineno++; }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 103 "rpld_conf.lex"
+;
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 105 "rpld_conf.lex"
+BEGIN COMMENT;
+       YY_BREAK
+case 5:
+#line 107 "rpld_conf.lex"
+case 6:
+YY_RULE_SETUP
+#line 107 "rpld_conf.lex"
+;
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 108 "rpld_conf.lex"
+BEGIN INITIAL;
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 110 "rpld_conf.lex"
+{ return BLOCK_START; }
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 112 "rpld_conf.lex"
+{ return BLOCK_END; }
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 114 "rpld_conf.lex"
+{ strtomac(yytext, (yylval.mac_address)); return MACADDR; }
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 116 "rpld_conf.lex"
+{
+                               yylval.number = strtol(yytext + 2, NULL, 16);
+                               return NUMBER;
+                       }
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 121 "rpld_conf.lex"
+{
+                               int i; i = strtol(yytext, NULL, 10);
+                               yylval.number = i; return NUMBER;
+                       }
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 126 "rpld_conf.lex"
+{ yylval.name = strdup(yytext); return NAME; }
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 128 "rpld_conf.lex"
+{ yylval.text = strdup(yytext + 1); *(yylval.text + strlen(yylval.text) - 1) = 0; return TEXT;}
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 130 "rpld_conf.lex"
+{ return yytext[0]; }
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 132 "rpld_conf.lex"
+ECHO;
+       YY_BREAK
+#line 814 "rpld_conf.yy.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+       yyterminate();
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yy_hold_char;
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between yy_current_buffer and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yy_n_chars = yy_current_buffer->yy_n_chars;
+                       yy_current_buffer->yy_input_file = yyin;
+                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state();
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yy_c_buf_p;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer() )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yy_did_buffer_switch_on_eof = 0;
+
+                               if ( yywrap() )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yy_c_buf_p =
+                                       yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yy_c_buf_p =
+                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+       } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+       {
+       register char *dest = yy_current_buffer->yy_ch_buf;
+       register char *source = yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( yy_current_buffer->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+       else
+               {
+               int num_to_read =
+                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = yy_current_buffer;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yy_flex_realloc( (void *) b->yy_ch_buf,
+                                                        b->yy_buf_size + 2 );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = yy_current_buffer->yy_buf_size -
+                                               number_to_move - 1;
+#endif
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+                       yy_n_chars, num_to_read );
+
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       if ( yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart( yyin );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       yy_current_buffer->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       yy_n_chars += number_to_move;
+       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+       return ret_val;
+       }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+
+       yy_current_state = yy_start;
+
+       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               if ( yy_accept[yy_current_state] )
+                       {
+                       yy_last_accepting_state = yy_current_state;
+                       yy_last_accepting_cpos = yy_cp;
+                       }
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 50 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               }
+
+       return yy_current_state;
+       }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+       {
+       register int yy_is_jam;
+       register char *yy_cp = yy_c_buf_p;
+
+       register YY_CHAR yy_c = 1;
+       if ( yy_accept[yy_current_state] )
+               {
+               yy_last_accepting_state = yy_current_state;
+               yy_last_accepting_cpos = yy_cp;
+               }
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 50 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 49);
+
+       return yy_is_jam ? 0 : yy_current_state;
+       }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+       {
+       register char *yy_cp = yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yy_hold_char;
+
+       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yy_n_chars + 2;
+               register char *dest = &yy_current_buffer->yy_ch_buf[
+                                       yy_current_buffer->yy_buf_size + 2];
+               register char *source =
+                               &yy_current_buffer->yy_ch_buf[number_to_move];
+
+               while ( source > yy_current_buffer->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               yy_current_buffer->yy_n_chars =
+                       yy_n_chars = yy_current_buffer->yy_buf_size;
+
+               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+
+       yytext_ptr = yy_bp;
+       yy_hold_char = *yy_cp;
+       yy_c_buf_p = yy_cp;
+       }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+       {
+       int c;
+
+       *yy_c_buf_p = yy_hold_char;
+
+       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = yy_c_buf_p - yytext_ptr;
+                       ++yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer() )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       yyrestart( yyin );
+
+                                       /* fall through */
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap() )
+                                               return EOF;
+
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yy_c_buf_p = yytext_ptr + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
+       *yy_c_buf_p = '\0';     /* preserve yytext */
+       yy_hold_char = *++yy_c_buf_p;
+
+
+       return c;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+       {
+       if ( ! yy_current_buffer )
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+       yy_init_buffer( yy_current_buffer, input_file );
+       yy_load_buffer_state();
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+       {
+       if ( yy_current_buffer == new_buffer )
+               return;
+
+       if ( yy_current_buffer )
+               {
+               /* Flush out information for old buffer. */
+               *yy_c_buf_p = yy_hold_char;
+               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       yy_current_buffer = new_buffer;
+       yy_load_buffer_state();
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yy_did_buffer_switch_on_eof = 1;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+       {
+       yy_n_chars = yy_current_buffer->yy_n_chars;
+       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+       yyin = yy_current_buffer->yy_input_file;
+       yy_hold_char = *yy_c_buf_p;
+       }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+       {
+       YY_BUFFER_STATE b;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer( b, file );
+
+       return b;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+       {
+       if ( ! b )
+               return;
+
+       if ( b == yy_current_buffer )
+               yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yy_flex_free( (void *) b->yy_ch_buf );
+
+       yy_flex_free( (void *) b );
+       }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+       {
+       yy_flush_buffer( b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+       b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+       b->yy_is_interactive = 0;
+#else
+       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+       {
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == yy_current_buffer )
+               yy_load_buffer_state();
+       }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+       {
+       YY_BUFFER_STATE b;
+
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       yy_switch_to_buffer( b );
+
+       return b;
+       }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+       {
+       int len;
+       for ( len = 0; yy_str[len]; ++len )
+               ;
+
+       return yy_scan_bytes( yy_str, len );
+       }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+       {
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = len + 2;
+       buf = (char *) yy_flex_alloc( n );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+       for ( i = 0; i < len; ++i )
+               buf[i] = bytes[i];
+
+       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = yy_scan_buffer( buf, n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+       }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+       {
+       if ( yy_start_stack_ptr >= yy_start_stack_depth )
+               {
+               yy_size_t new_size;
+
+               yy_start_stack_depth += YY_START_STACK_INCR;
+               new_size = yy_start_stack_depth * sizeof( int );
+
+               if ( ! yy_start_stack )
+                       yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+               else
+                       yy_start_stack = (int *) yy_flex_realloc(
+                                       (void *) yy_start_stack, new_size );
+
+               if ( ! yy_start_stack )
+                       YY_FATAL_ERROR(
+                       "out of memory expanding start-condition stack" );
+               }
+
+       yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+       BEGIN(new_state);
+       }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+       {
+       if ( --yy_start_stack_ptr < 0 )
+               YY_FATAL_ERROR( "start-condition stack underflow" );
+
+       BEGIN(yy_start_stack[yy_start_stack_ptr]);
+       }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+       {
+       return yy_start_stack[yy_start_stack_ptr - 1];
+       }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+       {
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+       }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               yytext[yyleng] = yy_hold_char; \
+               yy_c_buf_p = yytext + n; \
+               yy_hold_char = *yy_c_buf_p; \
+               *yy_c_buf_p = '\0'; \
+               yyleng = n; \
+               } \
+       while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+       {
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+       }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+       {
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+       }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+       {
+       return (void *) malloc( size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+       {
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+       {
+       free( ptr );
+       }
+
+#if YY_MAIN
+int main()
+       {
+       yylex();
+       return 0;
+       }
+#endif
+#line 132 "rpld_conf.lex"
+
+
+
+int yywrap()
+{
+       return 1;
+}
+
diff --git a/util.c b/util.c
new file mode 100644 (file)
index 0000000..3d9c4d0
--- /dev/null
+++ b/util.c
@@ -0,0 +1,84 @@
+/*************************************************
+*     rpld - an IBM style RIPL server            *
+*************************************************/
+
+/* Copyright (c) 1999, James McKenzie.
+ *                      All rights reserved
+ * Copyright (c) 1998, Christopher Lightfoot.
+ *                      All rights reserved
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENCE file which can be found at the top level of
+ * the rpld distribution.
+ *
+ * IBM is a trademark of IBM corp.
+ *
+ */
+
+
+static char rcsid[] = "$Id: util.c,v 1.6 2000/07/16 13:18:10 root Exp root $";
+
+/*
+ * $Log: util.c,v $
+ * Revision 1.6  2000/07/16 13:18:10  root
+ * #
+ *
+ * Revision 1.1  2000/07/16 13:16:33  root
+ * #
+ *
+ * Revision 1.5  1999/09/13 11:17:35  root
+ * \#
+ *
+ * Revision 1.4  1999/09/13 11:05:27  root
+ * \#
+ *
+ * Revision 1.3  1999/09/13 11:04:13  root
+ * \#
+ *
+ */
+
+#include "project.h"
+
+
+unsigned char ethtoaret[1024];
+
+unsigned char *
+ethtoa (void *in)
+{
+  unsigned char *p = (unsigned char *) in;
+  int i = ETH_ALEN;
+  int len = 0;
+
+  len += sprintf (ethtoaret + len, "%02x", *(p++));
+
+  while (--i)
+    len += sprintf (ethtoaret + len, ":%02x", *(p++));
+
+  return (ethtoaret);
+}
+
+void
+daemonize (void)
+{
+  int fd;
+
+  switch (fork ())
+    {
+    case 0:
+      break;
+    case -1:
+      openlog ("rpld", LOG_PID, LOG_DAEMON);
+      syslog (LOG_ERR, "fork failed: %m");
+      exit (1);
+    default:
+      exit (0);
+    }
+
+  setpgrp ();
+
+  fd = open ("/dev/null", O_RDWR);
+  dup2 (fd, 0);
+  dup2 (fd, 1);
+  dup2 (fd, 2);
+  close (fd);
+}