summaryrefslogtreecommitdiff
path: root/release/src/router/busybox/networking/udhcp
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/busybox/networking/udhcp')
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/AUTHORS14
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/COPYING339
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/ChangeLog262
-rw-r--r--[-rwxr-xr-x]release/src/router/busybox/networking/udhcp/Config.in126
-rw-r--r--release/src/router/busybox/networking/udhcp/Kbuild25
-rw-r--r--release/src/router/busybox/networking/udhcp/Makefile30
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/Makefile.in61
-rw-r--r--release/src/router/busybox/networking/udhcp/README50
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/README.dumpleases17
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/README.udhcpc141
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/README.udhcpd59
-rwxr-xr-xrelease/src/router/busybox/networking/udhcp/TODO14
-rw-r--r--release/src/router/busybox/networking/udhcp/arpping.c162
-rw-r--r--release/src/router/busybox/networking/udhcp/arpping.h30
-rw-r--r--release/src/router/busybox/networking/udhcp/clientpacket.c280
-rw-r--r--release/src/router/busybox/networking/udhcp/clientpacket.h12
-rw-r--r--release/src/router/busybox/networking/udhcp/clientsocket.c108
-rw-r--r--release/src/router/busybox/networking/udhcp/common.c147
-rw-r--r--release/src/router/busybox/networking/udhcp/common.h132
-rw-r--r--release/src/router/busybox/networking/udhcp/debug.h41
-rw-r--r--release/src/router/busybox/networking/udhcp/dhcpc.c924
-rw-r--r--release/src/router/busybox/networking/udhcp/dhcpc.h65
-rw-r--r--release/src/router/busybox/networking/udhcp/dhcpd.c347
-rw-r--r--release/src/router/busybox/networking/udhcp/dhcpd.h218
-rw-r--r--release/src/router/busybox/networking/udhcp/dhcprelay.c325
-rw-r--r--release/src/router/busybox/networking/udhcp/domain_codec.c205
-rw-r--r--release/src/router/busybox/networking/udhcp/dumpleases.c149
-rw-r--r--release/src/router/busybox/networking/udhcp/files.c568
-rw-r--r--release/src/router/busybox/networking/udhcp/files.h17
-rw-r--r--release/src/router/busybox/networking/udhcp/frontend.c16
-rw-r--r--release/src/router/busybox/networking/udhcp/leases.c210
-rw-r--r--release/src/router/busybox/networking/udhcp/leases.h25
-rw-r--r--release/src/router/busybox/networking/udhcp/leases_file.c1
-rw-r--r--release/src/router/busybox/networking/udhcp/libbb_udhcp.h29
-rw-r--r--release/src/router/busybox/networking/udhcp/options.c363
-rw-r--r--release/src/router/busybox/networking/udhcp/options.h110
-rw-r--r--release/src/router/busybox/networking/udhcp/packet.c269
-rw-r--r--release/src/router/busybox/networking/udhcp/packet.h41
-rw-r--r--release/src/router/busybox/networking/udhcp/pidfile.c69
-rw-r--r--release/src/router/busybox/networking/udhcp/pidfile.h26
-rw-r--r--release/src/router/busybox/networking/udhcp/script.c256
-rw-r--r--release/src/router/busybox/networking/udhcp/script.h6
-rw-r--r--release/src/router/busybox/networking/udhcp/serverpacket.c223
-rw-r--r--release/src/router/busybox/networking/udhcp/serverpacket.h11
-rw-r--r--release/src/router/busybox/networking/udhcp/signalpipe.c82
-rw-r--r--release/src/router/busybox/networking/udhcp/socket.c142
-rw-r--r--release/src/router/busybox/networking/udhcp/socket.h9
-rw-r--r--release/src/router/busybox/networking/udhcp/static_leases.c79
-rw-r--r--release/src/router/busybox/networking/udhcp/version.h6
49 files changed, 3448 insertions, 3393 deletions
diff --git a/release/src/router/busybox/networking/udhcp/AUTHORS b/release/src/router/busybox/networking/udhcp/AUTHORS
deleted file mode 100755
index 3772aedb..00000000
--- a/release/src/router/busybox/networking/udhcp/AUTHORS
+++ /dev/null
@@ -1,14 +0,0 @@
-udhcp server/client package
------------------------
-
-Russ Dill <Russ.Dill@asu.edu>
-Matthew Ramsay <matthewr@moreton.com.au>
-Chris Trew <christ@moreton.com.au>
-
-Other Credits:
---------------
-Moreton Bay (http://www.moretonbay.com/)
-Lineo (http://opensource.lineo.com)
-Vladimir Oleynik <dzo@simtrea.ru>, optimize and more integrate for busybox
-
-
diff --git a/release/src/router/busybox/networking/udhcp/COPYING b/release/src/router/busybox/networking/udhcp/COPYING
deleted file mode 100755
index a43ea212..00000000
--- a/release/src/router/busybox/networking/udhcp/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/release/src/router/busybox/networking/udhcp/ChangeLog b/release/src/router/busybox/networking/udhcp/ChangeLog
deleted file mode 100755
index 9ee97534..00000000
--- a/release/src/router/busybox/networking/udhcp/ChangeLog
+++ /dev/null
@@ -1,262 +0,0 @@
-0.9.10
- Size optimization (over 3k), more busybox integration
- (Vladimir Oleynik <dzo@simtreas.ru>
-
-0.9.9 (pending)
-+ Fixed a little endian problem in mton (Bastian Blank <waldi@debian.org>)
-+ Fixed a arpping alignment problem (Rui He <rhe@3eti.com>)
-+ Added sanity check for max_leases (udhcp bug #1285) (me)
-+ Finally got rid of the trailing space in enviromental vars (me)
-+ added an new enviromental variable: $mask. It contains the number
- of subnet bits for tools like ip route that require it.
- (Bastian Blank <waldi@debian.org>, me)
-
-0.9.8 (021031)
-+ split up README files (me)
-+ use /dev/urandom to seed xid's (instead of time(0)) (me)
-+ fixed renew behavior (me)
-+ udhcp now fits nicely into busybox
- (Glenn McGrath <bug1@optushome.com.au> as well as myself)
-+ updated client manpage (me)
-+ both client and server now use sockets for signal handling,
- hopefully, this will be the last needed change in signal
- handling, I'm fairly certain all the possible races are now
- closed. (me)
-+ The server now restarts the auto_time timer when it receives
- a SIGUSR1 (write out config file). (me)
-+ Improve signal handling (David Poole)
-+ Fix to config file parsing (Matt Kraai)
-+ Fix load lease logic (me)
-+ Fix clear_lease logic (me)
-+ -h is now an alias for -H (udhcp bug #1253)
-+ Shorter timeout on not receiving offers (me)
-+ Improved signal behavior by client (me)
-+ Would never assign end address (Keith Smith <keith@ksmith.com>)
-+ Was improperly reporting yiaddr as siaddr (ben-udhcp@bdlow.net)
- udhcp bug#1256
-+ Fixed reading of client id (David Poole <davep@portsmith.com>)
-+ change sys_errlist[] to strerror() as it aparently doesn't exist
- (Erik Andersen <andersen@codepoet.org>)
-+ fixed get_raw_packet so it returns -2 on non fatal errors
- (Ted Lemon <Ted.Lemon@nominum.com>)
-+ Improved (hopefully) NAKing behavior (me)
-+ Added -b option (Jouni Malinen)
-+ Compute checksums correctly on big endian hosts
- (Jouni Malinen <jkmaline@cc.hut.fi>)
-
-0.9.7 (020526)
-+ Use add_lease in read_leases, sanitizes leases more, and clears out exprired
- ones if there is no more room (me)
-+ Moved udhcpd.leases to /var/lib/misc/udhcpd.leases (Debian bug #147747)
-+ Change (obsolete) AF_INET in arping.c to PF_PACKET (Debian bug #127049)
-+ Added script hook for DHCPNAK (nak), as well as providing the message option
- (me)
-+ Generate the paramaters request list by seeing what options in options.c are
- ored with OPTION_REQ in options.c
-+ Fix dhcp renew forgetfullness on client (bug #1230)
-+ Fix dhcp release bug on client (bug #1231)
-+ Set option request list for DHCP renew (bug #1233)
-+ Set BOOTREQUEST/REPLY properly
-+ Change client-identifier field to popularly expected behavior (me)
-+ Only reopen port on errors (me)
-+ Change fork/close/setsid structures to daemon() (me)
-+ Allow user to specify udhcpd config file at run time (Steven, me)
-+ Write pidfile after changing it (Steven CTR Carr <Steven.CTR.Carr@tc.faa.gov>)
-+ Added env var docs to udhcpc man page (Matt)
-+ Standardized lowercase udhcp in documentation (me)
-+ Accept packets without a UDP checksum (me)
-+ Accept packets with extra garbage (me)
-+ Better error handling in files.c (me)
-+ Combined read_interface function to reduce COMBINED_BINARY size (me)
-+ Drop calc_length(), some servers choke on smaller packets (me)
-+ Try to clean some fat out (me)
-
-0.9.6 (011001)
-+ Added bootp paramaters to server (me)
-+ Added bootp paramaters to client (me)
-+ Added vendor id to client (me)
-+ Better pidfile handling in client and server (me)
-+ Added man pages (Matt Kraai <kraai@alumni.carnegiemellon.edu>)
-
-0.9.5 (010914)
-+ Fixed $HOME and $PATH env passing (me)
-+ Fixed client to only listen for raw packets on correct interface (me)
-+ added --quit,-q option to quit after a lease is obtained (me)
-+ Fixed 100% CPU utilization by client when interface is down (me)
-
-0.9.4 (010827)
-+ Force broadcast to broken clients that request unicast (ie, MSFT 98)
-+ Make install rules (Adam J. Richter <adam@yggdrasil.com>)
-+ One scripts, instead of many (Adam)
-+ Removed script paramater info files (env vars only) (Adam)
-+ Controlling of forking behavior in client (Adam)
-+ General script.c/dhcpc.c cleanups (Adam)
-
-0.9.3 (010820)
-+ Increased debugging verbosity (me)
-+ Cut trailing whitespace when reading config file (me)
-+ added hostname option to client (me)
-+ fixed a strncpy bug in script.c (me)
-+ fixed a leaky socket in dhcpc.c (me)
-+ fixed a leaky socket in dhcpd.c (me)
-
-0.9.2 (010810)
-+ Added raw sockets to client (me)
-+ alignment fixes (Mark Huang)
-+ compiler warning fixes (Mark Huang)
-+ client now sends parameter list (Mark Huang/me)
-+ added ipttl option
-+ Does now not request broadcast packets
-
-0.9.1 (010806)
-+ Added udhcpc client
-+ reorganized functions/files
-+ listening socket now only binds to one interface
-
-0.9.0 (010720) Major rewrite, current changes, goals:
-+ should not segfault on bogus packets.
-+ Options can be read from sname and file fields.
-+ supports all DHCP messages (release, decline, inform).
-+ IP block is now specified by a range of IP's.
-+ Leases file now contains lease time (relative, or absolute).
-+ Just about any DHCP option is now supported.
-+ DNS entries are no longer read from resolv.conf
-+ Lease file can be written periodically when the process receives a SIGUSR1
-+ arpping should be supported on all arches.
-+ support for DHCP relays.
-+ DHCP messages can be unicast if the client requests it.
-+ many, many, many other things.
-
-0.8.29 (000323)
-+ stable(?) release
-
-
-0.8.28 (000323)
-+ removed alarm as it was causing server to go down
-+ removed debugging
-+ break down dhcpd.c into manageable files
-
-
-0.8.27 (000221)
-+ OFFER also sends gateway/subnet (for picky dhcp clients)
-+ multiple DNS now handled from resolv.conf if available
-+ multiple WINS (from dhcpd.conf)
-
-0.8.25 (000120)
-+ now compiles *and* runs on a generic linux system
- tested with a windows 98 client and the sample config
- files in the samples directory.
-
-0.8.24 (000117)
-+ makeiplist tool has basic functionality in place
-+ new sample config files
-+ route add -host 255.255.255.255 dev eth0 added for generic linux
-
-0.8.23 (000117)
-+ NETtel specific fix for ignoring dhcp requests on 2nd interface
-
-0.8.22 (000113)
-+ minor changes to compile under a generic linux system
-+ minor config file location changes for a generic linux system
-+ makeiplist fixes.. still incomplete.. but etting closer
-
-0.8.21 (000113)
-+ now sends the correct server ip instead of hardcoded value
-+ minor debugging fixes for critical messages
-
-0.8.20 (000106)
-+ cut out dhcp server checking.. this was causing dialout ppp
- sessions with idle time set to never time out.
-+ also removed the 10 second pause before launching.. as this
- was originally to stop it replying to a dhcp client
- on a NETtel which was really a bad way to do it in the
- first place :-)
-
-0.8.19 (000104)
-+ fixes for route add -host on a machine that needs to run both
- a DHCP client and server (dual eth box)
-
-0.8.18 (991220)
-
-+ Race conditions fixed by disabling alarm whilst the server is busy
-+ Fixed continous clearing of the offered array so that it is only cleared
- when it is dirty - (could change the position of when dirty is set)
-
-0.8.17 (991212)
-
-- has problems clearing out the offered array
-
-0.8.16 (991203)
-+ Non blocking error is changes to informational as it is not really
- an error
-
-0.8.15 (991129)
-+ Servs the dns field 3 times (Nettel only) so that windows servers
- dont time out whilst nettel is booting
-
-0.8.14 (991126)
-+ added owner check for the offered array so clean out time may be
- increased
-+ added new func to print out chadder/MAC
-
-0.8.13 (991125)
-+ added win95 support (w95 changed xid halfway through conversation)
-+ had to change the offered array to use hardware addresses instead of xid
-+ fixed re offered bug
-+ added more debugging
-
-0.8.12 (991111)
-+ debugging was real bad.. cleaned up a bit.. needs overhaul
-
-
-0.8.11 (991110)
-+ fixed up offeredAddr array to actually be used now!! offeredAddr is
- used to see if another simultaneous connecting client was offered
- an address that we are about to offer another client (multiple
- client bug)
-+ removed re_offered variable as it breaks multiple client support
-+ added lease time to ACK -- doesn't work if in OFFER
-+ decreased internal array clear delay to 60 seconds
-+ minor findAddr bug (returning -1 instead of 0)
-+ if clients xid already in offeredAddr offer the same addr and don't add a
- new addr to offered (caused by a client issuing multiple DISCOVERs)
-
-0.8.10 (991105)
-+ \n bug in arpping
-+ minor debugging changes (removed printfs etc)
-+ started browseiplist (not finished)
-
-0.8.9 (19991105)
-+ fixed options array size bug (options were cut off)
-
-0.8.8 (19991105)
-+ ignores requests from dhcpcd on the same machine
-
-0.8.7 (19991104)
-+ don't die if we can't bind to search for existing DHCP server
-+ slightly more verbose syslogging
-
-0.8.6 (19991103)
-+ added makeiplist (not finished -- core dumps)
-+ minor debug changes
-
-0.8.5 (19991029)
-+ exits if another DHCP server is already on the network
-+ added Linux Makefile
-
-0.8.4 (19991026)
-+ minor bug fix in findaddr preventing an addr being found
-
-0.8.3 (19991025)
-+ fixed up debugging
-+ minor hwaddr issues
-
-0.8.2 (19991022)
-+ free leases (new arpping code from dhcpcd)
-+ fixed bug where crashes if no leases/iplist file
-+ syslogging and debugging switch
-+ serve DNS from resolv.conf
-+ fixed bug where new lease added if same mac offered
-+ now checks the ip is free b4 offering
-+ now supports wins server
-
diff --git a/release/src/router/busybox/networking/udhcp/Config.in b/release/src/router/busybox/networking/udhcp/Config.in
index a3223de9..d4b76e18 100755..100644
--- a/release/src/router/busybox/networking/udhcp/Config.in
+++ b/release/src/router/busybox/networking/udhcp/Config.in
@@ -3,60 +3,120 @@
# see scripts/kbuild/config-language.txt.
#
-menu "udhcp Server/Client"
-
-config CONFIG_UDHCPD
- bool "udhcp Server (udhcpd)"
+config APP_UDHCPD
+ bool "udhcp server (udhcpd)"
default n
help
- uDHCPd is a DHCP server geared primarily toward embedded systems,
+ udhcpd is a DHCP server geared primarily toward embedded systems,
while striving to be fully functional and RFC compliant.
- See http://udhcp.busybox.net for further details.
-
-config CONFIG_UDHCPC
- bool "udhcp Client (udhcpc)"
+config APP_DHCPRELAY
+ bool "dhcprelay"
default n
+ depends on APP_UDHCPD
help
- uDHCPc is a DHCP client geared primarily toward embedded systems,
- while striving to be fully functional and RFC compliant.
-
- The udhcp client negotiates a lease with the DHCP server and
- notifies a set of scripts when a leases is obtained or lost.
-
- See http://udhcp.busybox.net for further details.
+ dhcprelay listens for dhcp requests on one or more interfaces
+ and forwards these requests to a different interface or dhcp
+ server.
-config CONFIG_DUMPLEASES
+config APP_DUMPLEASES
bool "Lease display utility (dumpleases)"
default n
- depends on CONFIG_UDHCPD
+ depends on APP_UDHCPD
help
dumpleases displays the leases written out by the udhcpd server.
Lease times are stored in the file by time remaining in lease, or
by the absolute time that it expires in seconds from epoch.
- See http://udhcp.busybox.net for further details.
+config FEATURE_UDHCPD_WRITE_LEASES_EARLY
+ bool "Rewrite the lease file at every new acknowledge"
+ default n
+ depends on APP_UDHCPD
+ help
+ If selected, udhcpd will write a new file with leases every
+ time a new lease has been accepted, thus eliminating the need
+ to send SIGUSR1 for the initial writing or updating. Any timed
+ rewriting remains undisturbed
+
+config DHCPD_LEASES_FILE
+ string "Absolute path to lease file"
+ default "/var/lib/misc/udhcpd.leases"
+ depends on APP_UDHCPD
+ help
+ udhcpd stores addresses in a lease file. This is the absolute path
+ of the file. Normally it is safe to leave it untouched.
-config CONFIG_FEATURE_UDHCP_SYSLOG
- bool " Log udhcp messages to syslog (instead of stdout)"
+config APP_UDHCPC
+ bool "udhcp client (udhcpc)"
default n
- depends on CONFIG_UDHCPD || CONFIG_UDHCPC
help
- If selected, udhcpd will log all its messages to syslog, otherwise,
- it will attempt to log them to stdout.
+ udhcpc is a DHCP client geared primarily toward embedded systems,
+ while striving to be fully functional and RFC compliant.
- See http://udhcp.busybox.net for further details.
+ The udhcp client negotiates a lease with the DHCP server and
+ runs a script when a lease is obtained or lost.
-config CONFIG_FEATURE_UDHCP_DEBUG
- bool " Compile udhcp with noisy debugging messages"
+config FEATURE_UDHCPC_ARPING
+ bool "Verify that the offered address is free, using ARP ping"
+ default y
+ depends on APP_UDHCPC
+ help
+ If selected, udhcpc will send ARP probes and make sure
+ the offered address is really not in use by anyone. The client
+ will DHCPDECLINE the offer if the address is in use,
+ and restart the discover process.
+
+config FEATURE_UDHCP_PORT
+ bool "Enable '-P port' option for udhcpd and udhcpc"
+ default n
+ depends on APP_UDHCPD || APP_UDHCPC
+ help
+ At the cost of ~300 bytes, enables -P port option.
+ This feature is typically not needed.
+
+config UDHCP_DEBUG
+ bool "Compile udhcp with noisy debugging messages"
default n
- depends on CONFIG_UDHCPD || CONFIG_UDHCPC
+ depends on APP_UDHCPD || APP_UDHCPC
help
- If selected, udhcpd will output extra debugging output. If using
- this option, compile uDHCP with "-g", and do not fork the daemon to
- the background.
+ If selected, udhcpd will output extra debugging output.
- See http://udhcp.busybox.net for further details.
+config FEATURE_UDHCP_RFC3397
+ bool "Support for RFC3397 domain search (experimental)"
+ default n
+ depends on APP_UDHCPD || APP_UDHCPC
+ help
+ If selected, both client and server will support passing of domain
+ search lists via option 119, specified in RFC3397.
+
+config UDHCPC_DEFAULT_SCRIPT
+ string "Absolute path to config script"
+ default "/usr/share/udhcpc/default.script"
+ depends on APP_UDHCPC
+ help
+ This script is called after udhcpc receives an answer. See
+ examples/udhcp for a working example. Normally it is safe
+ to leave this untouched.
+
+config UDHCPC_SLACK_FOR_BUGGY_SERVERS
+ int "DHCP options slack buffer size"
+ default 80
+ range 0 924
+ depends on APP_UDHCPD || APP_UDHCPC
+ help
+ Some buggy DHCP servers send DHCP offer packets with option
+ field larger than we expect (which might also be considered a
+ buffer overflow attempt). These packets are normally discarded.
+ If circumstances beyond your control force you to support such
+ servers, this may help. The upper limit (924) makes dhcpc accept
+ even 1500 byte packets (maximum-sized ethernet packets).
-endmenu
+ This option does not make dhcp[cd] emit non-standard
+ sized packets.
+ Known buggy DHCP servers:
+ 3Com OfficeConnect Remote 812 ADSL Router:
+ seems to confuse maximum allowed UDP packet size with
+ maximum size of entire IP packet, and sends packets which are
+ 28 bytes too large.
+ Seednet (ISP) VDSL: sends packets 2 bytes too large.
diff --git a/release/src/router/busybox/networking/udhcp/Kbuild b/release/src/router/busybox/networking/udhcp/Kbuild
new file mode 100644
index 00000000..e938076f
--- /dev/null
+++ b/release/src/router/busybox/networking/udhcp/Kbuild
@@ -0,0 +1,25 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+#
+
+lib-y:=
+lib-$(CONFIG_APP_UDHCPC) += common.o options.o packet.o \
+ signalpipe.o socket.o
+lib-$(CONFIG_APP_UDHCPD) += common.o options.o packet.o \
+ signalpipe.o socket.o
+
+lib-$(CONFIG_APP_UDHCPC) += dhcpc.o clientpacket.o clientsocket.o \
+ script.o
+
+UDHCPC_NEEDS_ARPING-$(CONFIG_FEATURE_UDHCPC_ARPING) = y
+lib-$(UDHCPC_NEEDS_ARPING-y) += arpping.o
+
+lib-$(CONFIG_APP_UDHCPD) += dhcpd.o arpping.o files.o leases.o \
+ serverpacket.o static_leases.o
+
+lib-$(CONFIG_APP_DUMPLEASES) += dumpleases.o
+lib-$(CONFIG_APP_DHCPRELAY) += dhcprelay.o
+lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o
diff --git a/release/src/router/busybox/networking/udhcp/Makefile b/release/src/router/busybox/networking/udhcp/Makefile
deleted file mode 100644
index ee34d48f..00000000
--- a/release/src/router/busybox/networking/udhcp/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-TOPDIR:= ../../
-UDHCP_DIR:=./
-include $(TOPDIR).config
-include $(TOPDIR)Rules.mak
-include Makefile.in
-all: $(libraries-y)
--include $(TOPDIR).depend
-
-clean:
- rm -f *.o *.a $(AR_TARGET)
-
diff --git a/release/src/router/busybox/networking/udhcp/Makefile.in b/release/src/router/busybox/networking/udhcp/Makefile.in
deleted file mode 100755
index 502aa1c3..00000000
--- a/release/src/router/busybox/networking/udhcp/Makefile.in
+++ /dev/null
@@ -1,61 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-UDHCP_AR:=udhcp.a
-ifndef $(UDHCP_DIR)
-UDHCP_DIR:=$(TOPDIR)networking/udhcp/
-endif
-
-#ok, so I forgot how to do an or, but this is a quick and dirty hack
-ifeq ($(CONFIG_UDHCPC), y)
-CONFIG_UDHCP_SHARED=y
-else
-ifeq ($(CONFIG_UDHCPD), y)
-CONFIG_UDHCP_SHARED=y
-else
-CONFIG_UDHCP_SHARED=n
-endif
-endif
-
-ifeq ($(CONFIG_UDHCPD), y)
-CONFIG_UDHCP_LEASES_FILE=y
-else
-ifeq ($(CONFIG_UDHCPD), y)
-CONFIG_UDHCP_LEASES_FILE=y
-else
-CONFIG_UDHCP_LEASES_FILE=n
-endif
-endif
-
-UDHCP-y:=
-UDHCP-$(CONFIG_UDHCP_SHARED) += options.c socket.c packet.c common.c
-UDHCP-$(CONFIG_UDHCPC) += dhcpc.c clientpacket.c script.c
-UDHCP-$(CONFIG_UDHCPD) += dhcpd.c arpping.c files.c leases.c serverpacket.c
-UDHCP-$(CONFIG_DUMPLEASES) += dumpleases.c
-UDHCP-$(CONFIG_UDHCP_LEASES_FILE) += leases_file.c
-UDHCP_OBJS=$(patsubst %.c,$(UDHCP_DIR)%.o, $(UDHCP-y))
-
-libraries-y+=$(UDHCP_DIR)$(UDHCP_AR)
-
-$(UDHCP_DIR)$(UDHCP_AR): $(UDHCP_OBJS)
- $(AR) -ro $@ $(UDHCP_OBJS)
-
-$(UDHCP_OBJS): %.o : %.c
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
-
diff --git a/release/src/router/busybox/networking/udhcp/README b/release/src/router/busybox/networking/udhcp/README
deleted file mode 100644
index 5f4bb78a..00000000
--- a/release/src/router/busybox/networking/udhcp/README
+++ /dev/null
@@ -1,50 +0,0 @@
-udhcp server/client package readme
--------------------------
-
-The udhcp server/client package is primarily geared towards embedded
-systems. It does however, strive to be fully functional, and RFC
-compliant.
-
-
-compile time options
--------------------
-
-The Makefile contains three of the compile time options:
-
- DEBUG: If DEBUG is defined, udhcpd will output extra debugging
- output, compile with -g, and not fork to the background when run.
- SYSLOG: If SYSLOG is defined, udhcpd will log all its messages
- syslog, otherwise, it will attempt to log them to stdout.
-
- COMBINED_BINARY: If COMBINED_BINARY is define, one binary, udhcpd,
- is created. If called as udhcpd, the dhcp server will be started.
- If called as udhcpc, the dhcp client will be started.
-
-dhcpd.h contains the other two compile time options:
-
- LEASE_TIME: The default lease time if not specified in the config
- file.
-
- DHCPD_CONFIG_FILE: The defualt config file to use.
-
-options.c contains a set of dhcp options for the client:
-
- name[10]: The name of the option as it will appear in scripts
-
- flags: The type of option, as well as if it will be requested
- by the client (OPTION_REQ)
-
- code: The DHCP code for this option
-
-
-busybox drop-in
---------------
-udhcp is now a drop-in component for busybox (http://busybox.net).
-To update busybox to the latest revision, simply do a:
-
-cp *.[ch] README AUTHORS COPYING ChangeLog TODO \
- <busybox_source>/networking/udhcp
-
-The only two files udhcp does not provide are config.in and
-Makefile.in, so these may need to be updated from time to time.
-
diff --git a/release/src/router/busybox/networking/udhcp/README.dumpleases b/release/src/router/busybox/networking/udhcp/README.dumpleases
deleted file mode 100755
index 6367710c..00000000
--- a/release/src/router/busybox/networking/udhcp/README.dumpleases
+++ /dev/null
@@ -1,17 +0,0 @@
-udhcp lease dump (dumpleases)
-----------------------------
-
-dumpleases displays the leases written out by the udhcpd server. Lease
-times are stored in the file by time remaining in lease (for systems
-without clock that works when there is no power), or by the absolute
-time that it expires in seconds from epoch. dumpleases accepts the
-following command line options:
-
--a, --absolute Interpret lease times as expiration time.
--r, --remaining Interpret lease times as remaining time.
--f, --file=FILE Read lease information from FILE.
--h, --help Display help.
-
-Note that if udhcpd has not written a leases file recently, the output
-of may not be up to date.
-
diff --git a/release/src/router/busybox/networking/udhcp/README.udhcpc b/release/src/router/busybox/networking/udhcp/README.udhcpc
deleted file mode 100755
index 8aee9814..00000000
--- a/release/src/router/busybox/networking/udhcp/README.udhcpc
+++ /dev/null
@@ -1,141 +0,0 @@
-udhcp client (udhcpc)
---------------------
-
-The udhcp client negotiates a lease with the DHCP server and notifies
-a set of scripts when a leases is obtained or lost.
-
-
-command line options
--------------------
-
-The command line options for the udhcp client are:
-
--c, --clientid=CLIENTID Client identifier
--H, --hostname=HOSTNAME Client hostname
--h, Alias for -H
--f, --foreground Do not fork after getting lease
--b, --background Fork to background if lease cannot be
- immediately negotiated.
--i, --interface=INTERFACE Interface to use (default: eth0)
--n, --now Exit with failure if lease cannot be
- immediately negotiated.
--p, --pidfile=file Store process ID of daemon in file
--q, --quit Quit after obtaining lease
--r, --request=IP IP address to request (default: none)
--s, --script=file Run file at dhcp events (default:
- /usr/share/udhcpc/default.script)
--v, --version Display version
-
-
-If the requested IP address cannot be obtained, the client accepts the
-address that the server offers.
-
-
-udhcp client scripts
--------------------
-
-When an event occurs, udhcpc calls the action script. udhcpc never does
-any configuration of the network interface itself, but instead relies on
-a set of scripts. The script by default is
-/usr/share/udhcpc/default.script but this can be changed via the command
-line arguments. The three possible arguments to the script are:
-
- deconfig: This argument is used when udhcpc starts, and
- when a leases is lost. The script must put the interface in an
- up, but deconfigured state, ie: ifconfig $interface 0.0.0.0.
-
- bound: This argument is used when udhcpc moves from an
- unbound, to a bound state. All of the paramaters are set in
- enviromental variables, The script should configure the interface,
- and set any other relavent parameters (default gateway, dns server,
- etc).
-
- renew: This argument is used when a DHCP lease is renewed. All of
- the paramaters are set in enviromental variables. This argument is
- used when the interface is already configured, so the IP address,
- will not change, however, the other DHCP paramaters, such as the
- default gateway, subnet mask, and dns server may change.
-
- nak: This argument is used with udhcpc receives a NAK message.
- The script with the deconfig argument will be called directly
- afterwards, so no changes to the network interface are neccessary.
- This hook is provided for purely informational purposes (the
- message option may contain a reason for the NAK).
-
-The paramaters for enviromental variables are as follows:
-
- $HOME - The set $HOME env or "/"
- $PATH - the set $PATH env or "/bin:/usr/bin:/sbin:/usr/sbin"
- $1 - What action the script should perform
- interface - The interface this was obtained on
- ip - The obtained IP
- mask - The number of bits in the netmask (ie: 24)
- siaddr - The bootp next server option
- sname - The bootp server name option
- boot_file - The bootp boot file option
- subnet - The assigend subnet mask
- timezone - Offset in seconds from UTC
- router - A list of routers
- timesvr - A list of time servers
- namesvr - A list of IEN 116 name servers
- dns - A list of DNS server
- logsvr - A list of MIT-LCS UDP log servers
- cookiesvr - A list of RFC 865 cookie servers
- lprsvr - A list of LPR servers
- hostname - The assigned hostname
- bootsize - The length in 512 octect blocks of the bootfile
- domain - The domain name of the network
- swapsvr - The IP address of the client's swap server
- rootpath - The path name of the client's root disk
- ipttl - The TTL to use for this network
- mtu - The MTU to use for this network
- broadcast - The broadcast address for this network
- ntpsrv - A list of NTP servers
- wins - A list of WINS servers
- lease - The lease time, in seconds
- dhcptype - DHCP message type (safely ignored)
- serverid - The IP of the server
- message - Reason for a DHCPNAK
- tftp - The TFTP server name
- bootfile - The bootfile name
-
-additional options are easily added in options.c.
-
-
-note on udhcpc's random seed
----------------------------
-
-udhcpc will seed its random number generator (used for generating xid's)
-by reading /dev/urandom. If you have a lot of embedded systems on the same
-network, with no entropy, you can either seed /dev/urandom by a method of
-your own, or doing the following on startup:
-
-ifconfig eth0 > /dev/urandom
-
-in order to seed /dev/urandom with some data (mac address) unique to your
-system. If reading /dev/urandom fails, udhcpc will fall back to its old
-behavior of seeding with time(0).
-
-
-signals accepted by udhcpc
--------------------------
-
-udhcpc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state,
-and SIGUSR2 will force a release of the current lease, and cause udhcpc to
-go into an inactive state (until it is killed, or receives a SIGUSR1). You do
-not need to sleep between sending signals, as signals received are processed
-sequencially in the order they are received.
-
-
-compile time options
--------------------
-
-options.c contains a set of dhcp options for the client:
-
- name[10]: The name of the option as it will appear in scripts
-
- flags: The type of option, as well as if it will be requested
- by the client (OPTION_REQ)
-
- code: The DHCP code for this option
-
diff --git a/release/src/router/busybox/networking/udhcp/README.udhcpd b/release/src/router/busybox/networking/udhcp/README.udhcpd
deleted file mode 100755
index bc6137de..00000000
--- a/release/src/router/busybox/networking/udhcp/README.udhcpd
+++ /dev/null
@@ -1,59 +0,0 @@
-udhcp server (udhcpd)
---------------------
-
-The only command line argument to udhcpd is an optional specifed
-config file. If no config file is specified, udhcpd uses the default
-config file, /etc/udhcpd.conf. Ex:
-
-udhcpd /etc/udhcpd.eth1.conf
-
-The udhcp server employs a number of simple config files:
-
-udhcpd.leases
-------------
-
-The udhcpd.leases behavior is designed for an embedded system. The
-file is written either every auto_time seconds, or when a SIGUSR1
-is received (the auto_time timer restarts if a SIGUSR1 is received).
-If you send a SIGTERM to udhcpd directly after a SIGUSR1, udhcpd will
-finish writing the leases file and wait for the aftermentioned script
-to be executed and finish before quiting, so you do not need to sleep
-between sending signals. When the file is written, a script can be
-optionally called to commit the file to flash. Lease times are stored
-in the file by time remaining in lease (for systems without clock
-that works when there is no power), or by the absolute time that it
-expires in seconds from epoch. In the remaining format, expired leases
-are stored as zero. The file is of the format:
-
-16 byte MAC
-4 byte ip address
-u32 expire time
-16 byte MAC
-4 byte ip address
-u32 expire time
-.
-etc.
-
-example: hexdump udhcpd.leases
-
-0000000 1000 c95a 27d9 0000 0000 0000 0000 0000
-0000010 a8c0 150a 0d00 2d29 5000 23fc 8566 0000
-0000020 0000 0000 0000 0000 a8c0 140a 0d00 4e29
-0000030
-
-
-udhcpd.conf
-----------
-
-The format is fairly simple, there is a sample file with all the
-available options and comments describing them in samples/udhcpd.conf
-
-compile time options
--------------------
-
-dhcpd.h contains the other two compile time options:
-
- LEASE_TIME: The default lease time if not specified in the config
- file.
-
- DHCPD_CONFIG_FILE: The defualt config file to use.
diff --git a/release/src/router/busybox/networking/udhcp/TODO b/release/src/router/busybox/networking/udhcp/TODO
deleted file mode 100755
index f88694a8..00000000
--- a/release/src/router/busybox/networking/udhcp/TODO
+++ /dev/null
@@ -1,14 +0,0 @@
-TODO
-----
-+ Integrade README.*'s with manpages
-+ using time(0) breaks if the system clock changes, find a portable solution
-+ make failure of reading functions revert to previous value, not the default
-+ sanity code for option[OPT_LEN]
-+ fix aliasing (ie: eth0:0)
-+ better standard linux distro support
-+ make sure packet generation works on a wide varitey of arches
-+ Interoperability testing
-+ Hooks within the DHCP server
-+ Additional bootp support in client/server
-+ Make serverid option in server configurable
-+ Possibly add failure message to DHCP NAK
diff --git a/release/src/router/busybox/networking/udhcp/arpping.c b/release/src/router/busybox/networking/udhcp/arpping.c
index e20395a9..b10bff65 100644
--- a/release/src/router/busybox/networking/udhcp/arpping.c
+++ b/release/src/router/busybox/networking/udhcp/arpping.c
@@ -1,102 +1,118 @@
+/* vi: set sw=4 ts=4: */
/*
* arpping.c
*
* Mostly stolen from: dhcpcd - DHCP client daemon
* by Yoichi Hariguchi <yoichi@fore.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <sys/time.h>
-#include <time.h>
-#include <sys/socket.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include "dhcpd.h"
-#include "arpping.h"
#include "common.h"
+#include "dhcpd.h"
-/* args: yiaddr - what IP to ping
- * ip - our ip
- * mac - our arp address
- * interface - interface to use
- * retn: 1 addr free
- * 0 addr used
- * -1 error
- */
-
-/* FIXME: match response against chaddr */
-int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *mac, char *interface)
-{
- int timeout = 2;
- int optval = 1;
- int s; /* socket */
- int rv = 1; /* return value */
- struct sockaddr addr; /* for interface name */
- struct arpMsg arp;
- fd_set fdset;
- struct timeval tm;
- time_t prevTime;
+struct arpMsg {
+ /* Ethernet header */
+ uint8_t h_dest[6]; /* 00 destination ether addr */
+ uint8_t h_source[6]; /* 06 source ether addr */
+ uint16_t h_proto; /* 0c packet type ID field */
+
+ /* ARP packet */
+ uint16_t htype; /* 0e hardware type (must be ARPHRD_ETHER) */
+ uint16_t ptype; /* 10 protocol type (must be ETH_P_IP) */
+ uint8_t hlen; /* 12 hardware address length (must be 6) */
+ uint8_t plen; /* 13 protocol address length (must be 4) */
+ uint16_t operation; /* 14 ARP opcode */
+ uint8_t sHaddr[6]; /* 16 sender's hardware address */
+ uint8_t sInaddr[4]; /* 1c sender's IP address */
+ uint8_t tHaddr[6]; /* 20 target's hardware address */
+ uint8_t tInaddr[4]; /* 26 target's IP address */
+ uint8_t pad[18]; /* 2a pad for min. ethernet payload (60 bytes) */
+} PACKED;
+enum {
+ ARP_MSG_SIZE = 0x2a
+};
+
+
+/* Returns 1 if no reply received */
+
+int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface)
+{
+ int timeout_ms;
+ struct pollfd pfd[1];
+#define s (pfd[0].fd) /* socket */
+ int rv = 1; /* "no reply received" yet */
+ struct sockaddr addr; /* for interface name */
+ struct arpMsg arp;
- if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) {
- LOG(LOG_ERR, bb_msg_can_not_create_raw_socket);
+ s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
+ if (s == -1) {
+ bb_perror_msg(bb_msg_can_not_create_raw_socket);
return -1;
}
-
- if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
- LOG(LOG_ERR, "Could not setsocketopt on raw socket");
- close(s);
- return -1;
+
+ if (setsockopt_broadcast(s) == -1) {
+ bb_perror_msg("cannot enable bcast on raw socket");
+ goto ret;
}
/* send arp request */
memset(&arp, 0, sizeof(arp));
- memcpy(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6); /* MAC DA */
- memcpy(arp.ethhdr.h_source, mac, 6); /* MAC SA */
- arp.ethhdr.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
- arp.htype = htons(ARPHRD_ETHER); /* hardware type */
- arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */
- arp.hlen = 6; /* hardware address length */
- arp.plen = 4; /* protocol address length */
- arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
- memcpy(arp.sInaddr, &ip, sizeof(ip)); /* source IP address */
- memcpy(arp.sHaddr, mac, 6); /* source hardware address */
- memcpy(arp.tInaddr, &yiaddr, sizeof(yiaddr)); /* target IP address */
-
+ memset(arp.h_dest, 0xff, 6); /* MAC DA */
+ memcpy(arp.h_source, from_mac, 6); /* MAC SA */
+ arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
+ arp.htype = htons(ARPHRD_ETHER); /* hardware type */
+ arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */
+ arp.hlen = 6; /* hardware address length */
+ arp.plen = 4; /* protocol address length */
+ arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
+ memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */
+ memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */
+ /* tHaddr is zero-fiiled */ /* target hardware address */
+ memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */
+
memset(&addr, 0, sizeof(addr));
- strcpy(addr.sa_data, interface);
- if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
- rv = 0;
-
- /* wait arp reply, and check it */
- tm.tv_usec = 0;
- time(&prevTime);
- while (timeout > 0) {
- FD_ZERO(&fdset);
- FD_SET(s, &fdset);
- tm.tv_sec = timeout;
- if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) {
- DEBUG(LOG_ERR, "Error on ARPING request: %m");
- if (errno != EINTR) rv = 0;
- } else if (FD_ISSET(s, &fdset)) {
- if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0;
- if (arp.operation == htons(ARPOP_REPLY) &&
- bcmp(arp.tHaddr, mac, 6) == 0 &&
- *((u_int *) arp.sInaddr) == yiaddr) {
- DEBUG(LOG_INFO, "Valid arp reply receved for this address");
+ safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data));
+ if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) {
+ // TODO: error message? caller didn't expect us to fail,
+ // just returning 1 "no reply received" misleads it.
+ goto ret;
+ }
+
+ /* wait for arp reply, and check it */
+ timeout_ms = 2000;
+ do {
+ int r;
+ unsigned prevTime = monotonic_us();
+
+ pfd[0].events = POLLIN;
+ r = safe_poll(pfd, 1, timeout_ms);
+ if (r < 0)
+ break;
+ if (r) {
+ r = read(s, &arp, sizeof(arp));
+ if (r < 0)
+ break;
+ if (r >= ARP_MSG_SIZE
+ && arp.operation == htons(ARPOP_REPLY)
+ /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */
+ /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */
+ && *((uint32_t *) arp.sInaddr) == test_ip
+ ) {
rv = 0;
break;
}
}
- timeout -= time(NULL) - prevTime;
- time(&prevTime);
- }
+ timeout_ms -= ((unsigned)monotonic_us() - prevTime) / 1000;
+ } while (timeout_ms > 0);
+
+ ret:
close(s);
- DEBUG(LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V");
+ DEBUG("%srp reply received for this address", rv ? "No a" : "A");
return rv;
}
diff --git a/release/src/router/busybox/networking/udhcp/arpping.h b/release/src/router/busybox/networking/udhcp/arpping.h
deleted file mode 100644
index 92b828db..00000000
--- a/release/src/router/busybox/networking/udhcp/arpping.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * arpping .h
- */
-
-#ifndef ARPPING_H
-#define ARPPING_H
-
-#include <netinet/if_ether.h>
-#include <net/if_arp.h>
-#include <net/if.h>
-#include <netinet/in.h>
-
-struct arpMsg {
- struct ethhdr ethhdr; /* Ethernet header */
- u_short htype; /* hardware type (must be ARPHRD_ETHER) */
- u_short ptype; /* protocol type (must be ETH_P_IP) */
- u_char hlen; /* hardware address length (must be 6) */
- u_char plen; /* protocol address length (must be 4) */
- u_short operation; /* ARP opcode */
- u_char sHaddr[6]; /* sender's hardware address */
- u_char sInaddr[4]; /* sender's IP address */
- u_char tHaddr[6]; /* target's hardware address */
- u_char tInaddr[4]; /* target's IP address */
- u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */
-};
-
-/* function prototypes */
-int arpping(u_int32_t yiaddr, u_int32_t ip, unsigned char *arp, char *interface);
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/clientpacket.c b/release/src/router/busybox/networking/udhcp/clientpacket.c
index 7debac2e..3f9522ff 100644
--- a/release/src/router/busybox/networking/udhcp/clientpacket.c
+++ b/release/src/router/busybox/networking/udhcp/clientpacket.c
@@ -1,28 +1,15 @@
+/* vi: set sw=4 ts=4: */
/* clientpacket.c
*
* Packet generation and dispatching functions for the DHCP client.
*
* Russ Dill <Russ.Dill@asu.edu> July 2001
*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-
-#include <string.h>
-#include <sys/socket.h>
+
#include <features.h>
-#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
+#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
@@ -30,36 +17,21 @@
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#endif
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-
+#include "common.h"
#include "dhcpd.h"
-#include "options.h"
#include "dhcpc.h"
-#include "common.h"
+#include "options.h"
/* Create a random xid */
-unsigned long random_xid(void)
+uint32_t FAST_FUNC random_xid(void)
{
- static int initialized;
- if (!initialized) {
- int fd;
- unsigned long seed;
+ static smallint initialized;
- fd = open("/dev/urandom", 0);
- if (fd < 0 || read(fd, &seed, sizeof(seed)) < 0) {
- LOG(LOG_WARNING, "Could not load seed from /dev/urandom: %m");
- seed = time(0);
- }
- if (fd >= 0) close(fd);
- srand(seed);
- initialized++;
+ if (!initialized) {
+ srand(monotonic_us());
+ initialized = 1;
}
return rand();
}
@@ -68,39 +40,90 @@ unsigned long random_xid(void)
/* initialize a packet with the proper defaults */
static void init_packet(struct dhcpMessage *packet, char type)
{
- struct vendor {
- char vendor, length;
- char str[sizeof("udhcp "VERSION)];
- } vendor_id = { DHCP_VENDOR, sizeof("udhcp "VERSION) - 1, "udhcp "VERSION};
-
- init_header(packet, type);
+ udhcp_init_header(packet, type);
memcpy(packet->chaddr, client_config.arp, 6);
- add_option_string(packet->options, client_config.clientid);
- if (client_config.hostname) add_option_string(packet->options, client_config.hostname);
- add_option_string(packet->options, (unsigned char *) &vendor_id);
+ if (client_config.clientid)
+ add_option_string(packet->options, client_config.clientid);
+ if (client_config.hostname)
+ add_option_string(packet->options, client_config.hostname);
+ if (client_config.fqdn)
+ add_option_string(packet->options, client_config.fqdn);
+ if ((type != DHCPDECLINE) && (type != DHCPRELEASE))
+ add_option_string(packet->options, client_config.vendorclass);
}
-/* Add a paramater request list for stubborn DHCP servers. Pull the data
+/* Add a parameter request list for stubborn DHCP servers. Pull the data
* from the struct in options.c. Don't do bounds checking here because it
* goes towards the head of the packet. */
-static void add_requests(struct dhcpMessage *packet)
+static void add_param_req_option(struct dhcpMessage *packet)
{
+ uint8_t c;
int end = end_option(packet->options);
int i, len = 0;
- packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
- for (i = 0; options[i].code; i++)
- if (options[i].flags & OPTION_REQ)
- packet->options[end + OPT_DATA + len++] = options[i].code;
- packet->options[end + OPT_LEN] = len;
- packet->options[end + OPT_DATA + len] = DHCP_END;
+ for (i = 0; (c = dhcp_options[i].code) != 0; i++) {
+ if (((dhcp_options[i].flags & OPTION_REQ)
+ && !client_config.no_default_options)
+ || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
+ ) {
+ packet->options[end + OPT_DATA + len] = c;
+ len++;
+ }
+ }
+ if (len) {
+ packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
+ packet->options[end + OPT_LEN] = len;
+ packet->options[end + OPT_DATA + len] = DHCP_END;
+ }
+}
+
+/* RFC 2131
+ * 4.4.4 Use of broadcast and unicast
+ *
+ * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
+ * messages, unless the client knows the address of a DHCP server.
+ * The client unicasts DHCPRELEASE messages to the server. Because
+ * the client is declining the use of the IP address supplied by the server,
+ * the client broadcasts DHCPDECLINE messages.
+ *
+ * When the DHCP client knows the address of a DHCP server, in either
+ * INIT or REBOOTING state, the client may use that address
+ * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
+ * The client may also use unicast to send DHCPINFORM messages
+ * to a known DHCP server. If the client receives no response to DHCP
+ * messages sent to the IP address of a known DHCP server, the DHCP
+ * client reverts to using the IP broadcast address.
+ */
+static int raw_bcast_from_client_config_ifindex(struct dhcpMessage *packet)
+{
+ return udhcp_send_raw_packet(packet,
+ /*src*/ INADDR_ANY, CLIENT_PORT,
+ /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
+ client_config.ifindex);
}
+#if ENABLE_FEATURE_UDHCPC_ARPING
+/* Broadcast a DHCP decline message */
+int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested)
+{
+ struct dhcpMessage packet;
+
+ init_packet(&packet, DHCPDECLINE);
+ packet.xid = xid;
+ add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
+ add_simple_option(packet.options, DHCP_SERVER_ID, server);
+
+ bb_info_msg("Sending decline...");
+
+ return raw_bcast_from_client_config_ifindex(&packet);
+}
+#endif
+
/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
-int send_discover(unsigned long xid, unsigned long requested)
+int FAST_FUNC send_discover(uint32_t xid, uint32_t requested)
{
struct dhcpMessage packet;
@@ -109,15 +132,22 @@ int send_discover(unsigned long xid, unsigned long requested)
if (requested)
add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
- add_requests(&packet);
- LOG(LOG_DEBUG, "Sending discover...");
- return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
- SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
+ /* Explicitly saying that we want RFC-compliant packets helps
+ * some buggy DHCP servers to NOT send bigger packets */
+ add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576));
+
+ add_param_req_option(&packet);
+
+ bb_info_msg("Sending discover...");
+ return raw_bcast_from_client_config_ifindex(&packet);
}
/* Broadcasts a DHCP request message */
-int send_selecting(unsigned long xid, unsigned long server, unsigned long requested)
+/* RFC 2131 3.1 paragraph 3:
+ * "The client _broadcasts_ a DHCPREQUEST message..."
+ */
+int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested)
{
struct dhcpMessage packet;
struct in_addr addr;
@@ -127,121 +157,115 @@ int send_selecting(unsigned long xid, unsigned long server, unsigned long reques
add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
add_simple_option(packet.options, DHCP_SERVER_ID, server);
-
- add_requests(&packet);
+ add_param_req_option(&packet);
+
addr.s_addr = requested;
- LOG(LOG_DEBUG, "Sending select for %s...", inet_ntoa(addr));
- return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
- SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
+ bb_info_msg("Sending select for %s...", inet_ntoa(addr));
+ return raw_bcast_from_client_config_ifindex(&packet);
}
/* Unicasts or broadcasts a DHCP renew message */
-int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr)
+int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
{
struct dhcpMessage packet;
- int ret = 0;
init_packet(&packet, DHCPREQUEST);
packet.xid = xid;
packet.ciaddr = ciaddr;
- add_requests(&packet);
- LOG(LOG_DEBUG, "Sending renew...");
- if (server)
- ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
- else ret = raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
- SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
- return ret;
-}
+ add_param_req_option(&packet);
+ bb_info_msg("Sending renew...");
+ if (server)
+ return udhcp_send_kernel_packet(&packet,
+ ciaddr, CLIENT_PORT,
+ server, SERVER_PORT);
+
+ return raw_bcast_from_client_config_ifindex(&packet);
+}
/* Unicasts a DHCP release message */
-int send_release(unsigned long server, unsigned long ciaddr)
+int FAST_FUNC send_release(uint32_t server, uint32_t ciaddr)
{
struct dhcpMessage packet;
init_packet(&packet, DHCPRELEASE);
packet.xid = random_xid();
packet.ciaddr = ciaddr;
-
- add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr);
+
add_simple_option(packet.options, DHCP_SERVER_ID, server);
- LOG(LOG_DEBUG, "Sending release...");
- return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
+ bb_info_msg("Sending release...");
+ return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
}
-/* return -1 on errors that are fatal for the socket, -2 for those that aren't */
-int get_raw_packet(struct dhcpMessage *payload, int fd)
+/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
+int FAST_FUNC udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd)
{
int bytes;
struct udp_dhcp_packet packet;
- u_int32_t source, dest;
- u_int16_t check;
+ uint16_t check;
- memset(&packet, 0, sizeof(struct udp_dhcp_packet));
- bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet));
+ memset(&packet, 0, sizeof(packet));
+ bytes = safe_read(fd, &packet, sizeof(packet));
if (bytes < 0) {
- DEBUG(LOG_INFO, "couldn't read on raw listening socket -- ignoring");
- usleep(500000); /* possible down interface, looping condition */
- return -1;
+ DEBUG("Cannot read on raw listening socket - ignoring");
+ /* NB: possible down interface, etc. Caller should pause. */
+ return bytes; /* returns -1 */
}
-
- if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) {
- DEBUG(LOG_INFO, "message too short, ignoring");
+
+ if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
+ DEBUG("Packet is too short, ignoring");
return -2;
}
-
+
if (bytes < ntohs(packet.ip.tot_len)) {
- DEBUG(LOG_INFO, "Truncated packet");
+ /* packet is bigger than sizeof(packet), we did partial read */
+ DEBUG("Oversized packet, ignoring");
return -2;
}
-
+
/* ignore any extra garbage bytes */
bytes = ntohs(packet.ip.tot_len);
-
- /* Make sure its the right packet for us, and that it passes sanity checks */
- if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION ||
- packet.ip.ihl != sizeof(packet.ip) >> 2 || packet.udp.dest != htons(CLIENT_PORT) ||
- bytes > (int) sizeof(struct udp_dhcp_packet) ||
- ntohs(packet.udp.len) != (short) (bytes - sizeof(packet.ip))) {
- DEBUG(LOG_INFO, "unrelated/bogus packet");
- return -2;
+
+ /* make sure its the right packet for us, and that it passes sanity checks */
+ if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
+ || packet.ip.ihl != (sizeof(packet.ip) >> 2)
+ || packet.udp.dest != htons(CLIENT_PORT)
+ /* || bytes > (int) sizeof(packet) - can't happen */
+ || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
+ ) {
+ DEBUG("Unrelated/bogus packet");
+ return -2;
}
- /* check IP checksum */
+ /* verify IP checksum */
check = packet.ip.check;
packet.ip.check = 0;
- if (check != checksum(&(packet.ip), sizeof(packet.ip))) {
- DEBUG(LOG_INFO, "bad IP header checksum, ignoring");
- return -1;
+ if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
+ DEBUG("Bad IP header checksum, ignoring");
+ return -2;
}
-
- /* verify the UDP checksum by replacing the header with a psuedo header */
- source = packet.ip.saddr;
- dest = packet.ip.daddr;
+
+ /* verify UDP checksum. IP header has to be modified for this */
+ memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
+ /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
+ packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
check = packet.udp.check;
packet.udp.check = 0;
- memset(&packet.ip, 0, sizeof(packet.ip));
-
- packet.ip.protocol = IPPROTO_UDP;
- packet.ip.saddr = source;
- packet.ip.daddr = dest;
- packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */
- if (check && check != checksum(&packet, bytes)) {
- DEBUG(LOG_ERR, "packet with bad UDP checksum received, ignoring");
+ if (check && check != udhcp_checksum(&packet, bytes)) {
+ bb_error_msg("packet with bad UDP checksum received, ignoring");
return -2;
}
-
- memcpy(payload, &(packet.data), bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
-
- if (ntohl(payload->cookie) != DHCP_MAGIC) {
- LOG(LOG_ERR, "received bogus message (bad magic) -- ignoring");
+
+ memcpy(payload, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
+
+ if (payload->cookie != htonl(DHCP_MAGIC)) {
+ bb_error_msg("received bogus message (bad magic), ignoring");
return -2;
}
- DEBUG(LOG_INFO, "oooooh!!! got some!");
+ DEBUG("Got valid DHCP packet");
return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
-
}
diff --git a/release/src/router/busybox/networking/udhcp/clientpacket.h b/release/src/router/busybox/networking/udhcp/clientpacket.h
deleted file mode 100644
index 2a6facbc..00000000
--- a/release/src/router/busybox/networking/udhcp/clientpacket.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _CLIENTPACKET_H
-#define _CLIENTPACKET_H
-
-unsigned long random_xid(void);
-int send_discover(unsigned long xid, unsigned long requested);
-int send_selecting(unsigned long xid, unsigned long server, unsigned long requested);
-int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr);
-int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr);
-int send_release(unsigned long server, unsigned long ciaddr);
-int get_raw_packet(struct dhcpMessage *payload, int fd);
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/clientsocket.c b/release/src/router/busybox/networking/udhcp/clientsocket.c
new file mode 100644
index 00000000..1dcc1057
--- /dev/null
+++ b/release/src/router/busybox/networking/udhcp/clientsocket.c
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * clientsocket.c -- DHCP client socket creation
+ *
+ * udhcp client
+ *
+ * Russ Dill <Russ.Dill@asu.edu> July 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <features.h>
+#include <asm/types.h>
+#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#else
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+#endif
+#include <linux/filter.h>
+
+#include "common.h"
+#include "dhcpd.h"
+#include "dhcpc.h"
+
+int FAST_FUNC udhcp_raw_socket(int ifindex)
+{
+ int fd;
+ struct sockaddr_ll sock;
+
+ /*
+ * Comment:
+ *
+ * I've selected not to see LL header, so BPF doesn't see it, too.
+ * The filter may also pass non-IP and non-ARP packets, but we do
+ * a more complete check when receiving the message in userspace.
+ *
+ * and filter shamelessly stolen from:
+ *
+ * http://www.flamewarmaster.de/software/dhcpclient/
+ *
+ * There are a few other interesting ideas on that page (look under
+ * "Motivation"). Use of netlink events is most interesting. Think
+ * of various network servers listening for events and reconfiguring.
+ * That would obsolete sending HUP signals and/or make use of restarts.
+ *
+ * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
+ * License: GPL v2.
+ *
+ * TODO: make conditional?
+ */
+#define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68)
+ static const struct sock_filter filter_instr[] = {
+ /* check for udp */
+ BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0), /* L5, L1, is UDP? */
+ /* ugly check for arp on ethernet-like and IPv4 */
+ BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4), /* L3, L4 */
+ /* skip IP header */
+ BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */
+ /* check udp source and destination ports */
+ BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
+ /* returns */
+ BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ), /* L3: pass */
+ BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */
+ };
+ static const struct sock_fprog filter_prog = {
+ .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
+ /* casting const away: */
+ .filter = (struct sock_filter *) filter_instr,
+ };
+
+ DEBUG("opening raw socket on ifindex %d", ifindex);
+
+ fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ DEBUG("got raw socket fd %d", fd);
+
+ if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
+ /* Use only if standard ports are in use */
+ /* Ignoring error (kernel may lack support for this) */
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
+ sizeof(filter_prog)) >= 0)
+ DEBUG("attached filter to raw socket fd %d", fd);
+ }
+
+ sock.sll_family = AF_PACKET;
+ sock.sll_protocol = htons(ETH_P_IP);
+ sock.sll_ifindex = ifindex;
+ xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
+ DEBUG("bound to raw socket fd %d", fd);
+
+ return fd;
+}
diff --git a/release/src/router/busybox/networking/udhcp/common.c b/release/src/router/busybox/networking/udhcp/common.c
index c01cd576..a47bbaff 100644
--- a/release/src/router/busybox/networking/udhcp/common.c
+++ b/release/src/router/busybox/networking/udhcp/common.c
@@ -1,150 +1,11 @@
+/* vi: set sw=4 ts=4: */
/* common.c
*
- * Functions to assist in the writing and removing of pidfiles.
- *
- * Russ Dill <Russ.Dill@asu.edu> Soptember 2001
- * Rewrited by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
- *
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/socket.h>
-
#include "common.h"
-
-static int daemonized;
-
-#ifdef CONFIG_FEATURE_UDHCP_SYSLOG
-
-void udhcp_logging(int level, const char *fmt, ...)
-{
- int e = errno;
- va_list p;
- va_list p2;
-
- va_start(p, fmt);
- __va_copy(p2, p);
- if(!daemonized) {
- vprintf(fmt, p);
- putchar('\n');
- errno = e;
- }
- vsyslog(level, fmt, p2);
- va_end(p);
-}
-
-void start_log(const char *client_server)
-{
- openlog(bb_applet_name, LOG_PID | LOG_CONS, LOG_LOCAL0);
- udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, VERSION);
-}
-
-#else
-
-static char *syslog_level_msg[] = {
- [LOG_EMERG] = "EMERGENCY!",
- [LOG_ALERT] = "ALERT!",
- [LOG_CRIT] = "critical!",
- [LOG_WARNING] = "warning",
- [LOG_ERR] = "error",
- [LOG_INFO] = "info",
- [LOG_DEBUG] = "debug"
+const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
-
-void udhcp_logging(int level, const char *fmt, ...)
-{
- int e = errno;
- va_list p;
-
- va_start(p, fmt);
- if(!daemonized) {
- printf("%s, ", syslog_level_msg[level]);
- errno = e;
- vprintf(fmt, p);
- putchar('\n');
- }
- va_end(p);
-}
-
-void start_log(const char *client_server)
-{
- udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, VERSION);
-}
-#endif
-
-static const char *saved_pidfile;
-
-static void exit_fun(void)
-{
- if (saved_pidfile) unlink(saved_pidfile);
-}
-
-void background(const char *pidfile)
-{
- int pid_fd = -1;
-
- if (pidfile) {
- pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644);
- if (pid_fd < 0) {
- LOG(LOG_ERR, "Unable to open pidfile %s: %m", pidfile);
- } else {
- lockf(pid_fd, F_LOCK, 0);
- if(!saved_pidfile)
- atexit(exit_fun); /* set atexit one only */
- saved_pidfile = pidfile; /* but may be rewrite */
- }
- }
- while (pid_fd >= 0 && pid_fd < 3) pid_fd = dup(pid_fd); /* don't let daemon close it */
- if (daemon(0, 0) == -1) {
- perror("fork");
- exit(1);
- }
- daemonized++;
- if (pid_fd >= 0) {
- FILE *out;
-
- if ((out = fdopen(pid_fd, "w")) != NULL) {
- fprintf(out, "%d\n", getpid());
- fclose(out);
- }
- lockf(pid_fd, F_UNLCK, 0);
- close(pid_fd);
- }
-}
-
-/* Signal handler */
-int udhcp_signal_pipe[2];
-static void signal_handler(int sig)
-{
- if (send(udhcp_signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
- LOG(LOG_ERR, "Could not send signal: %m");
- }
-}
-
-void udhcp_set_signal_pipe(int sig_add)
-{
- socketpair(AF_UNIX, SOCK_STREAM, 0, udhcp_signal_pipe);
- signal(SIGUSR1, signal_handler);
- signal(SIGTERM, signal_handler);
- if(sig_add)
- signal(sig_add, signal_handler);
-}
diff --git a/release/src/router/busybox/networking/udhcp/common.h b/release/src/router/busybox/networking/udhcp/common.h
index 768f551b..0cea7aff 100644
--- a/release/src/router/busybox/networking/udhcp/common.h
+++ b/release/src/router/busybox/networking/udhcp/common.h
@@ -1,52 +1,106 @@
+/* vi: set sw=4 ts=4: */
/* common.h
*
- * Russ Dill <Russ.Dill@asu.edu> Soptember 2001
- * Rewrited by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
+ * Russ Dill <Russ.Dill@asu.edu> September 2001
+ * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
+#ifndef UDHCP_COMMON_H
+#define UDHCP_COMMON_H 1
+
+#include "libbb.h"
+#include <netinet/udp.h>
+#include <netinet/ip.h>
+
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
+
+#define DEFAULT_SCRIPT CONFIG_UDHCPC_DEFAULT_SCRIPT
+
+extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
-#include "version.h"
-#include "busybox.h"
-
-#ifndef CONFIG_FEATURE_UDHCP_SYSLOG
-enum syslog_levels {
- LOG_EMERG = 0,
- LOG_ALERT,
- LOG_CRIT,
- LOG_WARNING,
- LOG_ERR,
- LOG_INFO,
- LOG_DEBUG
+/*** packet.h ***/
+
+#define DHCP_OPTIONS_BUFSIZE 308
+
+struct dhcpMessage {
+ uint8_t op; /* 1 = BOOTREQUEST, 2 = BOOTREPLY */
+ uint8_t htype; /* hardware address type. 1 = 10mb ethernet */
+ uint8_t hlen; /* hardware address length */
+ uint8_t hops; /* used by relay agents only */
+ uint32_t xid; /* unique id */
+ uint16_t secs; /* elapsed since client began acquisition/renewal */
+ uint16_t flags; /* only one flag so far: */
+#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
+ uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
+ uint32_t yiaddr; /* 'your' (client) IP address */
+ uint32_t siaddr; /* IP address of next server to use in bootstrap,
+ * returned in DHCPOFFER, DHCPACK by server */
+ uint32_t giaddr; /* relay agent IP address */
+ uint8_t chaddr[16];/* link-layer client hardware address (MAC) */
+ uint8_t sname[64]; /* server host name (ASCIZ) */
+ uint8_t file[128]; /* boot file name (ASCIZ) */
+ uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */
+ uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
+} PACKED;
+
+struct udp_dhcp_packet {
+ struct iphdr ip;
+ struct udphdr udp;
+ struct dhcpMessage data;
+} PACKED;
+
+/* Let's see whether compiler understood us right */
+struct BUG_bad_sizeof_struct_udp_dhcp_packet {
+ char BUG_bad_sizeof_struct_udp_dhcp_packet
+ [(sizeof(struct udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1];
};
-#else
-#include <syslog.h>
-#endif
-void start_log(const char *client_server);
-void background(const char *pidfile);
-void udhcp_logging(int level, const char *fmt, ...);
+uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC;
+
+void udhcp_init_header(struct dhcpMessage *packet, char type) FAST_FUNC;
+
+/*int udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd); - in dhcpc.h */
+int udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd) FAST_FUNC;
+
+int udhcp_send_raw_packet(struct dhcpMessage *payload,
+ uint32_t source_ip, int source_port,
+ uint32_t dest_ip, int dest_port, const uint8_t *dest_arp,
+ int ifindex) FAST_FUNC;
+
+int udhcp_send_kernel_packet(struct dhcpMessage *payload,
+ uint32_t source_ip, int source_port,
+ uint32_t dest_ip, int dest_port) FAST_FUNC;
+
+extern int minpkt; // zzz
-extern int udhcp_signal_pipe[2];
-void udhcp_set_signal_pipe(int sig_add);
+/**/
+void udhcp_run_script(struct dhcpMessage *packet, const char *name) FAST_FUNC;
-#define LOG(level, str, args...) udhcp_logging(level, str, ## args)
+// Still need to clean these up...
-#ifdef CONFIG_FEATURE_UDHCP_DEBUG
-# define DEBUG(level, str, args...) udhcp_logging(level, str, ## args)
+/* from options.h */
+#define get_option udhcp_get_option
+#define end_option udhcp_end_option
+#define add_option_string udhcp_add_option_string
+#define add_simple_option udhcp_add_simple_option
+
+void udhcp_sp_setup(void) FAST_FUNC;
+int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC;
+int udhcp_sp_read(const fd_set *rfds) FAST_FUNC;
+int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) FAST_FUNC;
+int udhcp_raw_socket(int ifindex) FAST_FUNC;
+int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC;
+/* Returns 1 if no reply received */
+int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) FAST_FUNC;
+
+#if ENABLE_UDHCP_DEBUG
+# define DEBUG(str, args...) bb_info_msg("### " str, ## args)
#else
-# define DEBUG(level, str, args...) do {;} while(0)
+# define DEBUG(str, args...) do {;} while (0)
+#endif
+
+POP_SAVED_FUNCTION_VISIBILITY
+
#endif
diff --git a/release/src/router/busybox/networking/udhcp/debug.h b/release/src/router/busybox/networking/udhcp/debug.h
deleted file mode 100644
index a1e19741..00000000
--- a/release/src/router/busybox/networking/udhcp/debug.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _DEBUG_H
-#define _DEBUG_H
-
-#include "libbb_udhcp.h"
-
-#include <stdio.h>
-#ifdef SYSLOG
-#include <syslog.h>
-#endif
-
-
-#ifdef SYSLOG
-# define LOG(level, str, args...) do { printf(str, ## args); \
- printf("\n"); \
- syslog(level, str, ## args); } while(0)
-# define OPEN_LOG(name) openlog(name, 0, 0)
-#define CLOSE_LOG() closelog()
-#else
-# define LOG_EMERG "EMERGENCY!"
-# define LOG_ALERT "ALERT!"
-# define LOG_CRIT "critical!"
-# define LOG_WARNING "warning"
-# define LOG_ERR "error"
-# define LOG_INFO "info"
-# define LOG_DEBUG "debug"
-# define LOG(level, str, args...) do { printf("%s, ", level); \
- printf(str, ## args); \
- printf("\n"); } while(0)
-# define OPEN_LOG(name) do {;} while(0)
-#define CLOSE_LOG() do {;} while(0)
-#endif
-
-#ifdef DEBUG
-# undef DEBUG
-# define DEBUG(level, str, args...) LOG(level, str, ## args)
-# define DEBUGGING
-#else
-# define DEBUG(level, str, args...) do {;} while(0)
-#endif
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/dhcpc.c b/release/src/router/busybox/networking/udhcp/dhcpc.c
index d18cb423..37a26a46 100644
--- a/release/src/router/busybox/networking/udhcp/dhcpc.c
+++ b/release/src/router/busybox/networking/udhcp/dhcpc.c
@@ -1,492 +1,666 @@
+/* vi: set sw=4 ts=4: */
/* dhcpc.c
*
* udhcp DHCP client
*
* Russ Dill <Russ.Dill@asu.edu> July 2001
*
- * 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.
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
-
-#include <sys/time.h>
-#include <sys/file.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <signal.h>
-#include <time.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <errno.h>
+#include <syslog.h>
+
+/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
+#define WANT_PIDFILE 1
+#include "common.h"
#include "dhcpd.h"
#include "dhcpc.h"
#include "options.h"
-#include "clientpacket.h"
-#include "script.h"
-#include "socket.h"
-#include "common.h"
-static int state;
-static unsigned long requested_ip; /* = 0 */
-static unsigned long server_addr;
-static unsigned long timeout;
-static int packet_num; /* = 0 */
-static int fd = -1;
+
+static int sockfd = -1;
#define LISTEN_NONE 0
#define LISTEN_KERNEL 1
#define LISTEN_RAW 2
-static int listen_mode;
+static smallint listen_mode;
-#ifdef CONFIG_INSTALL_NO_USR
-#define DEFAULT_SCRIPT "/share/udhcpc/default.script"
-#else
-#define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script"
-#endif
+/* initial state: (re)start DHCP negotiation */
+#define INIT_SELECTING 0
+/* discover was sent, DHCPOFFER reply received */
+#define REQUESTING 1
+/* select/renew was sent, DHCPACK reply received */
+#define BOUND 2
+/* half of lease passed, want renew it by sending unicast renew requests */
+#define RENEWING 3
+/* renew requests were not answered, lease is almost over, send broadcast renew */
+#define REBINDING 4
+/* manually requested renew (SIGUSR1) */
+#define RENEW_REQUESTED 5
+/* release, possibly manually requested (SIGUSR2) */
+#define RELEASED 6
+static smallint state;
+
+/* struct client_config_t client_config is in bb_common_bufsiz1 */
-struct client_config_t client_config = {
- /* Default options. */
- abort_if_no_lease: 0,
- foreground: 0,
- quit_after_lease: 0,
- background_if_no_lease: 0,
- interface: "eth0",
- pidfile: NULL,
- script: DEFAULT_SCRIPT,
- clientid: NULL,
- hostname: NULL,
- ifindex: 0,
- arp: "\0\0\0\0\0\0", /* appease gcc-3.0 */
-};
/* just a little helper */
-static void change_mode(int new_mode)
+static void change_listen_mode(int new_mode)
{
- DEBUG(LOG_INFO, "entering %s listen mode",
- new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
- if (fd >= 0) close(fd);
- fd = -1;
+ DEBUG("Entering listen mode: %s",
+ new_mode != LISTEN_NONE
+ ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
+ : "none"
+ );
+
listen_mode = new_mode;
+ if (sockfd >= 0) {
+ close(sockfd);
+ sockfd = -1;
+ }
+ if (new_mode == LISTEN_KERNEL)
+ sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
+ else if (new_mode != LISTEN_NONE)
+ sockfd = udhcp_raw_socket(client_config.ifindex);
+ /* else LISTEN_NONE: sockfd stay closed */
}
/* perform a renew */
static void perform_renew(void)
{
- LOG(LOG_INFO, "Performing a DHCP renew");
+ bb_info_msg("Performing a DHCP renew");
switch (state) {
case BOUND:
- change_mode(LISTEN_KERNEL);
+ change_listen_mode(LISTEN_RAW); // zzz
case RENEWING:
case REBINDING:
- state = RENEW_REQUESTED;
- break;
+// state = RENEW_REQUESTED; // zzz
+// break;
case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
- run_script(NULL, "deconfig");
+ udhcp_run_script(NULL, "deconfig");
case REQUESTING:
case RELEASED:
- change_mode(LISTEN_RAW);
+ change_listen_mode(LISTEN_RAW);
state = INIT_SELECTING;
break;
case INIT_SELECTING:
break;
}
-
- /* start things over */
- packet_num = 0;
-
- /* Kill any timeouts because the user wants this to hurry along */
- timeout = 0;
}
/* perform a release */
-static void perform_release(void)
+static void perform_release(uint32_t requested_ip, uint32_t server_addr)
{
- char buffer[16];
+ char buffer[sizeof("255.255.255.255")];
struct in_addr temp_addr;
/* send release packet */
if (state == BOUND || state == RENEWING || state == REBINDING) {
temp_addr.s_addr = server_addr;
- sprintf(buffer, "%s", inet_ntoa(temp_addr));
+ strcpy(buffer, inet_ntoa(temp_addr));
temp_addr.s_addr = requested_ip;
- LOG(LOG_INFO, "Unicasting a release of %s to %s",
+ bb_info_msg("Unicasting a release of %s to %s",
inet_ntoa(temp_addr), buffer);
send_release(server_addr, requested_ip); /* unicast */
- run_script(NULL, "deconfig");
+ udhcp_run_script(NULL, "deconfig");
}
- LOG(LOG_INFO, "Entering released state");
+ bb_info_msg("Entering released state");
- change_mode(LISTEN_NONE);
+ change_listen_mode(LISTEN_NONE);
state = RELEASED;
- timeout = 0x7fffffff;
}
+#if BB_MMU
static void client_background(void)
{
- background(client_config.pidfile);
- client_config.foreground = 1; /* Do not fork again. */
- client_config.background_if_no_lease = 0;
+ bb_daemonize(0);
+ logmode &= ~LOGMODE_STDIO;
+ /* rewrite pidfile, as our pid is different now */
+ write_pidfile(client_config.pidfile);
}
+#endif
-int udhcpc_main(int argc, char *argv[])
+static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
{
- unsigned char *temp, *message;
- unsigned long t1 = 0, t2 = 0, xid = 0;
- unsigned long start = 0, lease;
- fd_set rfds;
+ uint8_t *storage;
+ int len = strlen(str);
+ if (len > 255) len = 255;
+ storage = xzalloc(len + extra + OPT_DATA);
+ storage[OPT_CODE] = code;
+ storage[OPT_LEN] = len + extra;
+ memcpy(storage + extra + OPT_DATA, str, len);
+ return storage;
+}
+
+
+int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int udhcpc_main(int argc UNUSED_PARAM, char **argv)
+{
+ uint8_t *temp, *message;
+ char *str_c, *str_V, *str_h, *str_F, *str_r;
+ USE_FEATURE_UDHCP_PORT(char *str_P;)
+ llist_t *list_O = NULL;
+ int tryagain_timeout = 20;
+ int discover_timeout = 3;
+ int discover_retries = 5;
+ uint32_t server_addr = server_addr; /* for compiler */
+ uint32_t requested_ip = 0;
+ uint32_t xid = 0;
+ uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */
+ int packet_num;
+ int timeout; /* must be signed */
+ unsigned already_waited_sec;
+ unsigned opt;
+ int max_fd;
int retval;
struct timeval tv;
- int c, len;
struct dhcpMessage packet;
- struct in_addr temp_addr;
- time_t now;
- int max_fd;
- int sig;
-
- static const struct option arg_options[] = {
- {"clientid", required_argument, 0, 'c'},
- {"foreground", no_argument, 0, 'f'},
- {"background", no_argument, 0, 'b'},
- {"hostname", required_argument, 0, 'H'},
- {"hostname", required_argument, 0, 'h'},
- {"interface", required_argument, 0, 'i'},
- {"now", no_argument, 0, 'n'},
- {"pidfile", required_argument, 0, 'p'},
- {"quit", no_argument, 0, 'q'},
- {"request", required_argument, 0, 'r'},
- {"script", required_argument, 0, 's'},
- {"version", no_argument, 0, 'v'},
- {0, 0, 0, 0}
+ fd_set rfds;
+
+#if ENABLE_GETOPT_LONG
+ static const char udhcpc_longopts[] ALIGN1 =
+ "clientid\0" Required_argument "c"
+ "clientid-none\0" No_argument "C"
+ "vendorclass\0" Required_argument "V"
+ "hostname\0" Required_argument "H"
+ "fqdn\0" Required_argument "F"
+ "interface\0" Required_argument "i"
+ "now\0" No_argument "n"
+ "pidfile\0" Required_argument "p"
+ "quit\0" No_argument "q"
+ "release\0" No_argument "R"
+ "request\0" Required_argument "r"
+ "script\0" Required_argument "s"
+ "timeout\0" Required_argument "T"
+ "version\0" No_argument "v"
+ "retries\0" Required_argument "t"
+ "tryagain\0" Required_argument "A"
+ "syslog\0" No_argument "S"
+ "request-option\0" Required_argument "O"
+ "no-default-options\0" No_argument "o"
+ "foreground\0" No_argument "f"
+ "background\0" No_argument "b"
+ USE_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a")
+ USE_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
+ ;
+#endif
+ enum {
+ OPT_c = 1 << 0,
+ OPT_C = 1 << 1,
+ OPT_V = 1 << 2,
+ OPT_H = 1 << 3,
+ OPT_h = 1 << 4,
+ OPT_F = 1 << 5,
+ OPT_i = 1 << 6,
+ OPT_n = 1 << 7,
+ OPT_p = 1 << 8,
+ OPT_q = 1 << 9,
+ OPT_R = 1 << 10,
+ OPT_r = 1 << 11,
+ OPT_s = 1 << 12,
+ OPT_T = 1 << 13,
+ OPT_t = 1 << 14,
+ OPT_v = 1 << 15,
+ OPT_S = 1 << 16,
+ OPT_A = 1 << 17,
+ OPT_O = 1 << 18,
+ OPT_o = 1 << 19,
+ OPT_f = 1 << 20,
+ OPT_m = 1 << 21, // zzz
+/* The rest has variable bit positions, need to be clever */
+ OPTBIT_LAST = 21,
+ USE_FOR_MMU( OPTBIT_b,)
+ USE_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
+ USE_FEATURE_UDHCP_PORT( OPTBIT_P,)
+ USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,)
+ USE_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
+ USE_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,)
};
- /* get options */
- while (1) {
- int option_index = 0;
- c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v", arg_options, &option_index);
- if (c == -1) break;
-
- switch (c) {
- case 'c':
- len = strlen(optarg) > 255 ? 255 : strlen(optarg);
- if (client_config.clientid) free(client_config.clientid);
- client_config.clientid = xmalloc(len + 2);
- client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
- client_config.clientid[OPT_LEN] = len;
- client_config.clientid[OPT_DATA] = '\0';
- strncpy(client_config.clientid + OPT_DATA, optarg, len);
- break;
- case 'f':
- client_config.foreground = 1;
- break;
- case 'b':
- client_config.background_if_no_lease = 1;
- break;
- case 'h':
- case 'H':
- len = strlen(optarg) > 255 ? 255 : strlen(optarg);
- if (client_config.hostname) free(client_config.hostname);
- client_config.hostname = xmalloc(len + 2);
- client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
- client_config.hostname[OPT_LEN] = len;
- strncpy(client_config.hostname + 2, optarg, len);
- break;
- case 'i':
- client_config.interface = optarg;
- break;
- case 'n':
- client_config.abort_if_no_lease = 1;
- break;
- case 'p':
- client_config.pidfile = optarg;
- break;
- case 'q':
- client_config.quit_after_lease = 1;
- break;
- case 'r':
- requested_ip = inet_addr(optarg);
- break;
- case 's':
- client_config.script = optarg;
- break;
- case 'v':
- bb_error_msg("version %s\n", VERSION);
- return(0);
- break;
- default:
- bb_show_usage();
- }
+ /* Default options. */
+ USE_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
+ USE_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
+ client_config.interface = "eth0";
+ client_config.script = DEFAULT_SCRIPT;
+
+ /* Parse command line */
+ /* Cc: mutually exclusive; O: list; -T,-t,-A take numeric param */
+ opt_complementary = "c--C:C--c:O::T+:t+:A+";
+ USE_GETOPT_LONG(applet_long_options = udhcpc_longopts;)
+ opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:vSA:O:of"
+ "m" // zzz
+ USE_FOR_MMU("b")
+ USE_FEATURE_UDHCPC_ARPING("a")
+ USE_FEATURE_UDHCP_PORT("P:")
+ , &str_c, &str_V, &str_h, &str_h, &str_F
+ , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
+ , &client_config.script /* s */
+ , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
+ , &list_O
+ USE_FEATURE_UDHCP_PORT(, &str_P)
+ );
+ if (opt & OPT_c)
+ client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
+ if (opt & OPT_V)
+ client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
+ if (opt & (OPT_h|OPT_H))
+ client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
+ if (opt & OPT_F) {
+ client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
+ /* Flags: 0000NEOS
+ S: 1 => Client requests Server to update A RR in DNS as well as PTR
+ O: 1 => Server indicates to client that DNS has been updated regardless
+ E: 1 => Name data is DNS format, i.e. <4>host<6>domain<3>com<0> not "host.domain.com"
+ N: 1 => Client requests Server to not update DNS
+ */
+ client_config.fqdn[OPT_DATA + 0] = 0x1;
+ /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */
+ /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */
+ }
+ if (opt & OPT_r)
+ requested_ip = inet_addr(str_r);
+ if (opt & OPT_v) {
+ puts("version "BB_VER);
+ return 0;
+ }
+#if ENABLE_FEATURE_UDHCP_PORT
+ if (opt & OPT_P) {
+ CLIENT_PORT = xatou16(str_P);
+ SERVER_PORT = CLIENT_PORT - 1;
+ }
+#endif
+ if (opt & OPT_o)
+ client_config.no_default_options = 1;
+ while (list_O) {
+ char *optstr = llist_pop(&list_O);
+ int n = index_in_strings(dhcp_option_strings, optstr);
+ if (n < 0)
+ bb_error_msg_and_die("unknown option '%s'", optstr);
+ n = dhcp_options[n].code;
+ client_config.opt_mask[n >> 3] |= 1 << (n & 7);
+ }
+ if (opt & OPT_m) minpkt = 1; // zzz
+
+ if (udhcp_read_interface(client_config.interface, &client_config.ifindex,
+ NULL, client_config.arp))
+ return 1;
+#if !BB_MMU
+ /* on NOMMU reexec (i.e., background) early */
+ if (!(opt & OPT_f)) {
+ bb_daemonize_or_rexec(0 /* flags */, argv);
+ logmode = LOGMODE_NONE;
+ }
+#endif
+ if (opt & OPT_S) {
+ openlog(applet_name, LOG_PID, LOG_DAEMON);
+ logmode |= LOGMODE_SYSLOG;
}
- start_log("client");
- if (read_interface(client_config.interface, &client_config.ifindex,
- NULL, client_config.arp) < 0)
- return(1);
-
- if (!client_config.clientid) {
- client_config.clientid = xmalloc(6 + 3);
- client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
- client_config.clientid[OPT_LEN] = 7;
+ /* Make sure fd 0,1,2 are open */
+ bb_sanitize_stdio();
+ /* Equivalent of doing a fflush after every \n */
+ setlinebuf(stdout);
+
+ /* Create pidfile */
+ write_pidfile(client_config.pidfile);
+
+ /* Goes to stdout (unless NOMMU) and possibly syslog */
+ bb_info_msg("%s (v"BB_VER") started", applet_name);
+
+ /* if not set, and not suppressed, setup the default client ID */
+ if (!client_config.clientid && !(opt & OPT_C)) {
+ client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
client_config.clientid[OPT_DATA] = 1;
- memcpy(client_config.clientid + 3, client_config.arp, 6);
+ memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);
}
- /* setup signal handlers */
- udhcp_set_signal_pipe(SIGUSR2);
-
+ if (!client_config.vendorclass)
+ client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
+
+ /* setup the signal pipe */
+ udhcp_sp_setup();
+
state = INIT_SELECTING;
- run_script(NULL, "deconfig");
- change_mode(LISTEN_RAW);
+ udhcp_run_script(NULL, "deconfig");
+ change_listen_mode(LISTEN_RAW);
+ packet_num = 0;
+ timeout = 0;
+ already_waited_sec = 0;
+ /* Main event loop. select() waits on signal pipe and possibly
+ * on sockfd.
+ * "continue" statements in code below jump to the top of the loop.
+ */
for (;;) {
+ /* silence "uninitialized!" warning */
+ unsigned timestamp_before_wait = timestamp_before_wait;
- tv.tv_sec = timeout - time(0);
- tv.tv_usec = 0;
- FD_ZERO(&rfds);
+ //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
- if (listen_mode != LISTEN_NONE && fd < 0) {
- if (listen_mode == LISTEN_KERNEL)
- fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
- else
- fd = raw_socket(client_config.ifindex);
- if (fd < 0) {
- LOG(LOG_ERR, "FATAL: couldn't listen on socket, %m");
- return(0);
- }
- }
- if (fd >= 0) FD_SET(fd, &rfds);
- FD_SET(udhcp_signal_pipe[0], &rfds);
+ /* Was opening raw or udp socket here
+ * if (listen_mode != LISTEN_NONE && sockfd < 0),
+ * but on fast network renew responses return faster
+ * than we open sockets. Thus this code is moved
+ * to change_listen_mode(). Thus we open listen socket
+ * BEFORE we send renew request (see "case BOUND:"). */
+
+ max_fd = udhcp_sp_fd_set(&rfds, sockfd);
- if (tv.tv_sec > 0) {
- DEBUG(LOG_INFO, "Waiting on select...\n");
- max_fd = udhcp_signal_pipe[0] > fd ? udhcp_signal_pipe[0] : fd;
+ tv.tv_sec = timeout - already_waited_sec;
+ tv.tv_usec = 0;
+ retval = 0; /* If we already timed out, fall through, else... */
+ if ((int)tv.tv_sec > 0) {
+ timestamp_before_wait = (unsigned)monotonic_sec();
+ DEBUG("Waiting on select...");
retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
- } else retval = 0; /* If we already timed out, fall through */
+ if (retval < 0) {
+ /* EINTR? A signal was caught, don't panic */
+ if (errno == EINTR) {
+ already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
+ continue;
+ }
+ /* Else: an error occured, panic! */
+ bb_perror_msg_and_die("select");
+ }
+ }
- now = time(0);
+ /* If timeout dropped to zero, time to become active:
+ * resend discover/renew/whatever
+ */
if (retval == 0) {
- /* timeout dropped to zero */
+ /* We will restart the wait in any case */
+ already_waited_sec = 0;
+
switch (state) {
case INIT_SELECTING:
- if (packet_num < 3) {
+ if (packet_num < discover_retries) {
if (packet_num == 0)
xid = random_xid();
- /* send discover packet */
send_discover(xid, requested_ip); /* broadcast */
-
- timeout = now + ((packet_num == 2) ? 4 : 2);
+
+ timeout = discover_timeout;
packet_num++;
- } else {
- if (client_config.background_if_no_lease) {
- LOG(LOG_INFO, "No lease, forking to background.");
- client_background();
- } else if (client_config.abort_if_no_lease) {
- LOG(LOG_INFO, "No lease, failing.");
- return(1);
- }
- /* wait to try again */
- packet_num = 0;
- timeout = now + 60;
+ continue;
}
- break;
- case RENEW_REQUESTED:
+ leasefail:
+ udhcp_run_script(NULL, "leasefail");
+#if BB_MMU /* -b is not supported on NOMMU */
+ if (opt & OPT_b) { /* background if no lease */
+ bb_info_msg("No lease, forking to background");
+ client_background();
+ /* do not background again! */
+ opt = ((opt & ~OPT_b) | OPT_f);
+ } else
+#endif
+ if (opt & OPT_n) { /* abort if no lease */
+ bb_info_msg("No lease, failing");
+ retval = 1;
+ goto ret;
+ }
+ /* wait before trying again */
+ timeout = tryagain_timeout;
+ packet_num = 0;
+ continue;
case REQUESTING:
- if (packet_num < 3) {
- /* send request packet */
- if (state == RENEW_REQUESTED)
- send_renew(xid, server_addr, requested_ip); /* unicast */
- else send_selecting(xid, server_addr, requested_ip); /* broadcast */
-
- timeout = now + ((packet_num == 2) ? 10 : 2);
+ if (packet_num < discover_retries) {
+ /* send broadcast select packet */
+ send_select(xid, server_addr, requested_ip);
+ timeout = discover_timeout;
packet_num++;
- } else {
- /* timed out, go back to init state */
- if (state == RENEW_REQUESTED) run_script(NULL, "deconfig");
- state = INIT_SELECTING;
- timeout = now;
- packet_num = 0;
- change_mode(LISTEN_RAW);
+ continue;
}
- break;
+ /* Timed out, go back to init state.
+ * "discover...select...discover..." loops
+ * were seen in the wild. Treat them similarly
+ * to "no response to discover" case */
+ change_listen_mode(LISTEN_RAW);
+ state = INIT_SELECTING;
+ goto leasefail;
case BOUND:
- /* Lease is starting to run out, time to enter renewing state */
+ /* Half of the lease passed, time to enter renewing state */
state = RENEWING;
- change_mode(LISTEN_KERNEL);
- DEBUG(LOG_INFO, "Entering renew state");
+ change_listen_mode(LISTEN_RAW); // was: LISTEN_KERNEL -- zzz
+ DEBUG("Entering renew state");
/* fall right through */
+ case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
+ case_RENEW_REQUESTED:
case RENEWING:
- /* Either set a new T1, or enter REBINDING state */
- if ((t2 - t1) <= (lease / 14400 + 1)) {
- /* timed out, enter rebinding state */
- state = REBINDING;
- timeout = now + (t2 - t1);
- DEBUG(LOG_INFO, "Entering rebinding state");
- } else {
- /* send a request packet */
- send_renew(xid, server_addr, requested_ip); /* unicast */
-
- t1 = (t2 - t1) / 2 + t1;
- timeout = t1 + start;
+ if (timeout > 60) {
+ /* send an unicast renew request packet */
+ send_renew(xid, server_addr, requested_ip);
+ timeout >>= 1;
+ continue;
}
- break;
+ /* Timed out, enter rebinding state */
+ DEBUG("Entering rebinding state");
+ state = REBINDING;
+ /* fall right through */
case REBINDING:
- /* Either set a new T2, or enter INIT state */
- if ((lease - t2) <= (lease / 14400 + 1)) {
- /* timed out, enter init state */
- state = INIT_SELECTING;
- LOG(LOG_INFO, "Lease lost, entering init state");
- run_script(NULL, "deconfig");
- timeout = now;
- packet_num = 0;
- change_mode(LISTEN_RAW);
- } else {
+ /* Switch to bcast receive */
+ change_listen_mode(LISTEN_RAW);
+ /* Lease is *really* about to run out,
+ * try to find DHCP server using broadcast */
+ if (timeout > 0) {
/* send a request packet */
- send_renew(xid, 0, requested_ip); /* broadcast */
-
- t2 = (lease - t2) / 2 + t2;
- timeout = t2 + start;
+ send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); /* broadcast */
+ timeout >>= 1;
+ continue;
}
- break;
- case RELEASED:
- /* yah, I know, *you* say it would never happen */
- timeout = 0x7fffffff;
- break;
+ /* Timed out, enter init state */
+ bb_info_msg("Lease lost, entering init state");
+ udhcp_run_script(NULL, "deconfig");
+ state = INIT_SELECTING;
+ /*timeout = 0; - already is */
+ packet_num = 0;
+ continue;
+ /* case RELEASED: */
}
- } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) {
- /* a packet is ready, read it */
-
+ /* yah, I know, *you* say it would never happen */
+ timeout = INT_MAX;
+ continue; /* back to main loop */
+ } /* if select timed out */
+
+ /* select() didn't timeout, something happened */
+
+ /* Is it a signal? */
+ /* note: udhcp_sp_read checks FD_ISSET before reading */
+ switch (udhcp_sp_read(&rfds)) {
+ case SIGUSR1:
+ perform_renew();
+ if (state == RENEW_REQUESTED)
+ goto case_RENEW_REQUESTED;
+ /* Start things over */
+ packet_num = 0;
+ /* Kill any timeouts because the user wants this to hurry along */
+ timeout = 0;
+ continue;
+ case SIGUSR2:
+ perform_release(requested_ip, server_addr);
+ timeout = INT_MAX;
+ continue;
+ case SIGTERM:
+ bb_info_msg("Received SIGTERM");
+ if (opt & OPT_R) /* release on quit */
+ perform_release(requested_ip, server_addr);
+ goto ret0;
+ }
+
+ /* Is it a packet? */
+ if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
+ continue; /* no */
+
+ {
+ int len;
+
+ /* A packet is ready, read it */
if (listen_mode == LISTEN_KERNEL)
- len = get_packet(&packet, fd);
- else len = get_raw_packet(&packet, fd);
-
- if (len == -1 && errno != EINTR) {
- DEBUG(LOG_INFO, "error on read, %m, reopening socket");
- change_mode(listen_mode); /* just close and reopen */
- }
- if (len < 0) continue;
-
- if (packet.xid != xid) {
- DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
- (unsigned long) packet.xid, xid);
- continue;
+ len = udhcp_recv_kernel_packet(&packet, sockfd);
+ else
+ len = udhcp_recv_raw_packet(&packet, sockfd);
+ if (len == -1) {
+ /* Error is severe, reopen socket */
+ bb_info_msg("Read error: %s, reopening socket", strerror(errno));
+ sleep(discover_timeout); /* 3 seconds by default */
+ change_listen_mode(listen_mode); /* just close and reopen */
}
-
- if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
- DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
+ /* If this packet will turn out to be unrelated/bogus,
+ * we will go back and wait for next one.
+ * Be sure timeout is properly decreased. */
+ already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
+ if (len < 0)
continue;
+ }
+
+ if (packet.xid != xid) {
+ DEBUG("xid %x (our is %x), ignoring packet",
+ (unsigned)packet.xid, (unsigned)xid);
+ continue;
+ }
+
+ /* Ignore packets that aren't for us */
+ if (memcmp(packet.chaddr, client_config.arp, 6)) {
+ DEBUG("Packet does not have our chaddr - ignoring");
+ continue;
+ }
+
+ message = get_option(&packet, DHCP_MESSAGE_TYPE);
+ if (message == NULL) {
+ bb_error_msg("no message type option, ignoring packet");
+ continue;
+ }
+
+ switch (state) {
+ case INIT_SELECTING:
+ /* Must be a DHCPOFFER to one of our xid's */
+ if (*message == DHCPOFFER) {
+ /* TODO: why we don't just fetch server's IP from IP header? */
+ temp = get_option(&packet, DHCP_SERVER_ID);
+ if (!temp) {
+ bb_error_msg("no server ID in message");
+ continue;
+ /* still selecting - this server looks bad */
+ }
+ /* it IS unaligned sometimes, don't "optimize" */
+ move_from_unaligned32(server_addr, temp);
+ xid = packet.xid;
+ requested_ip = packet.yiaddr;
+
+ /* enter requesting state */
+ state = REQUESTING;
+ timeout = 0;
+ packet_num = 0;
+ already_waited_sec = 0;
}
-
- switch (state) {
- case INIT_SELECTING:
- /* Must be a DHCPOFFER to one of our xid's */
- if (*message == DHCPOFFER) {
- if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
- memcpy(&server_addr, temp, 4);
- xid = packet.xid;
- requested_ip = packet.yiaddr;
-
- /* enter requesting state */
- state = REQUESTING;
- timeout = now;
+ continue;
+ case REQUESTING:
+ case RENEWING:
+ case RENEW_REQUESTED:
+ case REBINDING:
+ if (*message == DHCPACK) {
+ temp = get_option(&packet, DHCP_LEASE_TIME);
+ if (!temp) {
+ bb_error_msg("no lease time with ACK, using 1 hour lease");
+ lease_seconds = 60 * 60;
+ } else {
+ /* it IS unaligned sometimes, don't "optimize" */
+ move_from_unaligned32(lease_seconds, temp);
+ lease_seconds = ntohl(lease_seconds);
+ lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
+ if (lease_seconds < 10) /* and not too small */
+ lease_seconds = 10;
+ }
+#if ENABLE_FEATURE_UDHCPC_ARPING
+ if (opt & OPT_a) {
+/* RFC 2131 3.1 paragraph 5:
+ * "The client receives the DHCPACK message with configuration
+ * parameters. The client SHOULD perform a final check on the
+ * parameters (e.g., ARP for allocated network address), and notes
+ * the duration of the lease specified in the DHCPACK message. At this
+ * point, the client is configured. If the client detects that the
+ * address is already in use (e.g., through the use of ARP),
+ * the client MUST send a DHCPDECLINE message to the server and restarts
+ * the configuration process..." */
+ if (!arpping(packet.yiaddr,
+ (uint32_t) 0,
+ client_config.arp,
+ client_config.interface)
+ ) {
+ bb_info_msg("Offered address is in use "
+ "(got ARP reply), declining");
+ send_decline(xid, server_addr, packet.yiaddr);
+
+ if (state != REQUESTING)
+ udhcp_run_script(NULL, "deconfig");
+ change_listen_mode(LISTEN_RAW);
+ state = INIT_SELECTING;
+ requested_ip = 0;
+ timeout = tryagain_timeout;
packet_num = 0;
- } else {
- DEBUG(LOG_ERR, "No server ID in message");
+ already_waited_sec = 0;
+ continue; /* back to main loop */
}
}
- break;
- case RENEW_REQUESTED:
- case REQUESTING:
- case RENEWING:
- case REBINDING:
- if (*message == DHCPACK) {
- if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
- LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease");
- lease = 60 * 60;
- } else {
- memcpy(&lease, temp, 4);
- lease = ntohl(lease);
- }
-
- /* enter bound state */
- t1 = lease / 2;
-
- /* little fixed point for n * .875 */
- t2 = (lease * 0x7) >> 3;
+#endif
+ /* enter bound state */
+ timeout = lease_seconds / 2;
+ {
+ struct in_addr temp_addr;
temp_addr.s_addr = packet.yiaddr;
- LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",
- inet_ntoa(temp_addr), lease);
- start = now;
- timeout = t1 + start;
- requested_ip = packet.yiaddr;
- run_script(&packet,
- ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
-
- state = BOUND;
- change_mode(LISTEN_NONE);
- if (client_config.quit_after_lease)
- return(0);
- if (!client_config.foreground)
- client_background();
-
- } else if (*message == DHCPNAK) {
- /* return to init state */
- LOG(LOG_INFO, "Received DHCP NAK");
- run_script(&packet, "nak");
- if (state != REQUESTING)
- run_script(NULL, "deconfig");
- state = INIT_SELECTING;
- timeout = now;
- requested_ip = 0;
- packet_num = 0;
- change_mode(LISTEN_RAW);
- sleep(3); /* avoid excessive network traffic */
+ bb_info_msg("Lease of %s obtained, lease time %u",
+ inet_ntoa(temp_addr), (unsigned)lease_seconds);
}
- break;
- /* case BOUND, RELEASED: - ignore all packets */
- }
- } else if (retval > 0 && FD_ISSET(udhcp_signal_pipe[0], &rfds)) {
- if (read(udhcp_signal_pipe[0], &sig, sizeof(sig)) < 0) {
- DEBUG(LOG_ERR, "Could not read signal: %m");
- continue; /* probably just EINTR */
+ requested_ip = packet.yiaddr;
+ udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
+
+ state = BOUND;
+ change_listen_mode(LISTEN_NONE);
+ if (opt & OPT_q) { /* quit after lease */
+ if (opt & OPT_R) /* release on quit */
+ perform_release(requested_ip, server_addr);
+ goto ret0;
+ }
+ /* future renew failures should not exit (JM) */
+ opt &= ~OPT_n;
+#if BB_MMU /* NOMMU case backgrounded earlier */
+ if (!(opt & OPT_f)) {
+ client_background();
+ /* do not background again! */
+ opt = ((opt & ~OPT_b) | OPT_f);
+ }
+#endif
+ already_waited_sec = 0;
+ continue; /* back to main loop */
}
- switch (sig) {
- case SIGUSR1:
- perform_renew();
- break;
- case SIGUSR2:
- perform_release();
- break;
- case SIGTERM:
- LOG(LOG_INFO, "Received SIGTERM");
- return(0);
+ if (*message == DHCPNAK) {
+ /* return to init state */
+ bb_info_msg("Received DHCP NAK");
+ udhcp_run_script(&packet, "nak");
+ if (state != REQUESTING)
+ udhcp_run_script(NULL, "deconfig");
+ change_listen_mode(LISTEN_RAW);
+ sleep(3); /* avoid excessive network traffic */
+ state = INIT_SELECTING;
+ requested_ip = 0;
+ timeout = 0;
+ packet_num = 0;
+ already_waited_sec = 0;
}
- } else if (retval == -1 && errno == EINTR) {
- /* a signal was caught */
- } else {
- /* An error occured */
- DEBUG(LOG_ERR, "Error on select");
+ continue;
+ /* case BOUND: - ignore all packets */
+ /* case RELEASED: - ignore all packets */
}
-
- }
- return 0;
+ /* back to main loop */
+ } /* for (;;) - main loop ends */
+
+ ret0:
+ retval = 0;
+ ret:
+ /*if (client_config.pidfile) - remove_pidfile has its own check */
+ remove_pidfile(client_config.pidfile);
+ return retval;
}
diff --git a/release/src/router/busybox/networking/udhcp/dhcpc.h b/release/src/router/busybox/networking/udhcp/dhcpc.h
index e23d9d4f..7b779426 100644
--- a/release/src/router/busybox/networking/udhcp/dhcpc.h
+++ b/release/src/router/busybox/networking/udhcp/dhcpc.h
@@ -1,32 +1,51 @@
+/* vi: set sw=4 ts=4: */
/* dhcpc.h */
-#ifndef _DHCPC_H
-#define _DHCPC_H
-
-#define INIT_SELECTING 0
-#define REQUESTING 1
-#define BOUND 2
-#define RENEWING 3
-#define REBINDING 4
-#define INIT_REBOOT 5
-#define RENEW_REQUESTED 6
-#define RELEASED 7
+#ifndef UDHCP_DHCPC_H
+#define UDHCP_DHCPC_H 1
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
struct client_config_t {
- char foreground; /* Do not fork */
- char quit_after_lease; /* Quit after obtaining lease */
- char abort_if_no_lease; /* Abort if no lease */
- char background_if_no_lease; /* Fork to background if no lease */
- char *interface; /* The name of the interface to use */
- char *pidfile; /* Optionally store the process ID */
- char *script; /* User script to run at dhcp events */
- unsigned char *clientid; /* Optional client id to use */
- unsigned char *hostname; /* Optional hostname to use */
- int ifindex; /* Index number of the interface to use */
- unsigned char arp[6]; /* Our arp address */
+ uint8_t arp[6]; /* Our arp address */
+ /* TODO: combine flag fields into single "unsigned opt" */
+ /* (can be set directly to the result of getopt32) */
+ char no_default_options; /* Do not include default optins in request */
+ USE_FEATURE_UDHCP_PORT(uint16_t port;)
+ int ifindex; /* Index number of the interface to use */
+ uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */
+ const char *interface; /* The name of the interface to use */
+ char *pidfile; /* Optionally store the process ID */
+ const char *script; /* User script to run at dhcp events */
+ uint8_t *clientid; /* Optional client id to use */
+ uint8_t *vendorclass; /* Optional vendor class-id to use */
+ uint8_t *hostname; /* Optional hostname to use */
+ uint8_t *fqdn; /* Optional fully qualified domain name to use */
};
-extern struct client_config_t client_config;
+/* server_config sits in 1st half of bb_common_bufsiz1 */
+#define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2]))
+
+#if ENABLE_FEATURE_UDHCP_PORT
+#define CLIENT_PORT (client_config.port)
+#else
+#define CLIENT_PORT 68
+#endif
+
+
+/*** clientpacket.h ***/
+
+uint32_t random_xid(void) FAST_FUNC;
+int send_discover(uint32_t xid, uint32_t requested) FAST_FUNC;
+int send_select(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC;
+#if ENABLE_FEATURE_UDHCPC_ARPING
+int send_decline(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC;
+#endif
+int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC;
+int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC;
+int send_release(uint32_t server, uint32_t ciaddr) FAST_FUNC;
+
+int udhcp_recv_raw_packet(struct dhcpMessage *payload, int fd) FAST_FUNC;
+POP_SAVED_FUNCTION_VISIBILITY
#endif
diff --git a/release/src/router/busybox/networking/udhcp/dhcpd.c b/release/src/router/busybox/networking/udhcp/dhcpd.c
index c21cb72a..a82fd8c4 100644
--- a/release/src/router/busybox/networking/udhcp/dhcpd.c
+++ b/release/src/router/busybox/networking/udhcp/dhcpd.c
@@ -1,3 +1,4 @@
+/* vi: set sw=4 ts=4: */
/* dhcpd.c
*
* udhcp Server
@@ -6,248 +7,272 @@
*
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <time.h>
-#include <sys/time.h>
-
+#include <syslog.h>
+#include "common.h"
+#include "dhcpc.h"
#include "dhcpd.h"
-#include "arpping.h"
-#include "socket.h"
#include "options.h"
-#include "files.h"
-#include "serverpacket.h"
-#include "common.h"
/* globals */
struct dhcpOfferedAddr *leases;
-struct server_config_t server_config;
+/* struct server_config_t server_config is in bb_common_bufsiz1 */
-int udhcpd_main(int argc, char *argv[])
-{
+int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int udhcpd_main(int argc UNUSED_PARAM, char **argv)
+{
fd_set rfds;
- struct timeval tv;
- int server_socket = -1;
- int bytes, retval;
+ int server_socket = -1, retval, max_sock;
struct dhcpMessage packet;
- unsigned char *state;
- unsigned char *server_id, *requested;
- u_int32_t server_id_align, requested_align;
- unsigned long timeout_end;
+ uint8_t *state, *server_id, *requested;
+ uint32_t server_id_aligned = server_id_aligned; /* for compiler */
+ uint32_t requested_aligned = requested_aligned;
+ uint32_t static_lease_ip;
+ unsigned timeout_end;
+ unsigned num_ips;
+ unsigned opt;
struct option_set *option;
- struct dhcpOfferedAddr *lease;
- int max_sock;
- int sig;
- unsigned long num_ips;
-
- start_log("server");
-
- memset(&server_config, 0, sizeof(struct server_config_t));
-
- if (argc < 2)
- read_config(DHCPD_CONF_FILE);
- else read_config(argv[1]);
-
- if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
- memcpy(&server_config.lease, option->data + 2, 4);
+ struct dhcpOfferedAddr *lease, static_lease;
+ USE_FEATURE_UDHCP_PORT(char *str_P;)
+
+#if ENABLE_FEATURE_UDHCP_PORT
+ SERVER_PORT = 67;
+ CLIENT_PORT = 68;
+#endif
+
+ opt = getopt32(argv, "fS" USE_FEATURE_UDHCP_PORT("P:", &str_P));
+ argv += optind;
+ if (!(opt & 1)) { /* no -f */
+ bb_daemonize_or_rexec(0, argv);
+ logmode = LOGMODE_NONE;
+ }
+ if (opt & 2) { /* -S */
+ openlog(applet_name, LOG_PID, LOG_DAEMON);
+ logmode |= LOGMODE_SYSLOG;
+ }
+#if ENABLE_FEATURE_UDHCP_PORT
+ if (opt & 4) { /* -P */
+ SERVER_PORT = xatou16(str_P);
+ CLIENT_PORT = SERVER_PORT + 1;
+ }
+#endif
+ /* Would rather not do read_config before daemonization -
+ * otherwise NOMMU machines will parse config twice */
+ read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
+
+ /* Make sure fd 0,1,2 are open */
+ bb_sanitize_stdio();
+ /* Equivalent of doing a fflush after every \n */
+ setlinebuf(stdout);
+
+ /* Create pidfile */
+ write_pidfile(server_config.pidfile);
+ /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */
+
+ bb_info_msg("%s (v"BB_VER") started", applet_name);
+
+ option = find_option(server_config.options, DHCP_LEASE_TIME);
+ server_config.lease = LEASE_TIME;
+ if (option) {
+ move_from_unaligned32(server_config.lease, option->data + 2);
server_config.lease = ntohl(server_config.lease);
}
- else server_config.lease = LEASE_TIME;
-
+
/* Sanity check */
- num_ips = ntohl(server_config.end) - ntohl(server_config.start);
+ num_ips = server_config.end_ip - server_config.start_ip + 1;
if (server_config.max_leases > num_ips) {
- LOG(LOG_ERR, "max_leases value (%lu) not sane, "
- "setting to %lu instead",
- server_config.max_leases, num_ips);
+ bb_error_msg("max_leases=%u is too big, setting to %u",
+ (unsigned)server_config.max_leases, num_ips);
server_config.max_leases = num_ips;
}
- leases = xcalloc(sizeof(struct dhcpOfferedAddr), server_config.max_leases);
+ leases = xzalloc(server_config.max_leases * sizeof(*leases));
read_leases(server_config.lease_file);
- if (read_interface(server_config.interface, &server_config.ifindex,
- &server_config.server, server_config.arp) < 0)
- return(1);
-
-#ifndef CONFIG_FEATURE_UDHCP_DEBUG
- background(server_config.pidfile);
-#endif
+ if (udhcp_read_interface(server_config.interface, &server_config.ifindex,
+ &server_config.server, server_config.arp)) {
+ retval = 1;
+ goto ret;
+ }
- udhcp_set_signal_pipe(0);
+ /* Setup the signal pipe */
+ udhcp_sp_setup();
- timeout_end = time(0) + server_config.auto_time;
- while(1) { /* loop until universe collapses */
+ timeout_end = monotonic_sec() + server_config.auto_time;
+ while (1) { /* loop until universe collapses */
+ int bytes;
+ struct timeval tv;
- if (server_socket < 0)
- if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
- LOG(LOG_ERR, "FATAL: couldn't create server socket, %m");
- return(2);
- }
+ if (server_socket < 0) {
+ server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
+ server_config.interface);
+ }
- FD_ZERO(&rfds);
- FD_SET(server_socket, &rfds);
- FD_SET(udhcp_signal_pipe[0], &rfds);
+ max_sock = udhcp_sp_fd_set(&rfds, server_socket);
if (server_config.auto_time) {
- tv.tv_sec = timeout_end - time(0);
+ tv.tv_sec = timeout_end - monotonic_sec();
tv.tv_usec = 0;
}
+ retval = 0;
if (!server_config.auto_time || tv.tv_sec > 0) {
- max_sock = server_socket > udhcp_signal_pipe[0] ? server_socket : udhcp_signal_pipe[0];
- retval = select(max_sock + 1, &rfds, NULL, NULL,
+ retval = select(max_sock + 1, &rfds, NULL, NULL,
server_config.auto_time ? &tv : NULL);
- } else retval = 0; /* If we already timed out, fall through */
-
+ }
if (retval == 0) {
write_leases();
- timeout_end = time(0) + server_config.auto_time;
+ timeout_end = monotonic_sec() + server_config.auto_time;
continue;
- } else if (retval < 0 && errno != EINTR) {
- DEBUG(LOG_INFO, "error on select");
+ }
+ if (retval < 0 && errno != EINTR) {
+ DEBUG("error on select");
continue;
}
-
- if (FD_ISSET(udhcp_signal_pipe[0], &rfds)) {
- if (read(udhcp_signal_pipe[0], &sig, sizeof(sig)) < 0)
- continue; /* probably just EINTR */
- switch (sig) {
- case SIGUSR1:
- LOG(LOG_INFO, "Received a SIGUSR1");
- write_leases();
- /* why not just reset the timeout, eh */
- timeout_end = time(0) + server_config.auto_time;
- continue;
- case SIGTERM:
- LOG(LOG_INFO, "Received a SIGTERM");
- return(0);
- }
+
+ switch (udhcp_sp_read(&rfds)) {
+ case SIGUSR1:
+ bb_info_msg("Received a SIGUSR1");
+ write_leases();
+ /* why not just reset the timeout, eh */
+ timeout_end = monotonic_sec() + server_config.auto_time;
+ continue;
+ case SIGTERM:
+ bb_info_msg("Received a SIGTERM");
+ goto ret0;
+ case 0: /* no signal: read a packet */
+ break;
+ default: /* signal or error (probably EINTR): back to select */
+ continue;
}
- if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
+ bytes = udhcp_recv_kernel_packet(&packet, server_socket);
+ if (bytes < 0) {
+ /* bytes can also be -2 ("bad packet data") */
if (bytes == -1 && errno != EINTR) {
- DEBUG(LOG_INFO, "error on read, %m, reopening socket");
+ DEBUG("error on read, %s, reopening socket", strerror(errno));
close(server_socket);
server_socket = -1;
}
continue;
}
- if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
- DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
+ state = get_option(&packet, DHCP_MESSAGE_TYPE);
+ if (state == NULL) {
+ bb_error_msg("cannot get option from packet, ignoring");
continue;
}
-
- /* ADDME: look for a static lease */
- lease = find_lease_by_chaddr(packet.chaddr);
+
+ /* Look for a static lease */
+ static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);
+ if (static_lease_ip) {
+ bb_info_msg("Found static lease: %x", static_lease_ip);
+
+ memcpy(&static_lease.chaddr, &packet.chaddr, 16);
+ static_lease.yiaddr = static_lease_ip;
+ static_lease.expires = 0;
+
+ lease = &static_lease;
+ } else {
+ lease = find_lease_by_chaddr(packet.chaddr);
+ }
+
switch (state[0]) {
case DHCPDISCOVER:
- DEBUG(LOG_INFO,"received DISCOVER");
-
- if (sendOffer(&packet) < 0) {
- LOG(LOG_ERR, "send OFFER failed");
+ DEBUG("Received DISCOVER");
+
+ if (send_offer(&packet) < 0) {
+ bb_error_msg("send OFFER failed");
}
- break;
- case DHCPREQUEST:
- DEBUG(LOG_INFO, "received REQUEST");
+ break;
+ case DHCPREQUEST:
+ DEBUG("received REQUEST");
requested = get_option(&packet, DHCP_REQUESTED_IP);
server_id = get_option(&packet, DHCP_SERVER_ID);
- if (requested) memcpy(&requested_align, requested, 4);
- if (server_id) memcpy(&server_id_align, server_id, 4);
-
- if (lease) { /*ADDME: or static lease */
+ if (requested)
+ move_from_unaligned32(requested_aligned, requested);
+ if (server_id)
+ move_from_unaligned32(server_id_aligned, server_id);
+
+ if (lease) {
if (server_id) {
/* SELECTING State */
- DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
- if (server_id_align == server_config.server && requested &&
- requested_align == lease->yiaddr) {
- sendACK(&packet, lease->yiaddr);
+ DEBUG("server_id = %08x", ntohl(server_id_aligned));
+ if (server_id_aligned == server_config.server
+ && requested
+ && requested_aligned == lease->yiaddr
+ ) {
+ send_ACK(&packet, lease->yiaddr);
}
- } else {
- if (requested) {
- /* INIT-REBOOT State */
- if (lease->yiaddr == requested_align)
- sendACK(&packet, lease->yiaddr);
- else sendNAK(&packet);
- } else {
- /* RENEWING or REBINDING State */
- if (lease->yiaddr == packet.ciaddr)
- sendACK(&packet, lease->yiaddr);
- else {
- /* don't know what to do!!!! */
- sendNAK(&packet);
- }
- }
+ } else if (requested) {
+ /* INIT-REBOOT State */
+ if (lease->yiaddr == requested_aligned)
+ send_ACK(&packet, lease->yiaddr);
+ else
+ send_NAK(&packet);
+ } else if (lease->yiaddr == packet.ciaddr) {
+ /* RENEWING or REBINDING State */
+ send_ACK(&packet, lease->yiaddr);
+ } else { /* don't know what to do!!!! */
+ send_NAK(&packet);
}
-
+
/* what to do if we have no record of the client */
} else if (server_id) {
/* SELECTING State */
} else if (requested) {
/* INIT-REBOOT State */
- if ((lease = find_lease_by_yiaddr(requested_align))) {
+ lease = find_lease_by_yiaddr(requested_aligned);
+ if (lease) {
if (lease_expired(lease)) {
/* probably best if we drop this lease */
memset(lease->chaddr, 0, 16);
/* make some contention for this address */
- } else sendNAK(&packet);
- } else if (requested_align < server_config.start ||
- requested_align > server_config.end) {
- sendNAK(&packet);
- } /* else remain silent */
+ } else
+ send_NAK(&packet);
+ } else {
+ uint32_t r = ntohl(requested_aligned);
+ if (r < server_config.start_ip
+ || r > server_config.end_ip
+ ) {
+ send_NAK(&packet);
+ }
+ /* else remain silent */
+ }
} else {
- /* RENEWING or REBINDING State */
+ /* RENEWING or REBINDING State */
}
break;
case DHCPDECLINE:
- DEBUG(LOG_INFO,"received DECLINE");
+ DEBUG("Received DECLINE");
if (lease) {
memset(lease->chaddr, 0, 16);
- lease->expires = time(0) + server_config.decline_time;
- }
+ lease->expires = time(NULL) + server_config.decline_time;
+ }
break;
case DHCPRELEASE:
- DEBUG(LOG_INFO,"received RELEASE");
- if (lease) lease->expires = time(0);
+ DEBUG("Received RELEASE");
+ if (lease)
+ lease->expires = time(NULL);
break;
case DHCPINFORM:
- DEBUG(LOG_INFO,"received INFORM");
+ DEBUG("Received INFORM");
send_inform(&packet);
- break;
+ break;
default:
- LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
+ bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);
}
}
-
- return 0;
+ ret0:
+ retval = 0;
+ ret:
+ /*if (server_config.pidfile) - server_config.pidfile is never NULL */
+ remove_pidfile(server_config.pidfile);
+ return retval;
}
diff --git a/release/src/router/busybox/networking/udhcp/dhcpd.h b/release/src/router/busybox/networking/udhcp/dhcpd.h
index e219143c..9667c61e 100644
--- a/release/src/router/busybox/networking/udhcp/dhcpd.h
+++ b/release/src/router/busybox/networking/udhcp/dhcpd.h
@@ -1,11 +1,9 @@
+/* vi: set sw=4 ts=4: */
/* dhcpd.h */
-#ifndef _DHCPD_H
-#define _DHCPD_H
+#ifndef UDHCP_DHCPD_H
+#define UDHCP_DHCPD_H 1
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-
-#include "leases.h"
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
/************************************/
/* Defaults _you_ may want to tweak */
@@ -13,118 +11,126 @@
/* the period of time the client is allowed to use that address */
#define LEASE_TIME (60*60*24*10) /* 10 days of seconds */
+#define LEASES_FILE CONFIG_DHCPD_LEASES_FILE
/* where to find the DHCP server configuration file */
#define DHCPD_CONF_FILE "/etc/udhcpd.conf"
-/*****************************************************************/
-/* Do not modify below here unless you know what you are doing!! */
-/*****************************************************************/
-
-/* DHCP protocol -- see RFC 2131 */
-#define SERVER_PORT 67
-#define CLIENT_PORT 68
-
-#define DHCP_MAGIC 0x63825363
-
-/* DHCP option codes (partial list) */
-#define DHCP_PADDING 0x00
-#define DHCP_SUBNET 0x01
-#define DHCP_TIME_OFFSET 0x02
-#define DHCP_ROUTER 0x03
-#define DHCP_TIME_SERVER 0x04
-#define DHCP_NAME_SERVER 0x05
-#define DHCP_DNS_SERVER 0x06
-#define DHCP_LOG_SERVER 0x07
-#define DHCP_COOKIE_SERVER 0x08
-#define DHCP_LPR_SERVER 0x09
-#define DHCP_HOST_NAME 0x0c
-#define DHCP_BOOT_SIZE 0x0d
-#define DHCP_DOMAIN_NAME 0x0f
-#define DHCP_SWAP_SERVER 0x10
-#define DHCP_ROOT_PATH 0x11
-#define DHCP_IP_TTL 0x17
-#define DHCP_MTU 0x1a
-#define DHCP_BROADCAST 0x1c
-#define DHCP_NTP_SERVER 0x2a
-#define DHCP_WINS_SERVER 0x2c
-#define DHCP_REQUESTED_IP 0x32
-#define DHCP_LEASE_TIME 0x33
-#define DHCP_OPTION_OVER 0x34
-#define DHCP_MESSAGE_TYPE 0x35
-#define DHCP_SERVER_ID 0x36
-#define DHCP_PARAM_REQ 0x37
-#define DHCP_MESSAGE 0x38
-#define DHCP_MAX_SIZE 0x39
-#define DHCP_T1 0x3a
-#define DHCP_T2 0x3b
-#define DHCP_VENDOR 0x3c
-#define DHCP_CLIENT_ID 0x3d
-
-#define DHCP_END 0xFF
-
-
-#define BOOTREQUEST 1
-#define BOOTREPLY 2
-
-#define ETH_10MB 1
-#define ETH_10MB_LEN 6
-
-#define DHCPDISCOVER 1
-#define DHCPOFFER 2
-#define DHCPREQUEST 3
-#define DHCPDECLINE 4
-#define DHCPACK 5
-#define DHCPNAK 6
-#define DHCPRELEASE 7
-#define DHCPINFORM 8
-
-#define BROADCAST_FLAG 0x8000
-
-#define OPTION_FIELD 0
-#define FILE_FIELD 1
-#define SNAME_FIELD 2
-
-/* miscellaneous defines */
-#define MAC_BCAST_ADDR (unsigned char *) "\xff\xff\xff\xff\xff\xff"
-#define OPT_CODE 0
-#define OPT_LEN 1
-#define OPT_DATA 2
-
struct option_set {
- unsigned char *data;
+ uint8_t *data;
struct option_set *next;
};
+struct static_lease {
+ struct static_lease *next;
+ uint32_t ip;
+ uint8_t mac[6];
+};
+
struct server_config_t {
- u_int32_t server; /* Our IP, in network order */
- u_int32_t start; /* Start address of leases, network order */
- u_int32_t end; /* End of leases, network order */
- struct option_set *options; /* List of DHCP options loaded from the config file */
- char *interface; /* The name of the interface to use */
- int ifindex; /* Index number of the interface to use */
- unsigned char arp[6]; /* Our arp address */
- unsigned long lease; /* lease time in seconds (host order) */
- unsigned long max_leases; /* maximum number of leases (including reserved address) */
- char remaining; /* should the lease file be interpreted as lease time remaining, or
- * as the time the lease expires */
- unsigned long auto_time; /* how long should udhcpd wait before writing a config file.
- * if this is zero, it will only write one on SIGUSR1 */
- unsigned long decline_time; /* how long an address is reserved if a client returns a
- * decline message */
- unsigned long conflict_time; /* how long an arp conflict offender is leased for */
- unsigned long offer_time; /* how long an offered address is reserved */
- unsigned long min_lease; /* minimum lease a client can request*/
+ uint32_t server; /* Our IP, in network order */
+#if ENABLE_FEATURE_UDHCP_PORT
+ uint16_t port;
+#endif
+ /* start,end are in host order: we need to compare start <= ip <= end */
+ uint32_t start_ip; /* Start address of leases, in host order */
+ uint32_t end_ip; /* End of leases, in host order */
+ struct option_set *options; /* List of DHCP options loaded from the config file */
+ char *interface; /* The name of the interface to use */
+ int ifindex; /* Index number of the interface to use */
+ uint8_t arp[6]; /* Our arp address */
+// disabled: dumpleases has no way of knowing this value,
+// and will break if it's off. Now it's on always.
+// char remaining; /* Should the lease time in lease file
+// * be written as lease time remaining, or
+// * as the absolute time the lease expires */
+ uint32_t lease; /* lease time in seconds (host order) */
+ uint32_t max_leases; /* maximum number of leases (including reserved address) */
+ uint32_t auto_time; /* how long should udhcpd wait before writing a config file.
+ * if this is zero, it will only write one on SIGUSR1 */
+ uint32_t decline_time; /* how long an address is reserved if a client returns a
+ * decline message */
+ uint32_t conflict_time; /* how long an arp conflict offender is leased for */
+ uint32_t offer_time; /* how long an offered address is reserved */
+ uint32_t min_lease; /* minimum lease time a client can request */
+ uint32_t siaddr; /* next server bootp option */
char *lease_file;
char *pidfile;
- char *notify_file; /* What to run whenever leases are written */
- u_int32_t siaddr; /* next server bootp option */
- char *sname; /* bootp server name */
- char *boot_file; /* bootp boot file option */
-};
+ char *notify_file; /* What to run whenever leases are written */
+ char *sname; /* bootp server name */
+ char *boot_file; /* bootp boot file option */
+ struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */
+};
+
+#define server_config (*(struct server_config_t*)&bb_common_bufsiz1)
+/* client_config sits in 2nd half of bb_common_bufsiz1 */
+
+#if ENABLE_FEATURE_UDHCP_PORT
+#define SERVER_PORT (server_config.port)
+#else
+#define SERVER_PORT 67
+#endif
+
+
+/*** leases.h ***/
+
+typedef uint32_t leasetime_t;
+typedef int32_t signed_leasetime_t;
+
+struct dhcpOfferedAddr {
+ uint8_t chaddr[16];
+ /* In network order */
+ uint32_t yiaddr;
+ /* Unix time when lease expires, regardless of value of
+ * server_config.remaining. Kept in memory in host order.
+ * When written to file, converted to network order
+ * and optionally adjusted (current time subtracted)
+ * if server_config.remaining = 1 */
+ leasetime_t expires;
+ uint8_t hostname[20]; /* (size is a multiply of 4) */
+};
-extern struct server_config_t server_config;
extern struct dhcpOfferedAddr *leases;
-
+
+struct dhcpOfferedAddr *add_lease(
+ const uint8_t *chaddr, uint32_t yiaddr,
+ leasetime_t leasetime, uint8_t *hostname
+ ) FAST_FUNC;
+int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC;
+struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC;
+struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;
+uint32_t find_free_or_expired_address(void) FAST_FUNC;
+
+
+/*** static_leases.h ***/
+
+/* Config file will pass static lease info to this function which will add it
+ * to a data structure that can be searched later */
+void addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t ip) FAST_FUNC;
+/* Check to see if a mac has an associated static lease */
+uint32_t getIpByMac(struct static_lease *lease_struct, void *arg) FAST_FUNC;
+/* Check to see if an ip is reserved as a static ip */
+int reservedIp(struct static_lease *lease_struct, uint32_t ip) FAST_FUNC;
+/* Print out static leases just to check what's going on (debug code) */
+void printStaticLeases(struct static_lease **lease_struct) FAST_FUNC;
+
+
+/*** serverpacket.h ***/
+
+int send_offer(struct dhcpMessage *oldpacket) FAST_FUNC;
+int send_NAK(struct dhcpMessage *oldpacket) FAST_FUNC;
+int send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) FAST_FUNC;
+int send_inform(struct dhcpMessage *oldpacket) FAST_FUNC;
+
+
+/*** files.h ***/
+
+void read_config(const char *file) FAST_FUNC;
+void write_leases(void) FAST_FUNC;
+void read_leases(const char *file) FAST_FUNC;
+struct option_set *find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC;
+
+
+POP_SAVED_FUNCTION_VISIBILITY
#endif
diff --git a/release/src/router/busybox/networking/udhcp/dhcprelay.c b/release/src/router/busybox/networking/udhcp/dhcprelay.c
new file mode 100644
index 00000000..53540d1a
--- /dev/null
+++ b/release/src/router/busybox/networking/udhcp/dhcprelay.c
@@ -0,0 +1,325 @@
+/* vi: set sw=4 ts=4: */
+/* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com>
+ *
+ * Licensed under GPL v2, see file LICENSE in this tarball for details.
+ *
+ * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support
+ * Copyright (C) 2002 Mario Strasser <mast@gmx.net>,
+ * Zuercher Hochschule Winterthur,
+ * Netbeat AG
+ * Upstream has GPL v2 or later
+ */
+
+#include "common.h"
+#include "options.h"
+
+#define SERVER_PORT 67
+#define SELECT_TIMEOUT 5 /* select timeout in sec. */
+#define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */
+
+/* This list holds information about clients. The xid_* functions manipulate this list. */
+struct xid_item {
+ unsigned timestamp;
+ int client;
+ uint32_t xid;
+ struct sockaddr_in ip;
+ struct xid_item *next;
+};
+
+#define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1)
+
+static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client)
+{
+ struct xid_item *item;
+
+ /* create new xid entry */
+ item = xmalloc(sizeof(struct xid_item));
+
+ /* add xid entry */
+ item->ip = *ip;
+ item->xid = xid;
+ item->client = client;
+ item->timestamp = monotonic_sec();
+ item->next = dhcprelay_xid_list.next;
+ dhcprelay_xid_list.next = item;
+
+ return item;
+}
+
+static void xid_expire(void)
+{
+ struct xid_item *item = dhcprelay_xid_list.next;
+ struct xid_item *last = &dhcprelay_xid_list;
+ unsigned current_time = monotonic_sec();
+
+ while (item != NULL) {
+ if ((current_time - item->timestamp) > MAX_LIFETIME) {
+ last->next = item->next;
+ free(item);
+ item = last->next;
+ } else {
+ last = item;
+ item = item->next;
+ }
+ }
+}
+
+static struct xid_item *xid_find(uint32_t xid)
+{
+ struct xid_item *item = dhcprelay_xid_list.next;
+ while (item != NULL) {
+ if (item->xid == xid) {
+ return item;
+ }
+ item = item->next;
+ }
+ return NULL;
+}
+
+static void xid_del(uint32_t xid)
+{
+ struct xid_item *item = dhcprelay_xid_list.next;
+ struct xid_item *last = &dhcprelay_xid_list;
+ while (item != NULL) {
+ if (item->xid == xid) {
+ last->next = item->next;
+ free(item);
+ item = last->next;
+ } else {
+ last = item;
+ item = item->next;
+ }
+ }
+}
+
+/**
+ * get_dhcp_packet_type - gets the message type of a dhcp packet
+ * p - pointer to the dhcp packet
+ * returns the message type on success, -1 otherwise
+ */
+static int get_dhcp_packet_type(struct dhcpMessage *p)
+{
+ uint8_t *op;
+
+ /* it must be either a BOOTREQUEST or a BOOTREPLY */
+ if (p->op != BOOTREQUEST && p->op != BOOTREPLY)
+ return -1;
+ /* get message type option */
+ op = get_option(p, DHCP_MESSAGE_TYPE);
+ if (op != NULL)
+ return op[0];
+ return -1;
+}
+
+/**
+ * get_client_devices - parses the devices list
+ * dev_list - comma separated list of devices
+ * returns array
+ */
+static char **get_client_devices(char *dev_list, int *client_number)
+{
+ char *s, **client_dev;
+ int i, cn;
+
+ /* copy list */
+ dev_list = xstrdup(dev_list);
+
+ /* get number of items, replace ',' with NULs */
+ s = dev_list;
+ cn = 1;
+ while (*s) {
+ if (*s == ',') {
+ *s = '\0';
+ cn++;
+ }
+ s++;
+ }
+ *client_number = cn;
+
+ /* create vector of pointers */
+ client_dev = xzalloc(cn * sizeof(*client_dev));
+ client_dev[0] = dev_list;
+ i = 1;
+ while (i != cn) {
+ client_dev[i] = client_dev[i - 1] + strlen(client_dev[i - 1]) + 1;
+ i++;
+ }
+ return client_dev;
+}
+
+
+/* Creates listen sockets (in fds) bound to client and server ifaces,
+ * and returns numerically max fd.
+ */
+static int init_sockets(char **client_ifaces, int num_clients,
+ char *server_iface, int *fds)
+{
+ int i, n;
+
+ /* talk to real server on bootps */
+ fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_iface);
+ n = fds[0];
+
+ for (i = 1; i < num_clients; i++) {
+ /* listen for clients on bootps */
+ fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client_ifaces[i-1]);
+ if (fds[i] > n)
+ n = fds[i];
+ }
+ return n;
+}
+
+
+/**
+ * pass_to_server() - forwards dhcp packets from client to server
+ * p - packet to send
+ * client - number of the client
+ */
+static void pass_to_server(struct dhcpMessage *p, int packet_len, int client, int *fds,
+ struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
+{
+ int res, type;
+ struct xid_item *item;
+
+ /* check packet_type */
+ type = get_dhcp_packet_type(p);
+ if (type != DHCPDISCOVER && type != DHCPREQUEST
+ && type != DHCPDECLINE && type != DHCPRELEASE
+ && type != DHCPINFORM
+ ) {
+ return;
+ }
+
+ /* create new xid entry */
+ item = xid_add(p->xid, client_addr, client);
+
+ /* forward request to LAN (server) */
+ errno = 0;
+ res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr,
+ sizeof(struct sockaddr_in));
+ if (res != packet_len) {
+ bb_perror_msg("sendto");
+ }
+}
+
+/**
+ * pass_to_client() - forwards dhcp packets from server to client
+ * p - packet to send
+ */
+static void pass_to_client(struct dhcpMessage *p, int packet_len, int *fds)
+{
+ int res, type;
+ struct xid_item *item;
+
+ /* check xid */
+ item = xid_find(p->xid);
+ if (!item) {
+ return;
+ }
+
+ /* check packet type */
+ type = get_dhcp_packet_type(p);
+ if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) {
+ return;
+ }
+
+ if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
+ item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+ errno = 0;
+ res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*) &(item->ip),
+ sizeof(item->ip));
+ if (res != packet_len) {
+ bb_perror_msg("sendto");
+ return;
+ }
+
+ /* remove xid entry */
+ xid_del(p->xid);
+}
+
+int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dhcprelay_main(int argc, char **argv)
+{
+ struct dhcpMessage dhcp_msg;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in client_addr;
+ fd_set rfds;
+ char **client_ifaces;
+ int *fds;
+ int num_sockets, max_socket;
+ uint32_t our_ip;
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(SERVER_PORT);
+
+ /* dhcprelay client_iface1,client_iface2,... server_iface [server_IP] */
+ if (argc == 4) {
+ if (!inet_aton(argv[3], &server_addr.sin_addr))
+ bb_perror_msg_and_die("bad server IP");
+ } else if (argc == 3) {
+ server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+ } else {
+ bb_show_usage();
+ }
+
+ /* Produce list of client ifaces */
+ client_ifaces = get_client_devices(argv[1], &num_sockets);
+
+ num_sockets++; /* for server socket at fds[0] */
+ fds = xmalloc(num_sockets * sizeof(fds[0]));
+
+ /* Create sockets and bind one to every iface */
+ max_socket = init_sockets(client_ifaces, num_sockets, argv[2], fds);
+
+ /* Get our IP on server_iface */
+ if (udhcp_read_interface(argv[2], NULL, &our_ip, NULL))
+ return 1;
+
+ /* Main loop */
+ while (1) {
+//reinit stuff from time to time? go back to get_client_devices
+//every N minutes?
+ struct timeval tv;
+ size_t packlen;
+ socklen_t addr_size;
+ int i;
+
+ FD_ZERO(&rfds);
+ for (i = 0; i < num_sockets; i++)
+ FD_SET(fds[i], &rfds);
+ tv.tv_sec = SELECT_TIMEOUT;
+ tv.tv_usec = 0;
+ if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
+ /* server */
+ if (FD_ISSET(fds[0], &rfds)) {
+ packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
+ if (packlen > 0) {
+ pass_to_client(&dhcp_msg, packlen, fds);
+ }
+ }
+ /* clients */
+ for (i = 1; i < num_sockets; i++) {
+ if (!FD_ISSET(fds[i], &rfds))
+ continue;
+ addr_size = sizeof(struct sockaddr_in);
+ packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
+ (struct sockaddr *)(&client_addr), &addr_size);
+ if (packlen <= 0)
+ continue;
+
+ /* Get our IP on corresponding client_iface */
+//why? what if server can't route such IP?
+ if (udhcp_read_interface(client_ifaces[i-1], NULL, &dhcp_msg.giaddr, NULL)) {
+ /* Fall back to our server_iface's IP */
+//this makes more sense!
+ dhcp_msg.giaddr = our_ip;
+ }
+//maybe set dhcp_msg.flags |= BROADCAST_FLAG too?
+ pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr);
+ }
+ }
+ xid_expire();
+ } /* while (1) */
+
+ /* return 0; - not reached */
+}
diff --git a/release/src/router/busybox/networking/udhcp/domain_codec.c b/release/src/router/busybox/networking/udhcp/domain_codec.c
new file mode 100644
index 00000000..6f051c4b
--- /dev/null
+++ b/release/src/router/busybox/networking/udhcp/domain_codec.c
@@ -0,0 +1,205 @@
+/* vi: set sw=4 ts=4: */
+
+/* RFC1035 domain compression routines (C) 2007 Gabriel Somlo <somlo at cmu.edu>
+ *
+ * Loosely based on the isc-dhcpd implementation by dhankins@isc.org
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#if ENABLE_FEATURE_UDHCP_RFC3397
+
+#include "common.h"
+#include "options.h"
+
+#define NS_MAXDNAME 1025 /* max domain name length */
+#define NS_MAXCDNAME 255 /* max compressed domain name length */
+#define NS_MAXLABEL 63 /* max label length */
+#define NS_MAXDNSRCH 6 /* max domains in search path */
+#define NS_CMPRSFLGS 0xc0 /* name compression pointer flag */
+
+
+/* expand a RFC1035-compressed list of domain names "cstr", of length "clen";
+ * returns a newly allocated string containing the space-separated domains,
+ * prefixed with the contents of string pre, or NULL if an error occurs.
+ */
+char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
+{
+ const uint8_t *c;
+ int crtpos, retpos, depth, plen = 0, len = 0;
+ char *dst = NULL;
+
+ if (!cstr)
+ return NULL;
+
+ if (pre)
+ plen = strlen(pre);
+
+ /* We make two passes over the cstr string. First, we compute
+ * how long the resulting string would be. Then we allocate a
+ * new buffer of the required length, and fill it in with the
+ * expanded content. The advantage of this approach is not
+ * having to deal with requiring callers to supply their own
+ * buffer, then having to check if it's sufficiently large, etc.
+ */
+
+ while (!dst) {
+
+ if (len > 0) { /* second pass? allocate dst buffer and copy pre */
+ dst = xmalloc(len + plen);
+ memcpy(dst, pre, plen);
+ }
+
+ crtpos = retpos = depth = len = 0;
+
+ while (crtpos < clen) {
+ c = cstr + crtpos;
+
+ if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */
+ if (crtpos + 2 > clen) /* no offset to jump to? abort */
+ return NULL;
+ if (retpos == 0) /* toplevel? save return spot */
+ retpos = crtpos + 2;
+ depth++;
+ crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */
+ } else if (*c) { /* label */
+ if (crtpos + *c + 1 > clen) /* label too long? abort */
+ return NULL;
+ if (dst)
+ memcpy(dst + plen + len, c + 1, *c);
+ len += *c + 1;
+ crtpos += *c + 1;
+ if (dst)
+ *(dst + plen + len - 1) = '.';
+ } else { /* null: end of current domain name */
+ if (retpos == 0) { /* toplevel? keep going */
+ crtpos++;
+ } else { /* return to toplevel saved spot */
+ crtpos = retpos;
+ retpos = depth = 0;
+ }
+ if (dst)
+ *(dst + plen + len - 1) = ' ';
+ }
+
+ if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */
+ len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */
+ return NULL;
+ }
+
+ if (!len) /* expanded string has 0 length? abort */
+ return NULL;
+
+ if (dst)
+ *(dst + plen + len - 1) = '\0';
+ }
+
+ return dst;
+}
+
+/* Convert a domain name (src) from human-readable "foo.blah.com" format into
+ * RFC1035 encoding "\003foo\004blah\003com\000". Return allocated string, or
+ * NULL if an error occurs.
+ */
+static uint8_t *convert_dname(const char *src)
+{
+ uint8_t c, *res, *lp, *rp;
+ int len;
+
+ res = xmalloc(strlen(src) + 2);
+ rp = lp = res;
+ rp++;
+
+ for (;;) {
+ c = (uint8_t)*src++;
+ if (c == '.' || c == '\0') { /* end of label */
+ len = rp - lp - 1;
+ /* label too long, too short, or two '.'s in a row? abort */
+ if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) {
+ free(res);
+ return NULL;
+ }
+ *lp = len;
+ lp = rp++;
+ if (c == '\0' || *src == '\0') /* end of dname */
+ break;
+ } else {
+ if (c >= 0x41 && c <= 0x5A) /* uppercase? convert to lower */
+ c += 0x20;
+ *rp++ = c;
+ }
+ }
+
+ *lp = 0;
+ if (rp - res > NS_MAXCDNAME) { /* dname too long? abort */
+ free(res);
+ return NULL;
+ }
+ return res;
+}
+
+/* returns the offset within cstr at which dname can be found, or -1
+ */
+static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
+{
+ const uint8_t *c, *d;
+ int off, inc;
+
+ /* find all labels in cstr */
+ off = 0;
+ while (off < clen) {
+ c = cstr + off;
+
+ if ((*c & NS_CMPRSFLGS) != 0) { /* pointer, skip */
+ off += 2;
+ } else if (*c) { /* label, try matching dname */
+ inc = *c + 1;
+ d = dname;
+ while (*c == *d && memcmp(c + 1, d + 1, *c) == 0) {
+ if (*c == 0) /* match, return offset */
+ return off;
+ d += *c + 1;
+ c += *c + 1;
+ if ((*c & NS_CMPRSFLGS) != 0) /* pointer, jump */
+ c = cstr + (((*c & 0x3f) << 8) | (*(c + 1) & 0xff));
+ }
+ off += inc;
+ } else { /* null, skip */
+ off++;
+ }
+ }
+
+ return -1;
+}
+
+/* computes string to be appended to cstr so that src would be added to
+ * the compression (best case, it's a 2-byte pointer to some offset within
+ * cstr; worst case, it's all of src, converted to rfc3011 format).
+ * The computed string is returned directly; its length is returned via retlen;
+ * NULL and 0, respectively, are returned if an error occurs.
+ */
+uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)
+{
+ uint8_t *d, *dname;
+ int off;
+
+ dname = convert_dname(src);
+ if (dname == NULL) {
+ *retlen = 0;
+ return NULL;
+ }
+
+ for (d = dname; *d != 0; d += *d + 1) {
+ off = find_offset(cstr, clen, d);
+ if (off >= 0) { /* found a match, add pointer and terminate string */
+ *d++ = NS_CMPRSFLGS;
+ *d = off;
+ break;
+ }
+ }
+
+ *retlen = d - dname + 1;
+ return dname;
+}
+
+#endif /* ENABLE_FEATURE_UDHCP_RFC3397 */
diff --git a/release/src/router/busybox/networking/udhcp/dumpleases.c b/release/src/router/busybox/networking/udhcp/dumpleases.c
index 4c6107cf..1558f884 100644
--- a/release/src/router/busybox/networking/udhcp/dumpleases.c
+++ b/release/src/router/busybox/networking/udhcp/dumpleases.c
@@ -1,88 +1,93 @@
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <time.h>
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
-#include "leases.h"
-#include "busybox.h"
+#include "common.h"
+#include "dhcpd.h"
+
+#if BB_LITTLE_ENDIAN
+static inline uint64_t hton64(uint64_t v)
+{
+ return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32);
+}
+#else
+#define hton64(v) (v)
+#endif
+#define ntoh64(v) hton64(v)
-#define REMAINING 0
-#define ABSOLUTE 1
-int dumpleases_main(int argc, char *argv[])
+int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dumpleases_main(int argc UNUSED_PARAM, char **argv)
{
- FILE *fp;
- int i, c, mode = REMAINING;
- long expires;
- const char *file = leases_file;
+ int fd;
+ int i;
+ unsigned opt;
+ int64_t written_at, curr, expires_abs;
+ const char *file = LEASES_FILE;
struct dhcpOfferedAddr lease;
struct in_addr addr;
-
- static const struct option options[] = {
- {"absolute", 0, 0, 'a'},
- {"remaining", 0, 0, 'r'},
- {"file", 1, 0, 'f'},
- {0, 0, 0, 0}
+
+ enum {
+ OPT_a = 0x1, // -a
+ OPT_r = 0x2, // -r
+ OPT_f = 0x4, // -f
};
+#if ENABLE_GETOPT_LONG
+ static const char dumpleases_longopts[] ALIGN1 =
+ "absolute\0" No_argument "a"
+ "remaining\0" No_argument "r"
+ "file\0" Required_argument "f"
+ ;
- while (1) {
- int option_index = 0;
- c = getopt_long(argc, argv, "arf:", options, &option_index);
- if (c == -1) break;
-
- switch (c) {
- case 'a': mode = ABSOLUTE; break;
- case 'r': mode = REMAINING; break;
- case 'f':
- file = optarg;
- break;
- default:
- bb_show_usage();
- }
- }
-
- fp = bb_xfopen(file, "r");
+ applet_long_options = dumpleases_longopts;
+#endif
+ opt_complementary = "=0:a--r:r--a";
+ opt = getopt32(argv, "arf:", &file);
- printf("Mac Address IP-Address Expires %s\n", mode == REMAINING ? "in" : "at");
- /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
- while (fread(&lease, sizeof(lease), 1, fp)) {
+ fd = xopen(file, O_RDONLY);
+ printf("Mac Address IP Address Host Name Expires %s\n", (opt & OPT_a) ? "at" : "in");
+ /* "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */
+ /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */
+
+ if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
+ return 0;
+ written_at = ntoh64(written_at);
+ curr = time(NULL);
+ if (curr < written_at)
+ written_at = curr; /* lease file from future! :) */
+
+ while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
+ const char *fmt = ":%02x" + 1;
for (i = 0; i < 6; i++) {
- printf("%02x", lease.chaddr[i]);
- if (i != 5) printf(":");
+ printf(fmt, lease.chaddr[i]);
+ fmt = ":%02x";
}
addr.s_addr = lease.yiaddr;
- printf(" %-15s", inet_ntoa(addr));
- expires = ntohl(lease.expires);
- printf(" ");
- if (mode == REMAINING) {
- if (!expires) printf("expired\n");
- else {
- if (expires > 60*60*24) {
- printf("%ld days, ", expires / (60*60*24));
- expires %= 60*60*24;
- }
- if (expires > 60*60) {
- printf("%ld hours, ", expires / (60*60));
- expires %= 60*60;
- }
- if (expires > 60) {
- printf("%ld minutes, ", expires / 60);
- expires %= 60;
- }
- printf("%ld seconds\n", expires);
- }
- } else printf("%s", ctime(&expires));
+ /* actually, 15+1 and 19+1, +1 is a space between columns */
+ /* lease.hostname is char[20] and is always NUL terminated */
+ printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname);
+ expires_abs = ntohl(lease.expires) + written_at;
+ if (expires_abs <= curr) {
+ puts("expired");
+ continue;
+ }
+ if (!(opt & OPT_a)) { /* no -a */
+ unsigned d, h, m;
+ unsigned expires = expires_abs - curr;
+ d = expires / (24*60*60); expires %= (24*60*60);
+ h = expires / (60*60); expires %= (60*60);
+ m = expires / 60; expires %= 60;
+ if (d)
+ printf("%u days ", d);
+ printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
+ } else { /* -a */
+ time_t t = expires_abs;
+ fputs(ctime(&t), stdout);
+ }
}
- fclose(fp);
-
+ /* close(fd); */
+
return 0;
}
diff --git a/release/src/router/busybox/networking/udhcp/files.c b/release/src/router/busybox/networking/udhcp/files.c
index 3d0344b0..55f35978 100644
--- a/release/src/router/busybox/networking/udhcp/files.c
+++ b/release/src/router/busybox/networking/udhcp/files.c
@@ -1,287 +1,433 @@
-/*
+/* vi: set sw=4 ts=4: */
+/*
* files.c -- DHCP server file manipulation *
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <ctype.h>
+#include <netinet/ether.h>
+
+#include "common.h"
#include "dhcpd.h"
-#include "files.h"
#include "options.h"
-#include "common.h"
-/* on these functions, make sure you datatype matches */
+#if BB_LITTLE_ENDIAN
+static inline uint64_t hton64(uint64_t v)
+{
+ return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32);
+}
+#else
+#define hton64(v) (v)
+#endif
+#define ntoh64(v) hton64(v)
+
+
+/* on these functions, make sure your datatype matches */
static int read_ip(const char *line, void *arg)
{
- struct in_addr *addr = arg;
- struct hostent *host;
- int retval = 1;
-
- if (!inet_aton(line, addr)) {
- if ((host = gethostbyname(line)))
- addr->s_addr = *((unsigned long *) host->h_addr_list[0]);
- else retval = 0;
- }
- return retval;
+ len_and_sockaddr *lsa;
+
+ lsa = host_and_af2sockaddr(line, 0, AF_INET);
+ if (!lsa)
+ return 0;
+ *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr;
+ free(lsa);
+ return 1;
+}
+
+
+static int read_mac(const char *line, void *arg)
+{
+ return NULL == ether_aton_r(line, (struct ether_addr *)arg);
}
static int read_str(const char *line, void *arg)
{
char **dest = arg;
-
- if (*dest) free(*dest);
- *dest = strdup(line);
-
+
+ free(*dest);
+ *dest = xstrdup(line);
return 1;
}
static int read_u32(const char *line, void *arg)
{
- u_int32_t *dest = arg;
- char *endptr;
- *dest = strtoul(line, &endptr, 0);
- return endptr[0] == '\0';
+ *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
+ return errno == 0;
}
static int read_yn(const char *line, void *arg)
{
char *dest = arg;
- int retval = 1;
- if (!strcasecmp("yes", line))
+ if (!strcasecmp("yes", line)) {
*dest = 1;
- else if (!strcasecmp("no", line))
+ return 1;
+ }
+ if (!strcasecmp("no", line)) {
*dest = 0;
- else retval = 0;
-
- return retval;
+ return 1;
+ }
+ return 0;
+}
+
+
+/* find option 'code' in opt_list */
+struct option_set* FAST_FUNC find_option(struct option_set *opt_list, uint8_t code)
+{
+ while (opt_list && opt_list->data[OPT_CODE] < code)
+ opt_list = opt_list->next;
+
+ if (opt_list && opt_list->data[OPT_CODE] == code)
+ return opt_list;
+ return NULL;
+}
+
+
+/* add an option to the opt_list */
+static void attach_option(struct option_set **opt_list,
+ const struct dhcp_option *option, char *buffer, int length)
+{
+ struct option_set *existing, *new, **curr;
+
+ existing = find_option(*opt_list, option->code);
+ if (!existing) {
+ DEBUG("Attaching option %02x to list", option->code);
+
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ if ((option->flags & TYPE_MASK) == OPTION_STR1035)
+ /* reuse buffer and length for RFC1035-formatted string */
+ buffer = (char *)dname_enc(NULL, 0, buffer, &length);
+#endif
+
+ /* make a new option */
+ new = xmalloc(sizeof(*new));
+ new->data = xmalloc(length + 2);
+ new->data[OPT_CODE] = option->code;
+ new->data[OPT_LEN] = length;
+ memcpy(new->data + 2, buffer, length);
+
+ curr = opt_list;
+ while (*curr && (*curr)->data[OPT_CODE] < option->code)
+ curr = &(*curr)->next;
+
+ new->next = *curr;
+ *curr = new;
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
+ free(buffer);
+#endif
+ return;
+ }
+
+ /* add it to an existing option */
+ DEBUG("Attaching option %02x to existing member of list", option->code);
+ if (option->flags & OPTION_LIST) {
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ if ((option->flags & TYPE_MASK) == OPTION_STR1035)
+ /* reuse buffer and length for RFC1035-formatted string */
+ buffer = (char *)dname_enc(existing->data + 2,
+ existing->data[OPT_LEN], buffer, &length);
+#endif
+ if (existing->data[OPT_LEN] + length <= 255) {
+ existing->data = xrealloc(existing->data,
+ existing->data[OPT_LEN] + length + 3);
+ if ((option->flags & TYPE_MASK) == OPTION_STRING) {
+ /* ' ' can bring us to 256 - bad */
+ if (existing->data[OPT_LEN] + length >= 255)
+ return;
+ /* add space separator between STRING options in a list */
+ existing->data[existing->data[OPT_LEN] + 2] = ' ';
+ existing->data[OPT_LEN]++;
+ }
+ memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
+ existing->data[OPT_LEN] += length;
+ } /* else, ignore the data, we could put this in a second option in the future */
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
+ free(buffer);
+#endif
+ } /* else, ignore the new data */
}
-#define READ_CONFIG_BUF_SIZE 512 /* domainname may have 254 chars */
/* read a dhcp option and add it to opt_list */
static int read_opt(const char *const_line, void *arg)
{
- char line[READ_CONFIG_BUF_SIZE];
struct option_set **opt_list = arg;
char *opt, *val, *endptr;
- struct dhcp_option *option;
- int retval = 0, length;
- char buffer[256]; /* max opt length */
- u_int16_t result_u16;
- u_int32_t result_u32;
- void *valptr;
-
- if ((opt = strtok(strcpy(line, const_line), " \t="))) {
-
- for (option = options; option->code; option++)
- if (!strcasecmp(option->name, opt))
- break;
-
- if (option->code) do {
+ char *line;
+ const struct dhcp_option *option;
+ int retval, length, idx;
+ char buffer[8] ALIGNED(4);
+ uint16_t *result_u16 = (uint16_t *) buffer;
+ uint32_t *result_u32 = (uint32_t *) buffer;
+
+ /* Cheat, the only const line we'll actually get is "" */
+ line = (char *) const_line;
+ opt = strtok(line, " \t=");
+ if (!opt)
+ return 0;
+
+ idx = index_in_strings(dhcp_option_strings, opt); /* NB: was strcasecmp! */
+ if (idx < 0)
+ return 0;
+ option = &dhcp_options[idx];
+
+ retval = 0;
+ do {
val = strtok(NULL, ", \t");
- if(!val)
+ if (!val) break;
+ length = dhcp_option_lengths[option->flags & TYPE_MASK];
+ retval = 0;
+ opt = buffer; /* new meaning for variable opt */
+ switch (option->flags & TYPE_MASK) {
+ case OPTION_IP:
+ retval = read_ip(val, buffer);
break;
- length = option_lengths[option->flags & TYPE_MASK];
- valptr = NULL;
- switch (option->flags & TYPE_MASK) {
- case OPTION_IP:
- retval = read_ip(val, buffer);
- break;
- case OPTION_IP_PAIR:
- retval = read_ip(val, buffer);
- if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
- if (retval) retval = read_ip(val, buffer + 4);
- break;
- case OPTION_STRING:
- length = strlen(val);
- if (length > 0) {
- if (length > 254) length = 254;
- endptr = buffer + length;
- endptr[0] = 0;
- valptr = val;
- }
- break;
- case OPTION_BOOLEAN:
- retval = read_yn(val, buffer);
- break;
- case OPTION_U8:
- buffer[0] = strtoul(val, &endptr, 0);
- valptr = buffer;
- break;
- case OPTION_U16:
- result_u16 = htons(strtoul(val, &endptr, 0));
- valptr = &result_u16;
- break;
- case OPTION_S16:
- result_u16 = htons(strtol(val, &endptr, 0));
- valptr = &result_u16;
- break;
- case OPTION_U32:
- result_u32 = htonl(strtoul(val, &endptr, 0));
- valptr = &result_u32;
- break;
- case OPTION_S32:
- result_u32 = htonl(strtol(val, &endptr, 0));
- valptr = &result_u32;
- break;
- default:
- retval = 0;
- break;
+ case OPTION_IP_PAIR:
+ retval = read_ip(val, buffer);
+ val = strtok(NULL, ", \t/-");
+ if (!val)
+ retval = 0;
+ if (retval)
+ retval = read_ip(val, buffer + 4);
+ break;
+ case OPTION_STRING:
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ case OPTION_STR1035:
+#endif
+ length = strlen(val);
+ if (length > 0) {
+ if (length > 254) length = 254;
+ opt = val;
+ retval = 1;
}
- if(valptr) {
- memcpy(buffer, valptr, length);
+ break;
+ case OPTION_BOOLEAN:
+ retval = read_yn(val, buffer);
+ break;
+ case OPTION_U8:
+ buffer[0] = strtoul(val, &endptr, 0);
+ retval = (endptr[0] == '\0');
+ break;
+ /* htonX are macros in older libc's, using temp var
+ * in code below for safety */
+ /* TODO: use bb_strtoX? */
+ case OPTION_U16: {
+ unsigned long tmp = strtoul(val, &endptr, 0);
+ *result_u16 = htons(tmp);
+ retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/);
+ break;
+ }
+ case OPTION_S16: {
+ long tmp = strtol(val, &endptr, 0);
+ *result_u16 = htons(tmp);
+ retval = (endptr[0] == '\0');
+ break;
+ }
+ case OPTION_U32: {
+ unsigned long tmp = strtoul(val, &endptr, 0);
+ *result_u32 = htonl(tmp);
retval = (endptr[0] == '\0');
+ break;
}
- if (retval)
- attach_option(opt_list, option, buffer, length);
- else
+ case OPTION_S32: {
+ long tmp = strtol(val, &endptr, 0);
+ *result_u32 = htonl(tmp);
+ retval = (endptr[0] == '\0');
break;
- } while (option->flags & OPTION_LIST);
- }
+ }
+ default:
+ break;
+ }
+ if (retval)
+ attach_option(opt_list, option, opt, length);
+ } while (retval && option->flags & OPTION_LIST);
return retval;
}
+static int read_staticlease(const char *const_line, void *arg)
+{
+ char *line;
+ char *mac_string;
+ char *ip_string;
+ struct ether_addr mac_bytes;
+ uint32_t ip;
-static const struct config_keyword keywords[] = {
- /* keyword handler variable address default */
- {"start", read_ip, &(server_config.start), "192.168.0.20"},
- {"end", read_ip, &(server_config.end), "192.168.0.254"},
- {"interface", read_str, &(server_config.interface), "eth0"},
- {"option", read_opt, &(server_config.options), ""},
- {"opt", read_opt, &(server_config.options), ""},
- {"max_leases", read_u32, &(server_config.max_leases), "254"},
- {"remaining", read_yn, &(server_config.remaining), "yes"},
- {"auto_time", read_u32, &(server_config.auto_time), "7200"},
- {"decline_time",read_u32, &(server_config.decline_time),"3600"},
- {"conflict_time",read_u32,&(server_config.conflict_time),"3600"},
- {"offer_time", read_u32, &(server_config.offer_time), "60"},
- {"min_lease", read_u32, &(server_config.min_lease), "60"},
- {"lease_file", read_str, &(server_config.lease_file), leases_file},
- {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"},
- {"notify_file", read_str, &(server_config.notify_file), ""},
- {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"},
- {"sname", read_str, &(server_config.sname), ""},
- {"boot_file", read_str, &(server_config.boot_file), ""},
- /*ADDME: static lease */
- {"", NULL, NULL, ""}
+ /* Read mac */
+ line = (char *) const_line;
+ mac_string = strtok_r(line, " \t", &line);
+ read_mac(mac_string, &mac_bytes);
+
+ /* Read ip */
+ ip_string = strtok_r(NULL, " \t", &line);
+ read_ip(ip_string, &ip);
+
+ addStaticLease(arg, (uint8_t*) &mac_bytes, ip);
+
+ if (ENABLE_UDHCP_DEBUG) printStaticLeases(arg);
+
+ return 1;
+}
+
+
+struct config_keyword {
+ const char *keyword;
+ int (*handler)(const char *line, void *var);
+ void *var;
+ const char *def;
};
+static const struct config_keyword keywords[] = {
+ /* keyword handler variable address default */
+ {"start", read_ip, &(server_config.start_ip), "192.168.0.20"},
+ {"end", read_ip, &(server_config.end_ip), "192.168.0.254"},
+ {"interface", read_str, &(server_config.interface), "eth0"},
+ /* Avoid "max_leases value not sane" warning by setting default
+ * to default_end_ip - default_start_ip + 1: */
+ {"max_leases", read_u32, &(server_config.max_leases), "235"},
+// {"remaining", read_yn, &(server_config.remaining), "yes"},
+ {"auto_time", read_u32, &(server_config.auto_time), "7200"},
+ {"decline_time", read_u32, &(server_config.decline_time), "3600"},
+ {"conflict_time",read_u32, &(server_config.conflict_time),"3600"},
+ {"offer_time", read_u32, &(server_config.offer_time), "60"},
+ {"min_lease", read_u32, &(server_config.min_lease), "60"},
+ {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE},
+ {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"},
+ {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"},
+ /* keywords with no defaults must be last! */
+ {"option", read_opt, &(server_config.options), ""},
+ {"opt", read_opt, &(server_config.options), ""},
+ {"notify_file", read_str, &(server_config.notify_file), ""},
+ {"sname", read_str, &(server_config.sname), ""},
+ {"boot_file", read_str, &(server_config.boot_file), ""},
+ {"static_lease", read_staticlease, &(server_config.static_leases), ""},
+};
+enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
-int read_config(const char *file)
+void FAST_FUNC read_config(const char *file)
{
- FILE *in;
- char buffer[READ_CONFIG_BUF_SIZE], orig[READ_CONFIG_BUF_SIZE];
- char *token, *line;
- int i;
+ parser_t *parser;
+ const struct config_keyword *k;
+ unsigned i;
+ char *token[2];
- for (i = 0; keywords[i].keyword[0]; i++)
- if (keywords[i].def[0])
- keywords[i].handler(keywords[i].def, keywords[i].var);
+ for (i = 0; i < KWS_WITH_DEFAULTS; i++)
+ keywords[i].handler(keywords[i].def, keywords[i].var);
- if (!(in = fopen(file, "r"))) {
- LOG(LOG_ERR, "unable to open config file: %s", file);
- return 0;
- }
-
- while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
- if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
- strcpy(orig, buffer);
- if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0';
- token = strtok(buffer, " \t");
- if(!token)
- continue;
- line = strtok(NULL, "");
- if(!line)
- continue;
- while(*line == '=' || isspace(*line))
- line++;
- /* eat trailing whitespace */
- for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--);
- line[i] = '\0';
- if (*line == '\0')
- continue;
-
- for (i = 0; keywords[i].keyword[0]; i++)
- if (!strcasecmp(token, keywords[i].keyword))
- if (!keywords[i].handler(line, keywords[i].var)) {
- LOG(LOG_ERR, "unable to parse '%s'", orig);
+ parser = config_open(file);
+ while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
+ for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
+ if (!strcasecmp(token[0], k->keyword)) {
+ if (!k->handler(token[1], k->var)) {
+ bb_error_msg("can't parse line %u in %s",
+ parser->lineno, file);
/* reset back to the default value */
- keywords[i].handler(keywords[i].def, keywords[i].var);
+ k->handler(k->def, k->var);
}
+ break;
+ }
+ }
}
- fclose(in);
- return 1;
+ config_close(parser);
+
+ server_config.start_ip = ntohl(server_config.start_ip);
+ server_config.end_ip = ntohl(server_config.end_ip);
}
-void write_leases(void)
+void FAST_FUNC write_leases(void)
{
- FILE *fp;
- unsigned int i;
- char buf[255];
- time_t curr = time(0);
- unsigned long lease_time;
-
- if (!(fp = fopen(server_config.lease_file, "w"))) {
- LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
+ int fd;
+ unsigned i;
+ leasetime_t curr;
+ int64_t written_at;
+
+ fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
+ if (fd < 0)
return;
- }
-
+
+ curr = written_at = time(NULL);
+
+ written_at = hton64(written_at);
+ full_write(fd, &written_at, sizeof(written_at));
+
for (i = 0; i < server_config.max_leases; i++) {
- struct dhcpOfferedAddr lease;
- if (leases[i].yiaddr != 0) {
- if (server_config.remaining) {
- if (lease_expired(&(leases[i])))
- lease_time = 0;
- else lease_time = leases[i].expires - curr;
- } else lease_time = leases[i].expires;
- lease.expires = htonl(lease_time);
- memcpy(lease.chaddr, leases[i].chaddr, 16);
- lease.yiaddr = leases[i].yiaddr;
- fwrite(leases, sizeof(lease), 1, fp);
- }
+ leasetime_t tmp_time;
+
+ if (leases[i].yiaddr == 0)
+ continue;
+
+ /* Screw with the time in the struct, for easier writing */
+ tmp_time = leases[i].expires;
+
+ leases[i].expires -= curr;
+ if ((signed_leasetime_t) leases[i].expires < 0)
+ leases[i].expires = 0;
+ leases[i].expires = htonl(leases[i].expires);
+
+ /* No error check. If the file gets truncated,
+ * we lose some leases on restart. Oh well. */
+ full_write(fd, &leases[i], sizeof(leases[i]));
+
+ /* Then restore it when done */
+ leases[i].expires = tmp_time;
}
- fclose(fp);
-
+ close(fd);
+
if (server_config.notify_file) {
- sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file);
- system(buf);
+// TODO: vfork-based child creation
+ char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file);
+ system(cmd);
+ free(cmd);
}
}
-void read_leases(const char *file)
+void FAST_FUNC read_leases(const char *file)
{
- FILE *fp;
- unsigned int i = 0;
struct dhcpOfferedAddr lease;
-
- if (!(fp = fopen(file, "r"))) {
- LOG(LOG_ERR, "Unable to open %s for reading", file);
+ int64_t written_at, time_passed;
+ int fd;
+ USE_UDHCP_DEBUG(unsigned i;)
+
+ fd = open_or_warn(file, O_RDONLY);
+ if (fd < 0)
return;
- }
-
- while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) {
- /* ADDME: is it a static lease */
- if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) {
- lease.expires = ntohl(lease.expires);
- if (!server_config.remaining) lease.expires -= time(0);
- if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
- LOG(LOG_WARNING, "Too many leases while loading %s\n", file);
+
+ if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
+ goto ret;
+ written_at = ntoh64(written_at);
+
+ time_passed = time(NULL) - written_at;
+ /* Strange written_at, or lease file from old version of udhcpd
+ * which had no "written_at" field? */
+ if ((uint64_t)time_passed > 12 * 60 * 60)
+ goto ret;
+
+ USE_UDHCP_DEBUG(i = 0;)
+ while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
+ /* ADDME: what if it matches some static lease? */
+ uint32_t y = ntohl(lease.yiaddr);
+ if (y >= server_config.start_ip && y <= server_config.end_ip) {
+ signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
+ if (expires <= 0)
+ continue;
+ /* NB: add_lease takes "relative time", IOW,
+ * lease duration, not lease deadline. */
+ if (!(add_lease(lease.chaddr, lease.yiaddr, expires, NULL /* was lease.hostname. bug in add_lease, disabled */ ))) {
+ bb_error_msg("too many leases while loading %s", file);
break;
- }
- i++;
+ }
+ USE_UDHCP_DEBUG(i++;)
}
}
- DEBUG(LOG_INFO, "Read %d leases", i);
- fclose(fp);
+ DEBUG("Read %d leases", i);
+ ret:
+ close(fd);
}
diff --git a/release/src/router/busybox/networking/udhcp/files.h b/release/src/router/busybox/networking/udhcp/files.h
deleted file mode 100644
index 279738ad..00000000
--- a/release/src/router/busybox/networking/udhcp/files.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* files.h */
-#ifndef _FILES_H
-#define _FILES_H
-
-struct config_keyword {
- const char *keyword;
- int (* const handler)(const char *line, void *var);
- void *var;
- const char *def;
-};
-
-
-int read_config(const char *file);
-void write_leases(void);
-void read_leases(const char *file);
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/frontend.c b/release/src/router/busybox/networking/udhcp/frontend.c
deleted file mode 100644
index de577950..00000000
--- a/release/src/router/busybox/networking/udhcp/frontend.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <string.h>
-
-extern int udhcpd_main(int argc, char *argv[]);
-extern int udhcpc_main(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
- int ret = 0;
- char *base = strrchr(argv[0], '/');
-
- if (strstr(base ? (base + 1) : argv[0], "dhcpd"))
- ret = udhcpd_main(argc, argv);
- else ret = udhcpc_main(argc, argv);
-
- return ret;
-}
diff --git a/release/src/router/busybox/networking/udhcp/leases.c b/release/src/router/busybox/networking/udhcp/leases.c
index 0b6b409c..e17fb9e3 100644
--- a/release/src/router/busybox/networking/udhcp/leases.c
+++ b/release/src/router/busybox/networking/udhcp/leases.c
@@ -1,149 +1,181 @@
-/*
- * leases.c -- tools to manage DHCP leases
+/* vi: set sw=4 ts=4: */
+/*
+ * leases.c -- tools to manage DHCP leases
* Russ Dill <Russ.Dill@asu.edu> July 2001
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <time.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "dhcpd.h"
-#include "files.h"
-#include "options.h"
-#include "arpping.h"
#include "common.h"
+#include "dhcpd.h"
-unsigned char blank_chaddr[] = {[0 ... 15] = 0};
+/* Find the oldest expired lease, NULL if there are no expired leases */
+static struct dhcpOfferedAddr *oldest_expired_lease(void)
+{
+ struct dhcpOfferedAddr *oldest_lease = NULL;
+ leasetime_t oldest_time = time(NULL);
+ unsigned i;
+
+ /* Unexpired leases have leases[i].expires >= current time
+ * and therefore can't ever match */
+ for (i = 0; i < server_config.max_leases; i++) {
+ if (leases[i].expires < oldest_time) {
+ oldest_time = leases[i].expires;
+ oldest_lease = &(leases[i]);
+ }
+ }
+ return oldest_lease;
+}
+
-/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
-void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr)
+/* Clear every lease out that chaddr OR yiaddr matches and is nonzero */
+static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
{
- unsigned int i, j;
-
- for (j = 0; j < 16 && !chaddr[j]; j++);
-
- for (i = 0; i < server_config.max_leases; i++)
- if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) ||
- (yiaddr && leases[i].yiaddr == yiaddr)) {
- memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
+ unsigned i, j;
+
+ for (j = 0; j < 16 && !chaddr[j]; j++)
+ continue;
+
+ for (i = 0; i < server_config.max_leases; i++) {
+ if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0)
+ || (yiaddr && leases[i].yiaddr == yiaddr)
+ ) {
+ memset(&(leases[i]), 0, sizeof(leases[i]));
}
+ }
}
-/* add a lease into the table, clearing out any old ones */
-struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease)
+/* Add a lease into the table, clearing out any old ones */
+struct dhcpOfferedAddr* FAST_FUNC add_lease(
+ const uint8_t *chaddr, uint32_t yiaddr,
+ leasetime_t leasetime, uint8_t *hostname)
{
struct dhcpOfferedAddr *oldest;
-
+ uint8_t hostname_length;
+
/* clean out any old ones */
clear_lease(chaddr, yiaddr);
-
+
oldest = oldest_expired_lease();
-
+
if (oldest) {
+ oldest->hostname[0] = '\0';
+ if (hostname) {
+ /* option size byte, + 1 for NUL */
+ hostname_length = hostname[-1] + 1;
+ if (hostname_length > sizeof(oldest->hostname))
+ hostname_length = sizeof(oldest->hostname);
+ hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length);
+ /* sanitization (s/non-ASCII/^/g) */
+ while (*hostname) {
+ if (*hostname < ' ' || *hostname > 126)
+ *hostname = '^';
+ hostname++;
+ }
+ }
memcpy(oldest->chaddr, chaddr, 16);
oldest->yiaddr = yiaddr;
- oldest->expires = time(0) + lease;
+ oldest->expires = time(NULL) + leasetime;
}
-
+
return oldest;
}
-/* true if a lease has expired */
-int lease_expired(struct dhcpOfferedAddr *lease)
+/* True if a lease has expired */
+int FAST_FUNC lease_expired(struct dhcpOfferedAddr *lease)
{
- return (lease->expires < (unsigned long) time(0));
-}
-
-
-/* Find the oldest expired lease, NULL if there are no expired leases */
-struct dhcpOfferedAddr *oldest_expired_lease(void)
-{
- struct dhcpOfferedAddr *oldest = NULL;
- unsigned long oldest_lease = time(0);
- unsigned int i;
-
-
- for (i = 0; i < server_config.max_leases; i++)
- if (oldest_lease > leases[i].expires) {
- oldest_lease = leases[i].expires;
- oldest = &(leases[i]);
- }
- return oldest;
-
+ return (lease->expires < (leasetime_t) time(NULL));
}
/* Find the first lease that matches chaddr, NULL if no match */
-struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr)
+struct dhcpOfferedAddr* FAST_FUNC find_lease_by_chaddr(const uint8_t *chaddr)
{
- unsigned int i;
+ unsigned i;
for (i = 0; i < server_config.max_leases; i++)
- if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
-
+ if (!memcmp(leases[i].chaddr, chaddr, 16))
+ return &(leases[i]);
+
return NULL;
}
/* Find the first lease that matches yiaddr, NULL is no match */
-struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr)
+struct dhcpOfferedAddr* FAST_FUNC find_lease_by_yiaddr(uint32_t yiaddr)
{
- unsigned int i;
+ unsigned i;
for (i = 0; i < server_config.max_leases; i++)
- if (leases[i].yiaddr == yiaddr) return &(leases[i]);
-
+ if (leases[i].yiaddr == yiaddr)
+ return &(leases[i]);
+
return NULL;
}
/* check is an IP is taken, if it is, add it to the lease table */
-static int check_ip(u_int32_t addr)
+static int nobody_responds_to_arp(uint32_t addr)
{
+ /* 16 zero bytes */
+ static const uint8_t blank_chaddr[16] = { 0 };
+ /* = { 0 } helps gcc to put it in rodata, not bss */
+
struct in_addr temp;
+ int r;
+
+ r = arpping(addr, server_config.server, server_config.arp, server_config.interface);
+ if (r)
+ return r;
- if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
- temp.s_addr = addr;
- LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
- inet_ntoa(temp), server_config.conflict_time);
- add_lease(blank_chaddr, addr, server_config.conflict_time);
- return 1;
- } else return 0;
+ temp.s_addr = addr;
+ bb_info_msg("%s belongs to someone, reserving it for %u seconds",
+ inet_ntoa(temp), (unsigned)server_config.conflict_time);
+ add_lease(blank_chaddr, addr, server_config.conflict_time, NULL);
+ return 0;
}
-/* find an assignable address, it check_expired is true, we check all the expired leases as well.
- * Maybe this should try expired leases by age... */
-u_int32_t find_address(int check_expired)
+
+/* Find a new usable (we think) address. */
+uint32_t FAST_FUNC find_free_or_expired_address(void)
{
- u_int32_t addr, ret;
- struct dhcpOfferedAddr *lease = NULL;
+ uint32_t addr;
+ struct dhcpOfferedAddr *oldest_lease = NULL;
- addr = ntohl(server_config.start); /* addr is in host order here */
- for (;addr <= ntohl(server_config.end); addr++) {
+ addr = server_config.start_ip; /* addr is in host order here */
+ for (; addr <= server_config.end_ip; addr++) {
+ uint32_t net_addr;
+ struct dhcpOfferedAddr *lease;
/* ie, 192.168.55.0 */
- if (!(addr & 0xFF)) continue;
-
+ if ((addr & 0xff) == 0)
+ continue;
/* ie, 192.168.55.255 */
- if ((addr & 0xFF) == 0xFF) continue;
-
- /* lease is not taken */
- ret = htonl(addr);
- if ((!(lease = find_lease_by_yiaddr(ret)) ||
-
- /* or it expired and we are checking for expired leases */
- (check_expired && lease_expired(lease))) &&
-
- /* and it isn't on the network */
- !check_ip(ret)) {
- return ret;
- break;
+ if ((addr & 0xff) == 0xff)
+ continue;
+ net_addr = htonl(addr);
+ /* addr has a static lease? */
+ if (reservedIp(server_config.static_leases, net_addr))
+ continue;
+
+ lease = find_lease_by_yiaddr(net_addr);
+ if (!lease) {
+ if (nobody_responds_to_arp(net_addr))
+ return net_addr;
+ } else {
+ if (!oldest_lease || lease->expires < oldest_lease->expires)
+ oldest_lease = lease;
}
}
+
+ if (oldest_lease && lease_expired(oldest_lease)
+ && nobody_responds_to_arp(oldest_lease->yiaddr)
+ ) {
+ return oldest_lease->yiaddr;
+ }
+
return 0;
}
diff --git a/release/src/router/busybox/networking/udhcp/leases.h b/release/src/router/busybox/networking/udhcp/leases.h
deleted file mode 100644
index d54cd11c..00000000
--- a/release/src/router/busybox/networking/udhcp/leases.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* leases.h */
-#ifndef _LEASES_H
-#define _LEASES_H
-
-
-struct dhcpOfferedAddr {
- u_int8_t chaddr[16];
- u_int32_t yiaddr; /* network order */
- u_int32_t expires; /* host order */
-};
-
-extern const char leases_file[];
-
-extern unsigned char blank_chaddr[];
-
-void clear_lease(u_int8_t *chaddr, u_int32_t yiaddr);
-struct dhcpOfferedAddr *add_lease(u_int8_t *chaddr, u_int32_t yiaddr, unsigned long lease);
-int lease_expired(struct dhcpOfferedAddr *lease);
-struct dhcpOfferedAddr *oldest_expired_lease(void);
-struct dhcpOfferedAddr *find_lease_by_chaddr(u_int8_t *chaddr);
-struct dhcpOfferedAddr *find_lease_by_yiaddr(u_int32_t yiaddr);
-u_int32_t find_address(int check_expired);
-
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/leases_file.c b/release/src/router/busybox/networking/udhcp/leases_file.c
deleted file mode 100644
index 96e2f2d1..00000000
--- a/release/src/router/busybox/networking/udhcp/leases_file.c
+++ /dev/null
@@ -1 +0,0 @@
-const char leases_file[] = "/var/lib/misc/udhcpd.leases";
diff --git a/release/src/router/busybox/networking/udhcp/libbb_udhcp.h b/release/src/router/busybox/networking/udhcp/libbb_udhcp.h
deleted file mode 100644
index e0942980..00000000
--- a/release/src/router/busybox/networking/udhcp/libbb_udhcp.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* libbb_udhcp.h - busybox compatability wrapper */
-
-#ifndef _LIBBB_UDHCP_H
-#define _LIBBB_UDHCP_H
-
-#ifdef IN_BUSYBOX
-#include "libbb.h"
-
-#ifdef CONFIG_FEATURE_UDHCP_SYSLOG
-#define SYSLOG
-#endif
-
-#ifdef CONFIG_FEATURE_UDHCP_DEBUG
-#define DEBUG
-#endif
-
-#define COMBINED_BINARY
-#include "version.h"
-
-#else /* ! BB_VER */
-
-#define TRUE 1
-#define FALSE 0
-
-#define xmalloc malloc
-
-#endif /* BB_VER */
-
-#endif /* _LIBBB_UDHCP_H */
diff --git a/release/src/router/busybox/networking/udhcp/options.c b/release/src/router/busybox/networking/udhcp/options.c
index a3edd0b8..143a1fd1 100644
--- a/release/src/router/busybox/networking/udhcp/options.c
+++ b/release/src/router/busybox/networking/udhcp/options.c
@@ -1,143 +1,211 @@
-/*
- * options.c -- DHCP server option packet tools
+/* vi: set sw=4 ts=4: */
+/*
+ * options.c -- DHCP server option packet tools
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-
-#include <stdlib.h>
-#include <string.h>
+#include "common.h"
#include "dhcpd.h"
-#include "files.h"
#include "options.h"
-#include "common.h"
-/* supported options are easily added here */
-struct dhcp_option options[] = {
- /* name[10] flags code */
- {"subnet", OPTION_IP | OPTION_REQ, 0x01},
- {"timezone", OPTION_S32, 0x02},
- {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03},
- {"timesvr", OPTION_IP | OPTION_LIST, 0x04},
- {"namesvr", OPTION_IP | OPTION_LIST, 0x05},
- {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06},
- {"logsvr", OPTION_IP | OPTION_LIST, 0x07},
- {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08},
- {"lprsvr", OPTION_IP | OPTION_LIST, 0x09},
- {"hostname", OPTION_STRING | OPTION_REQ, 0x0c},
- {"bootsize", OPTION_U16, 0x0d},
- {"domain", OPTION_STRING | OPTION_REQ, 0x0f},
- {"swapsvr", OPTION_IP, 0x10},
- {"rootpath", OPTION_STRING, 0x11},
- {"ipttl", OPTION_U8, 0x17},
- {"mtu", OPTION_U16, 0x1a},
- {"broadcast", OPTION_IP | OPTION_REQ, 0x1c},
- {"ntpsrv", OPTION_IP | OPTION_LIST, 0x2a},
- {"wins", OPTION_IP | OPTION_LIST, 0x2c},
- {"requestip", OPTION_IP, 0x32},
- {"lease", OPTION_U32, 0x33},
- {"dhcptype", OPTION_U8, 0x35},
- {"serverid", OPTION_IP, 0x36},
- {"message", OPTION_STRING, 0x38},
- {"tftp", OPTION_STRING, 0x42},
- {"bootfile", OPTION_STRING, 0x43},
- {"", 0x00, 0x00}
+/* Supported options are easily added here */
+const struct dhcp_option dhcp_options[] = {
+ /* flags code */
+ { OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */
+ { OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */
+ { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */
+ { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */
+ { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */
+ { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */
+ { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */
+ { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */
+ { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */
+ { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */
+ { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */
+ { OPTION_STRING | OPTION_LIST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */
+ { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */
+ { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */
+ { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
+ { OPTION_U16 , 0x1a }, /* DHCP_MTU */
+ { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
+ { OPTION_STRING , 0x28 }, /* nisdomain */
+ { OPTION_IP | OPTION_LIST , 0x29 }, /* nissrv */
+ { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
+ { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */
+ { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */
+ { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */
+ { OPTION_U8 , 0x35 }, /* dhcptype */
+ { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */
+ { OPTION_STRING , 0x38 }, /* DHCP_MESSAGE */
+ { OPTION_STRING , 0x3C }, /* DHCP_VENDOR */
+ { OPTION_STRING , 0x3D }, /* DHCP_CLIENT_ID */
+ { OPTION_STRING , 0x42 }, /* tftp */
+ { OPTION_STRING , 0x43 }, /* bootfile */
+ { OPTION_STRING , 0x4D }, /* userclass */
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ { OPTION_STR1035 | OPTION_LIST , 0x77 }, /* search */
+#endif
+ /* MSIE's "Web Proxy Autodiscovery Protocol" support */
+ { OPTION_STRING , 0xfc }, /* wpad */
+
+ /* Options below have no match in dhcp_option_strings[],
+ * are not passed to dhcpc scripts, and cannot be specified
+ * with "option XXX YYY" syntax in dhcpd config file. */
+
+ { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */
+ { } /* zeroed terminating entry */
};
+/* Used for converting options from incoming packets to env variables
+ * for udhcpc stript */
+/* Must match dhcp_options[] order */
+const char dhcp_option_strings[] ALIGN1 =
+ "subnet" "\0" /* DHCP_SUBNET */
+ "timezone" "\0" /* DHCP_TIME_OFFSET */
+ "router" "\0" /* DHCP_ROUTER */
+ "timesrv" "\0" /* DHCP_TIME_SERVER */
+ "namesrv" "\0" /* DHCP_NAME_SERVER */
+ "dns" "\0" /* DHCP_DNS_SERVER */
+ "logsrv" "\0" /* DHCP_LOG_SERVER */
+ "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */
+ "lprsrv" "\0" /* DHCP_LPR_SERVER */
+ "hostname" "\0" /* DHCP_HOST_NAME */
+ "bootsize" "\0" /* DHCP_BOOT_SIZE */
+ "domain" "\0" /* DHCP_DOMAIN_NAME */
+ "swapsrv" "\0" /* DHCP_SWAP_SERVER */
+ "rootpath" "\0" /* DHCP_ROOT_PATH */
+ "ipttl" "\0" /* DHCP_IP_TTL */
+ "mtu" "\0" /* DHCP_MTU */
+ "broadcast" "\0" /* DHCP_BROADCAST */
+ "nisdomain" "\0" /* */
+ "nissrv" "\0" /* */
+ "ntpsrv" "\0" /* DHCP_NTP_SERVER */
+ "wins" "\0" /* DHCP_WINS_SERVER */
+ "requestip" "\0" /* DHCP_REQUESTED_IP */
+ "lease" "\0" /* DHCP_LEASE_TIME */
+ "dhcptype" "\0" /* */
+ "serverid" "\0" /* DHCP_SERVER_ID */
+ "message" "\0" /* DHCP_MESSAGE */
+ "vendorclass" "\0" /* DHCP_VENDOR */
+ "clientid" "\0" /* DHCP_CLIENT_ID */
+ "tftp" "\0"
+ "bootfile" "\0"
+ "userclass" "\0"
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ "search" "\0"
+#endif
+ /* MSIE's "Web Proxy Autodiscovery Protocol" support */
+ "wpad" "\0"
+ ;
+
+
/* Lengths of the different option types */
-int option_lengths[] = {
- [OPTION_IP] = 4,
- [OPTION_IP_PAIR] = 8,
- [OPTION_BOOLEAN] = 1,
- [OPTION_STRING] = 1,
- [OPTION_U8] = 1,
- [OPTION_U16] = 2,
- [OPTION_S16] = 2,
- [OPTION_U32] = 4,
- [OPTION_S32] = 4
+const uint8_t dhcp_option_lengths[] ALIGN1 = {
+ [OPTION_IP] = 4,
+ [OPTION_IP_PAIR] = 8,
+ [OPTION_BOOLEAN] = 1,
+ [OPTION_STRING] = 1,
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ [OPTION_STR1035] = 1,
+#endif
+ [OPTION_U8] = 1,
+ [OPTION_U16] = 2,
+ [OPTION_S16] = 2,
+ [OPTION_U32] = 4,
+ [OPTION_S32] = 4
};
-/* get an option with bounds checking (warning, not aligned). */
-unsigned char *get_option(struct dhcpMessage *packet, int code)
+/* get an option with bounds checking (warning, result is not aligned). */
+uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code)
{
- int i, length;
- unsigned char *optionptr;
- int over = 0, done = 0, curr = OPTION_FIELD;
-
+ uint8_t *optionptr;
+ int len;
+ int rem;
+ int overload = 0;
+ enum {
+ FILE_FIELD101 = FILE_FIELD * 0x101,
+ SNAME_FIELD101 = SNAME_FIELD * 0x101,
+ };
+
+ /* option bytes: [code][len][data1][data2]..[dataLEN] */
optionptr = packet->options;
- i = 0;
- length = 308;
- while (!done) {
- if (i >= length) {
- LOG(LOG_WARNING, "bogus packet, option fields too long.");
+ rem = sizeof(packet->options);
+ while (1) {
+ if (rem <= 0) {
+ bb_error_msg("bogus packet, malformed option field");
return NULL;
}
- if (optionptr[i + OPT_CODE] == code) {
- if (i + 1 + optionptr[i + OPT_LEN] >= length) {
- LOG(LOG_WARNING, "bogus packet, option fields too long.");
- return NULL;
- }
- return optionptr + i + 2;
- }
- switch (optionptr[i + OPT_CODE]) {
- case DHCP_PADDING:
- i++;
- break;
- case DHCP_OPTION_OVER:
- if (i + 1 + optionptr[i + OPT_LEN] >= length) {
- LOG(LOG_WARNING, "bogus packet, option fields too long.");
- return NULL;
- }
- over = optionptr[i + 3];
- i += optionptr[OPT_LEN] + 2;
- break;
- case DHCP_END:
- if (curr == OPTION_FIELD && over & FILE_FIELD) {
+ if (optionptr[OPT_CODE] == DHCP_PADDING) {
+ rem--;
+ optionptr++;
+ continue;
+ }
+ if (optionptr[OPT_CODE] == DHCP_END) {
+ if ((overload & FILE_FIELD101) == FILE_FIELD) {
+ /* can use packet->file, and didn't look at it yet */
+ overload |= FILE_FIELD101; /* "we looked at it" */
optionptr = packet->file;
- i = 0;
- length = 128;
- curr = FILE_FIELD;
- } else if (curr == FILE_FIELD && over & SNAME_FIELD) {
+ rem = sizeof(packet->file);
+ continue;
+ }
+ if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
+ /* can use packet->sname, and didn't look at it yet */
+ overload |= SNAME_FIELD101; /* "we looked at it" */
optionptr = packet->sname;
- i = 0;
- length = 64;
- curr = SNAME_FIELD;
- } else done = 1;
- break;
- default:
- i += optionptr[OPT_LEN + i] + 2;
+ rem = sizeof(packet->sname);
+ continue;
+ }
+ return NULL;
+ }
+ len = 2 + optionptr[OPT_LEN];
+ rem -= len;
+ if (rem < 0)
+ continue; /* complain and return NULL */
+
+ if (optionptr[OPT_CODE] == code)
+ return optionptr + OPT_DATA;
+
+ if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
+ overload |= optionptr[OPT_DATA];
+ /* fall through */
}
+ optionptr += len;
}
return NULL;
}
/* return the position of the 'end' option (no bounds checking) */
-int end_option(unsigned char *optionptr)
+int FAST_FUNC end_option(uint8_t *optionptr)
{
int i = 0;
-
+
while (optionptr[i] != DHCP_END) {
- if (optionptr[i] == DHCP_PADDING) i++;
- else i += optionptr[i + OPT_LEN] + 2;
+ if (optionptr[i] != DHCP_PADDING)
+ i += optionptr[i + OPT_LEN] + 1;
+ i++;
}
return i;
}
-/* add an option string to the options (an option string contains an option code,
- * length, then data) */
-int add_option_string(unsigned char *optionptr, unsigned char *string)
+/* add an option string to the options */
+/* option bytes: [code][len][data1][data2]..[dataLEN] */
+int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string)
{
int end = end_option(optionptr);
-
+
/* end position + string length + option code/length + end option */
- if (end + string[OPT_LEN] + 2 + 1 >= 308) {
- LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]);
+ if (end + string[OPT_LEN] + 2 + 1 >= DHCP_OPTIONS_BUFSIZE) {
+ bb_error_msg("option 0x%02x did not fit into the packet",
+ string[OPT_CODE]);
return 0;
}
- DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]);
+ DEBUG("adding option 0x%02x", string[OPT_CODE]);
memcpy(optionptr + end, string, string[OPT_LEN] + 2);
optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
return string[OPT_LEN] + 2;
@@ -145,84 +213,25 @@ int add_option_string(unsigned char *optionptr, unsigned char *string)
/* add a one to four byte option to a packet */
-int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data)
+int FAST_FUNC add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data)
{
- char length = 0;
- int i;
- unsigned char option[2 + 4];
- unsigned char *u8;
- u_int16_t *u16;
- u_int32_t *u32;
- u_int32_t aligned;
- u8 = (unsigned char *) &aligned;
- u16 = (u_int16_t *) &aligned;
- u32 = &aligned;
-
- for (i = 0; options[i].code; i++)
- if (options[i].code == code) {
- length = option_lengths[options[i].flags & TYPE_MASK];
+ const struct dhcp_option *dh;
+
+ for (dh = dhcp_options; dh->code; dh++) {
+ if (dh->code == code) {
+ uint8_t option[6], len;
+
+ option[OPT_CODE] = code;
+ len = dhcp_option_lengths[dh->flags & TYPE_MASK];
+ option[OPT_LEN] = len;
+ if (BB_BIG_ENDIAN)
+ data <<= 8 * (4 - len);
+ /* Assignment is unaligned! */
+ move_to_unaligned32(&option[OPT_DATA], data);
+ return add_option_string(optionptr, option);
}
-
- if (!length) {
- DEBUG(LOG_ERR, "Could not add option 0x%02x", code);
- return 0;
- }
-
- option[OPT_CODE] = code;
- option[OPT_LEN] = length;
-
- switch (length) {
- case 1: *u8 = data; break;
- case 2: *u16 = data; break;
- case 4: *u32 = data; break;
}
- memcpy(option + 2, &aligned, length);
- return add_option_string(optionptr, option);
-}
-
-/* find option 'code' in opt_list */
-struct option_set *find_option(struct option_set *opt_list, char code)
-{
- while (opt_list && opt_list->data[OPT_CODE] < code)
- opt_list = opt_list->next;
-
- if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;
- else return NULL;
-}
-
-
-/* add an option to the opt_list */
-void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)
-{
- struct option_set *existing, *new, **curr;
-
- /* add it to an existing option */
- if ((existing = find_option(*opt_list, option->code))) {
- DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);
- if (option->flags & OPTION_LIST) {
- if (existing->data[OPT_LEN] + length <= 255) {
- existing->data = realloc(existing->data,
- existing->data[OPT_LEN] + length + 2);
- memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
- existing->data[OPT_LEN] += length;
- } /* else, ignore the data, we could put this in a second option in the future */
- } /* else, ignore the new data */
- } else {
- DEBUG(LOG_INFO, "Attaching option %s to list", option->name);
-
- /* make a new option */
- new = xmalloc(sizeof(struct option_set));
- new->data = xmalloc(length + 2);
- new->data[OPT_CODE] = option->code;
- new->data[OPT_LEN] = length;
- memcpy(new->data + 2, buffer, length);
-
- curr = opt_list;
- while (*curr && (*curr)->data[OPT_CODE] < option->code)
- curr = &(*curr)->next;
-
- new->next = *curr;
- *curr = new;
- }
+ bb_error_msg("cannot add option 0x%02x", code);
+ return 0;
}
diff --git a/release/src/router/busybox/networking/udhcp/options.h b/release/src/router/busybox/networking/udhcp/options.h
index 1fded2ef..23370da6 100644
--- a/release/src/router/busybox/networking/udhcp/options.h
+++ b/release/src/router/busybox/networking/udhcp/options.h
@@ -1,15 +1,19 @@
+/* vi: set sw=4 ts=4: */
/* options.h */
-#ifndef _OPTIONS_H
-#define _OPTIONS_H
+#ifndef UDHCP_OPTIONS_H
+#define UDHCP_OPTIONS_H 1
-#include "packet.h"
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
-#define TYPE_MASK 0x0F
+#define TYPE_MASK 0x0F
enum {
- OPTION_IP=1,
+ OPTION_IP = 1,
OPTION_IP_PAIR,
OPTION_STRING,
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ OPTION_STR1035, /* RFC1035 compressed domain name list */
+#endif
OPTION_BOOLEAN,
OPTION_U8,
OPTION_U16,
@@ -18,23 +22,93 @@ enum {
OPTION_S32
};
-#define OPTION_REQ 0x10 /* have the client request this option */
-#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
+#define OPTION_REQ 0x10 /* have the client request this option */
+#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
+
+/*****************************************************************/
+/* Do not modify below here unless you know what you are doing!! */
+/*****************************************************************/
+
+/* DHCP protocol -- see RFC 2131 */
+#define DHCP_MAGIC 0x63825363
+
+/* DHCP option codes (partial list) */
+#define DHCP_PADDING 0x00
+#define DHCP_SUBNET 0x01
+#define DHCP_TIME_OFFSET 0x02
+#define DHCP_ROUTER 0x03
+#define DHCP_TIME_SERVER 0x04
+#define DHCP_NAME_SERVER 0x05
+#define DHCP_DNS_SERVER 0x06
+#define DHCP_LOG_SERVER 0x07
+#define DHCP_COOKIE_SERVER 0x08
+#define DHCP_LPR_SERVER 0x09
+#define DHCP_HOST_NAME 0x0c
+#define DHCP_BOOT_SIZE 0x0d
+#define DHCP_DOMAIN_NAME 0x0f
+#define DHCP_SWAP_SERVER 0x10
+#define DHCP_ROOT_PATH 0x11
+#define DHCP_IP_TTL 0x17
+#define DHCP_MTU 0x1a
+#define DHCP_BROADCAST 0x1c
+#define DHCP_NTP_SERVER 0x2a
+#define DHCP_WINS_SERVER 0x2c
+#define DHCP_REQUESTED_IP 0x32
+#define DHCP_LEASE_TIME 0x33
+#define DHCP_OPTION_OVERLOAD 0x34
+#define DHCP_MESSAGE_TYPE 0x35
+#define DHCP_SERVER_ID 0x36
+#define DHCP_PARAM_REQ 0x37
+#define DHCP_MESSAGE 0x38
+#define DHCP_MAX_SIZE 0x39
+#define DHCP_T1 0x3a
+#define DHCP_T2 0x3b
+#define DHCP_VENDOR 0x3c
+#define DHCP_CLIENT_ID 0x3d
+#define DHCP_FQDN 0x51
+#define DHCP_END 0xFF
+/* Offsets in option byte sequence */
+#define OPT_CODE 0
+#define OPT_LEN 1
+#define OPT_DATA 2
+/* Bits in "overload" option */
+#define OPTION_FIELD 0
+#define FILE_FIELD 1
+#define SNAME_FIELD 2
+
+#define BOOTREQUEST 1
+#define BOOTREPLY 2
+
+#define ETH_10MB 1
+#define ETH_10MB_LEN 6
+
+#define DHCPDISCOVER 1 /* client -> server */
+#define DHCPOFFER 2 /* client <- server */
+#define DHCPREQUEST 3 /* client -> server */
+#define DHCPDECLINE 4 /* client -> server */
+#define DHCPACK 5 /* client <- server */
+#define DHCPNAK 6 /* client <- server */
+#define DHCPRELEASE 7 /* client -> server */
+#define DHCPINFORM 8 /* client -> server */
struct dhcp_option {
- char name[10];
- char flags;
- unsigned char code;
+ uint8_t flags;
+ uint8_t code;
};
-extern struct dhcp_option options[];
-extern int option_lengths[];
+extern const struct dhcp_option dhcp_options[];
+extern const char dhcp_option_strings[];
+extern const uint8_t dhcp_option_lengths[];
+
+uint8_t *get_option(struct dhcpMessage *packet, int code) FAST_FUNC;
+int end_option(uint8_t *optionptr) FAST_FUNC;
+int add_option_string(uint8_t *optionptr, uint8_t *string) FAST_FUNC;
+int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) FAST_FUNC;
+#if ENABLE_FEATURE_UDHCP_RFC3397
+char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC;
+uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC;
+#endif
-unsigned char *get_option(struct dhcpMessage *packet, int code);
-int end_option(unsigned char *optionptr);
-int add_option_string(unsigned char *optionptr, unsigned char *string);
-int add_simple_option(unsigned char *optionptr, unsigned char code, u_int32_t data);
-struct option_set *find_option(struct option_set *opt_list, char code);
-void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length);
+POP_SAVED_FUNCTION_VISIBILITY
#endif
diff --git a/release/src/router/busybox/networking/udhcp/packet.c b/release/src/router/busybox/networking/udhcp/packet.c
index 0f2a3bc6..33320238 100644
--- a/release/src/router/busybox/networking/udhcp/packet.c
+++ b/release/src/router/busybox/networking/udhcp/packet.c
@@ -1,10 +1,13 @@
-#include <unistd.h>
-#include <string.h>
+/* vi: set sw=4 ts=4: */
+/*
+ * packet.c -- packet ops
+ * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <features.h>
-#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
+#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
@@ -12,27 +15,22 @@
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#endif
-#include <errno.h>
+#include "common.h"
#include "dhcpd.h"
#include "options.h"
-#include "common.h"
+int minpkt = 0; // zzz
-void init_header(struct dhcpMessage *packet, char type)
+void FAST_FUNC udhcp_init_header(struct dhcpMessage *packet, char type)
{
memset(packet, 0, sizeof(struct dhcpMessage));
+ packet->op = BOOTREQUEST; /* if client to a server */
switch (type) {
- case DHCPDISCOVER:
- case DHCPREQUEST:
- case DHCPRELEASE:
- case DHCPINFORM:
- packet->op = BOOTREQUEST;
- break;
case DHCPOFFER:
case DHCPACK:
case DHCPNAK:
- packet->op = BOOTREPLY;
+ packet->op = BOOTREPLY; /* if server to client */
}
packet->htype = ETH_10MB;
packet->hlen = ETH_10MB_LEN;
@@ -43,52 +41,64 @@ void init_header(struct dhcpMessage *packet, char type)
/* read a packet from socket fd, return -1 on read error, -2 on packet error */
-int get_packet(struct dhcpMessage *packet, int fd)
+int FAST_FUNC udhcp_recv_kernel_packet(struct dhcpMessage *packet, int fd)
{
int bytes;
- int i;
- const char broken_vendors[][8] = {
- "MSFT 98",
- ""
- };
- char unsigned *vendor;
+ unsigned char *vendor;
- memset(packet, 0, sizeof(struct dhcpMessage));
- bytes = read(fd, packet, sizeof(struct dhcpMessage));
+ memset(packet, 0, sizeof(*packet));
+ bytes = safe_read(fd, packet, sizeof(*packet));
if (bytes < 0) {
- DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring");
- return -1;
+ DEBUG("cannot read on listening socket, ignoring");
+ return bytes; /* returns -1 */
}
- if (ntohl(packet->cookie) != DHCP_MAGIC) {
- LOG(LOG_ERR, "received bogus message, ignoring");
+ if (packet->cookie != htonl(DHCP_MAGIC)) {
+ bb_error_msg("received bogus message, ignoring");
return -2;
}
- DEBUG(LOG_INFO, "Received a packet");
-
- if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) {
- for (i = 0; broken_vendors[i][0]; i++) {
- if (vendor[OPT_LEN - 2] == (unsigned char) strlen(broken_vendors[i]) &&
- !strncmp(vendor, broken_vendors[i], vendor[OPT_LEN - 2])) {
- DEBUG(LOG_INFO, "broken client (%s), forcing broadcast",
- broken_vendors[i]);
- packet->flags |= htons(BROADCAST_FLAG);
+ DEBUG("Received a packet");
+
+ if (packet->op == BOOTREQUEST) {
+ vendor = get_option(packet, DHCP_VENDOR);
+ if (vendor) {
+#if 0
+ static const char broken_vendors[][8] = {
+ "MSFT 98",
+ ""
+ };
+ int i;
+ for (i = 0; broken_vendors[i][0]; i++) {
+ if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i])
+ && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])
+ ) {
+ DEBUG("broken client (%s), forcing broadcast replies",
+ broken_vendors[i]);
+ packet->flags |= htons(BROADCAST_FLAG);
+ }
}
+#else
+ if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1)
+ && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0
+ ) {
+ DEBUG("broken client (%s), forcing broadcast replies", "MSFT 98");
+ packet->flags |= htons(BROADCAST_FLAG);
+ }
+#endif
}
}
-
return bytes;
}
-u_int16_t checksum(void *addr, int count)
+uint16_t FAST_FUNC udhcp_checksum(void *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
- register int32_t sum = 0;
- u_int16_t *source = (u_int16_t *) addr;
+ int32_t sum = 0;
+ uint16_t *source = (uint16_t *) addr;
while (count > 1) {
/* This is the inner loop */
@@ -100,8 +110,8 @@ u_int16_t checksum(void *addr, int count)
if (count > 0) {
/* Make sure that the left-over byte is added correctly both
* with little and big endian hosts */
- u_int16_t tmp = 0;
- *(unsigned char *) (&tmp) = * (unsigned char *) source;
+ uint16_t tmp = 0;
+ *(uint8_t*)&tmp = *(uint8_t*)source;
sum += tmp;
}
/* Fold 32-bit sum to 16 bits */
@@ -112,90 +122,177 @@ u_int16_t checksum(void *addr, int count)
}
-/* Constuct a ip/udp header for a packet, and specify the source and dest hardware address */
-int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
- u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex)
+/* Construct a ip/udp header for a packet, send packet */
+int FAST_FUNC udhcp_send_raw_packet(struct dhcpMessage *payload,
+ uint32_t source_ip, int source_port,
+ uint32_t dest_ip, int dest_port, const uint8_t *dest_arp,
+ int ifindex)
{
- int fd;
- int result;
struct sockaddr_ll dest;
struct udp_dhcp_packet packet;
+ int fd;
+ int result = -1;
+ const char *msg;
+
+ enum {
+ IP_UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
+ UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE - offsetof(struct udp_dhcp_packet, udp),
+ };
- if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
- DEBUG(LOG_ERR, "socket call failed: %m");
- return -1;
+ fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ if (fd < 0) {
+ msg = "socket(%s)";
+ goto ret_msg;
}
-
+
memset(&dest, 0, sizeof(dest));
memset(&packet, 0, sizeof(packet));
-
+ packet.data = *payload; /* struct copy */
+
dest.sll_family = AF_PACKET;
dest.sll_protocol = htons(ETH_P_IP);
dest.sll_ifindex = ifindex;
dest.sll_halen = 6;
memcpy(dest.sll_addr, dest_arp, 6);
- if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
- DEBUG(LOG_ERR, "bind call failed: %m");
- close(fd);
- return -1;
+ if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+ msg = "bind(%s)";
+ goto ret_close;
}
+#if 1 // zzz
+ int n;
+
+ // n = size of dhcp only
+ if (minpkt) n = (end_option(payload->options) + 1 + sizeof(*payload) - sizeof(payload->options));
+ else n = sizeof(struct dhcpMessage) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS;
+
packet.ip.protocol = IPPROTO_UDP;
packet.ip.saddr = source_ip;
packet.ip.daddr = dest_ip;
packet.udp.source = htons(source_port);
packet.udp.dest = htons(dest_port);
- packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */
+ /* size, excluding IP header: */
+ packet.udp.len = htons(sizeof(packet.udp) + n); // udp + dhcp
+
+ n += sizeof(packet) - sizeof(packet.data); // n = ip + udp + dhcp
+
+ /* for UDP checksumming, ip.len is set to UDP packet len */
packet.ip.tot_len = packet.udp.len;
- memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
- packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet));
-
- packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
+ packet.udp.check = udhcp_checksum(&packet, n);
+ /* but for sending, it is set to IP packet len */
+ packet.ip.tot_len = htons(n);
packet.ip.ihl = sizeof(packet.ip) >> 2;
packet.ip.version = IPVERSION;
packet.ip.ttl = IPDEFTTL;
- packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));
+ packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip));
+/*
+ bb_info_msg("%s", __FUNCTION__);
+ bb_info_msg("packet.udp.len=%d", ntohs(packet.udp.len));
+ bb_info_msg("packet.ip.tot_len=%d", ntohs(packet.ip.tot_len));
+ bb_info_msg("UPD_DHCP_SIZE=%d", UPD_DHCP_SIZE);
+ bb_info_msg("IP_UPD_DHCP_SIZE=%d", IP_UPD_DHCP_SIZE);
+*/
+ result = sendto(fd, &packet, n, 0, (struct sockaddr *) &dest, sizeof(dest));
+#else
+ packet.ip.protocol = IPPROTO_UDP;
+ packet.ip.saddr = source_ip;
+ packet.ip.daddr = dest_ip;
+ packet.udp.source = htons(source_port);
+ packet.udp.dest = htons(dest_port);
+ /* size, excluding IP header: */
+ packet.udp.len = htons(UPD_DHCP_SIZE);
+ /* for UDP checksumming, ip.len is set to UDP packet len */
+ packet.ip.tot_len = packet.udp.len;
+ packet.udp.check = udhcp_checksum(&packet, IP_UPD_DHCP_SIZE);
+ /* but for sending, it is set to IP packet len */
+ packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE);
+ packet.ip.ihl = sizeof(packet.ip) >> 2;
+ packet.ip.version = IPVERSION;
+ packet.ip.ttl = IPDEFTTL;
+ packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip));
- result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
- if (result <= 0) {
- DEBUG(LOG_ERR, "write on socket failed: %m");
- }
+ /* Currently we send full-sized DHCP packets (zero padded).
+ * If you need to change this: last byte of the packet is
+ * packet.data.options[end_option(packet.data.options)]
+ */
+ result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
+ (struct sockaddr *) &dest, sizeof(dest));
+#endif
+
+ msg = "sendto";
+ ret_close:
close(fd);
+ if (result < 0) {
+ ret_msg:
+ bb_perror_msg(msg, "PACKET");
+ }
return result;
}
/* Let the kernel do all the work for packet generation */
-int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
- u_int32_t dest_ip, int dest_port)
+int FAST_FUNC udhcp_send_kernel_packet(struct dhcpMessage *payload,
+ uint32_t source_ip, int source_port,
+ uint32_t dest_ip, int dest_port)
{
- int n = 1;
- int fd, result;
struct sockaddr_in client;
-
- if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- return -1;
-
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
- return -1;
+ int fd;
+ int result = -1;
+ const char *msg;
+
+ enum {
+ DHCP_SIZE = sizeof(struct dhcpMessage) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
+ };
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd < 0) {
+ msg = "socket(%s)";
+ goto ret_msg;
+ }
+ setsockopt_reuseaddr(fd);
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(source_port);
client.sin_addr.s_addr = source_ip;
-
- if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
- return -1;
+ if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
+ msg = "bind(%s)";
+ goto ret_close;
+ }
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(dest_port);
- client.sin_addr.s_addr = dest_ip;
+ client.sin_addr.s_addr = dest_ip;
+ if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
+ msg = "connect";
+ goto ret_close;
+ }
- if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
- return -1;
+#if 1 // zzz
+ int n;
- result = write(fd, payload, sizeof(struct dhcpMessage));
+ if (minpkt) n = (end_option(payload->options) + 1 + sizeof(*payload) - sizeof(payload->options));
+ else n = DHCP_SIZE;
+/*
+ bb_info_msg("%s n=%d", __FUNCTION__, n);
+ bb_info_msg("%s", __FUNCTION__);
+ bb_info_msg("n=%d", n);
+ bb_info_msg("DHCP_SIZE=%d", DHCP_SIZE);
+*/
+ result = write(fd, payload, n);
+
+#else
+ /* Currently we send full-sized DHCP packets (see above) */
+ result = safe_write(fd, payload, DHCP_SIZE);
+#endif
+
+ msg = "write";
+ ret_close:
close(fd);
+ if (result < 0) {
+ ret_msg:
+ bb_perror_msg(msg, "UDP");
+ }
return result;
-}
+}
diff --git a/release/src/router/busybox/networking/udhcp/packet.h b/release/src/router/busybox/networking/udhcp/packet.h
deleted file mode 100644
index 1a263ef8..00000000
--- a/release/src/router/busybox/networking/udhcp/packet.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _PACKET_H
-#define _PACKET_H
-
-#include <netinet/udp.h>
-#include <netinet/ip.h>
-
-struct dhcpMessage {
- u_int8_t op;
- u_int8_t htype;
- u_int8_t hlen;
- u_int8_t hops;
- u_int32_t xid;
- u_int16_t secs;
- u_int16_t flags;
- u_int32_t ciaddr;
- u_int32_t yiaddr;
- u_int32_t siaddr;
- u_int32_t giaddr;
- u_int8_t chaddr[16];
- u_int8_t sname[64];
- u_int8_t file[128];
- u_int32_t cookie;
- u_int8_t options[308]; /* 312 - cookie */
-};
-
-struct udp_dhcp_packet {
- struct iphdr ip;
- struct udphdr udp;
- struct dhcpMessage data;
-};
-
-void init_header(struct dhcpMessage *packet, char type);
-int get_packet(struct dhcpMessage *packet, int fd);
-u_int16_t checksum(void *addr, int count);
-int raw_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
- u_int32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex);
-int kernel_packet(struct dhcpMessage *payload, u_int32_t source_ip, int source_port,
- u_int32_t dest_ip, int dest_port);
-
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/pidfile.c b/release/src/router/busybox/networking/udhcp/pidfile.c
deleted file mode 100644
index 246a64aa..00000000
--- a/release/src/router/busybox/networking/udhcp/pidfile.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* pidfile.c
- *
- * Functions to assist in the writing and removing of pidfiles.
- *
- * Russ Dill <Russ.Dill@asu.edu> Soptember 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "debug.h"
-
-int pidfile_acquire(char *pidfile)
-{
- int pid_fd;
- if (pidfile == NULL) return -1;
-
- pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644);
- if (pid_fd < 0) {
- LOG(LOG_ERR, "Unable to open pidfile %s: %s\n",
- pidfile, strerror(errno));
- } else {
- lockf(pid_fd, F_LOCK, 0);
- }
-
- return pid_fd;
-}
-
-
-void pidfile_write_release(int pid_fd)
-{
- FILE *out;
-
- if (pid_fd < 0) return;
-
- if ((out = fdopen(pid_fd, "w")) != NULL) {
- fprintf(out, "%d\n", getpid());
- fclose(out);
- }
- lockf(pid_fd, F_UNLCK, 0);
- close(pid_fd);
-}
-
-
-void pidfile_delete(char *pidfile)
-{
- if (pidfile) unlink(pidfile);
-}
-
-
diff --git a/release/src/router/busybox/networking/udhcp/pidfile.h b/release/src/router/busybox/networking/udhcp/pidfile.h
deleted file mode 100644
index 0e2b148a..00000000
--- a/release/src/router/busybox/networking/udhcp/pidfile.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* pidfile.h
- *
- * Functions to assist in the writing and removing of pidfiles.
- *
- * Russ Dill <Russ.Dill@asu.edu> Soptember 2001
- *
- * 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.
- */
-
-
-int pidfile_acquire(char *pidfile);
-void pidfile_write_release(int pid_fd);
-void pidfile_delete(char *pidfile);
-
diff --git a/release/src/router/busybox/networking/udhcp/script.c b/release/src/router/busybox/networking/udhcp/script.c
index 41b680d6..3029b136 100644
--- a/release/src/router/busybox/networking/udhcp/script.c
+++ b/release/src/router/busybox/networking/udhcp/script.c
@@ -1,45 +1,26 @@
+/* vi: set sw=4 ts=4: */
/* script.c
*
- * Functions to call the DHCP client notification scripts
+ * Functions to call the DHCP client notification scripts
*
* Russ Dill <Russ.Dill@asu.edu> July 2001
*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "options.h"
-#include "dhcpd.h"
+#include "common.h"
#include "dhcpc.h"
#include "options.h"
-#include "common.h"
+
/* get a rough idea of how long an option will be (rounding up...) */
-static const int max_option_length[] = {
+static const uint8_t max_option_length[] = {
[OPTION_IP] = sizeof("255.255.255.255 "),
[OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
[OPTION_STRING] = 1,
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ [OPTION_STR1035] = 1,
+#endif
[OPTION_BOOLEAN] = sizeof("yes "),
[OPTION_U8] = sizeof("255 "),
[OPTION_U16] = sizeof("65535 "),
@@ -52,57 +33,56 @@ static const int max_option_length[] = {
static inline int upper_length(int length, int opt_index)
{
return max_option_length[opt_index] *
- (length / option_lengths[opt_index]);
+ (length / dhcp_option_lengths[opt_index]);
}
-static int sprintip(char *dest, unsigned char *ip)
-{
- return sprintf(dest, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
-}
-
-static void asprintip(char **dest, char *pre, unsigned char *ip)
+static int sprintip(char *dest, const char *pre, const uint8_t *ip)
{
- asprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
+ return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
}
/* really simple implementation, just count the bits */
-static int mton(struct in_addr *mask)
+static int mton(uint32_t mask)
{
- int i;
- unsigned long bits = ntohl(mask->s_addr);
- /* too bad one can't check the carry bit, etc in c bit
- * shifting */
- for (i = 0; i < 32 && !((bits >> i) & 1); i++);
- return 32 - i;
+ int i = 0;
+ mask = ntohl(mask); /* 111110000-like bit pattern */
+ while (mask) {
+ i++;
+ mask <<= 1;
+ }
+ return i;
}
-/* Fill dest with the text of option 'option'. */
-static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p)
+/* Allocate and fill with the text of option 'option'. */
+static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
{
- int type, optlen;
- u_int16_t val_u16;
+ int len, type, optlen;
+ uint16_t val_u16;
int16_t val_s16;
- u_int32_t val_u32;
+ uint32_t val_u32;
int32_t val_s32;
- int len = option[OPT_LEN - 2];
-
- dest += sprintf(dest, "%s=", type_p->name);
+ char *dest, *ret;
+ len = option[OPT_LEN - 2];
type = type_p->flags & TYPE_MASK;
- optlen = option_lengths[type];
- for(;;) {
+ optlen = dhcp_option_lengths[type];
+
+ dest = ret = xmalloc(upper_length(len, type) + strlen(opt_name) + 2);
+ dest += sprintf(ret, "%s=", opt_name);
+
+ for (;;) {
switch (type) {
case OPTION_IP_PAIR:
- dest += sprintip(dest, option);
- *(dest++) = '/';
+ dest += sprintip(dest, "", option);
+ *dest++ = '/';
option += 4;
optlen = 4;
case OPTION_IP: /* Works regardless of host byte order. */
- dest += sprintip(dest, option);
- break;
+ dest += sprintip(dest, "", option);
+ break;
case OPTION_BOOLEAN:
dest += sprintf(dest, *option ? "yes" : "no");
break;
@@ -110,134 +90,146 @@ static void fill_options(char *dest, unsigned char *option, struct dhcp_option *
dest += sprintf(dest, "%u", *option);
break;
case OPTION_U16:
- memcpy(&val_u16, option, 2);
+ move_from_unaligned16(val_u16, option);
dest += sprintf(dest, "%u", ntohs(val_u16));
break;
case OPTION_S16:
- memcpy(&val_s16, option, 2);
+ move_from_unaligned16(val_s16, option);
dest += sprintf(dest, "%d", ntohs(val_s16));
break;
case OPTION_U32:
- memcpy(&val_u32, option, 4);
+ move_from_unaligned32(val_u32, option);
dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));
break;
case OPTION_S32:
- memcpy(&val_s32, option, 4);
+ move_from_unaligned32(val_s32, option);
dest += sprintf(dest, "%ld", (long) ntohl(val_s32));
break;
case OPTION_STRING:
memcpy(dest, option, len);
dest[len] = '\0';
- return; /* Short circuit this case */
+ return ret; /* Short circuit this case */
+#if ENABLE_FEATURE_UDHCP_RFC3397
+ case OPTION_STR1035:
+ /* unpack option into dest; use ret for prefix (i.e., "optname=") */
+ dest = dname_dec(option, len, ret);
+ free(ret);
+ return dest;
+#endif
}
option += optlen;
len -= optlen;
- if (len <= 0) break;
+ if (len <= 0)
+ break;
dest += sprintf(dest, " ");
}
+ return ret;
}
-static char *find_env(const char *prefix, char *defaultstr)
-{
- char *ptr;
-
- ptr = getenv(prefix);
- return ptr ? ptr : defaultstr;
-}
-
-
-/* put all the paramaters into an environment */
+/* put all the parameters into an environment */
static char **fill_envp(struct dhcpMessage *packet)
{
int num_options = 0;
- int i, j;
- char **envp;
- unsigned char *temp;
- struct in_addr subnet;
- char over = 0;
-
- if (packet == NULL)
- num_options = 0;
- else {
- for (i = 0; options[i].code; i++)
- if (get_option(packet, options[i].code))
+ int i;
+ char **envp, **curr;
+ const char *opt_name;
+ uint8_t *temp;
+ uint8_t over = 0;
+
+ if (packet) {
+ for (i = 0; dhcp_options[i].code; i++) {
+ if (get_option(packet, dhcp_options[i].code)) {
num_options++;
- if (packet->siaddr) num_options++;
- if ((temp = get_option(packet, DHCP_OPTION_OVER)))
+ if (dhcp_options[i].code == DHCP_SUBNET)
+ num_options++; /* for mton */
+ }
+ }
+ if (packet->siaddr)
+ num_options++;
+ temp = get_option(packet, DHCP_OPTION_OVERLOAD);
+ if (temp)
over = *temp;
- if (!(over & FILE_FIELD) && packet->file[0]) num_options++;
- if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
- }
-
- envp = xmalloc((num_options + 5) * sizeof(char *));
- j = 0;
- asprintf(&envp[j++], "interface=%s", client_config.interface);
- envp[j++] = find_env("PATH", "PATH=/bin:/usr/bin:/sbin:/usr/sbin");
- envp[j++] = find_env("HOME", "HOME=/");
-
- if (packet == NULL) {
- envp[j++] = NULL;
- return envp;
+ if (!(over & FILE_FIELD) && packet->file[0])
+ num_options++;
+ if (!(over & SNAME_FIELD) && packet->sname[0])
+ num_options++;
}
- asprintip(&envp[j++], "ip=", (unsigned char *) &packet->yiaddr);
+ curr = envp = xzalloc(sizeof(char *) * (num_options + 3));
+ *curr = xasprintf("interface=%s", client_config.interface);
+ putenv(*curr++);
+ if (packet == NULL)
+ return envp;
- for (i = 0; options[i].code; i++) {
- if (!(temp = get_option(packet, options[i].code)))
- continue;
- envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], options[i].flags & TYPE_MASK) + strlen(options[i].name) + 2);
- fill_options(envp[j++], temp, &options[i]);
+ *curr = xmalloc(sizeof("ip=255.255.255.255"));
+ sprintip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
+ putenv(*curr++);
+
+ opt_name = dhcp_option_strings;
+ i = 0;
+ while (*opt_name) {
+ temp = get_option(packet, dhcp_options[i].code);
+ if (!temp)
+ goto next;
+ *curr = alloc_fill_opts(temp, &dhcp_options[i], opt_name);
+ putenv(*curr++);
/* Fill in a subnet bits option for things like /24 */
- if (options[i].code == DHCP_SUBNET) {
- memcpy(&subnet, temp, 4);
- asprintf(&envp[j++], "mask=%d", mton(&subnet));
+ if (dhcp_options[i].code == DHCP_SUBNET) {
+ uint32_t subnet;
+ move_from_unaligned32(subnet, temp);
+ *curr = xasprintf("mask=%d", mton(subnet));
+ putenv(*curr++);
}
+ next:
+ opt_name += strlen(opt_name) + 1;
+ i++;
}
if (packet->siaddr) {
- asprintip(&envp[j++], "siaddr=", (unsigned char *) &packet->siaddr);
+ *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
+ sprintip(*curr, "siaddr=", (uint8_t *) &packet->siaddr);
+ putenv(*curr++);
}
if (!(over & FILE_FIELD) && packet->file[0]) {
/* watch out for invalid packets */
packet->file[sizeof(packet->file) - 1] = '\0';
- asprintf(&envp[j++], "boot_file=%s", packet->file);
+ *curr = xasprintf("boot_file=%s", packet->file);
+ putenv(*curr++);
}
if (!(over & SNAME_FIELD) && packet->sname[0]) {
/* watch out for invalid packets */
packet->sname[sizeof(packet->sname) - 1] = '\0';
- asprintf(&envp[j++], "sname=%s", packet->sname);
- }
- envp[j] = NULL;
+ *curr = xasprintf("sname=%s", packet->sname);
+ putenv(*curr++);
+ }
return envp;
}
/* Call a script with a par file and env vars */
-void run_script(struct dhcpMessage *packet, const char *name)
+void FAST_FUNC udhcp_run_script(struct dhcpMessage *packet, const char *name)
{
- int pid;
- char **envp;
+ char **envp, **curr;
+ char *argv[3];
if (client_config.script == NULL)
return;
+ DEBUG("vfork'ing and exec'ing %s", client_config.script);
+
+ envp = fill_envp(packet);
+
/* call script */
- pid = fork();
- if (pid) {
- waitpid(pid, NULL, 0);
- return;
- } else if (pid == 0) {
- envp = fill_envp(packet);
-
- /* close fd's? */
-
- /* exec script */
- DEBUG(LOG_INFO, "execle'ing %s", client_config.script);
- execle(client_config.script, client_config.script,
- name, NULL, envp);
- LOG(LOG_ERR, "script %s failed: %m", client_config.script);
- exit(1);
- }
+ argv[0] = (char*) client_config.script;
+ argv[1] = (char*) name;
+ argv[2] = NULL;
+ wait4pid(spawn(argv));
+
+ for (curr = envp; *curr; curr++) {
+ bb_unsetenv(*curr);
+ free(*curr);
+ }
+ free(envp);
}
diff --git a/release/src/router/busybox/networking/udhcp/script.h b/release/src/router/busybox/networking/udhcp/script.h
deleted file mode 100644
index 87a20cc1..00000000
--- a/release/src/router/busybox/networking/udhcp/script.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SCRIPT_H
-#define _SCRIPT_H
-
-void run_script(struct dhcpMessage *packet, const char *name);
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/serverpacket.c b/release/src/router/busybox/networking/udhcp/serverpacket.c
index 09682444..8b0f1856 100644
--- a/release/src/router/busybox/networking/udhcp/serverpacket.c
+++ b/release/src/router/busybox/networking/udhcp/serverpacket.c
@@ -1,6 +1,7 @@
+/* vi: set sw=4 ts=4: */
/* serverpacket.c
*
- * Constuct and send DHCP server packets
+ * Construct and send DHCP server packets
*
* Russ Dill <Russ.Dill@asu.edu> July 2001
*
@@ -19,22 +20,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <time.h>
-
+#include "common.h"
+#include "dhcpc.h"
#include "dhcpd.h"
#include "options.h"
-#include "common.h"
+
/* send a packet to giaddr using the kernel ip stack */
static int send_packet_to_relay(struct dhcpMessage *payload)
{
- DEBUG(LOG_INFO, "Forwarding packet to relay");
+ DEBUG("Forwarding packet to relay");
- return kernel_packet(payload, server_config.server, SERVER_PORT,
+ return udhcp_send_kernel_packet(payload, server_config.server, SERVER_PORT,
payload->giaddr, SERVER_PORT);
}
@@ -42,46 +39,45 @@ static int send_packet_to_relay(struct dhcpMessage *payload)
/* send a packet to a specific arp address and ip address by creating our own ip packet */
static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast)
{
- unsigned char *chaddr;
- u_int32_t ciaddr;
-
+ const uint8_t *chaddr;
+ uint32_t ciaddr;
+
if (force_broadcast) {
- DEBUG(LOG_INFO, "broadcasting packet to client (NAK)");
+ DEBUG("broadcasting packet to client (NAK)");
ciaddr = INADDR_BROADCAST;
chaddr = MAC_BCAST_ADDR;
} else if (payload->ciaddr) {
- DEBUG(LOG_INFO, "unicasting packet to client ciaddr");
+ DEBUG("unicasting packet to client ciaddr");
ciaddr = payload->ciaddr;
chaddr = payload->chaddr;
- } else if (ntohs(payload->flags) & BROADCAST_FLAG) {
- DEBUG(LOG_INFO, "broadcasting packet to client (requested)");
+ } else if (payload->flags & htons(BROADCAST_FLAG)) {
+ DEBUG("broadcasting packet to client (requested)");
ciaddr = INADDR_BROADCAST;
chaddr = MAC_BCAST_ADDR;
} else {
- DEBUG(LOG_INFO, "unicasting packet to client yiaddr");
+ DEBUG("unicasting packet to client yiaddr");
ciaddr = payload->yiaddr;
chaddr = payload->chaddr;
}
- return raw_packet(payload, server_config.server, SERVER_PORT,
- ciaddr, CLIENT_PORT, chaddr, server_config.ifindex);
+ return udhcp_send_raw_packet(payload,
+ /*src*/ server_config.server, SERVER_PORT,
+ /*dst*/ ciaddr, CLIENT_PORT, chaddr,
+ server_config.ifindex);
}
/* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */
static int send_packet(struct dhcpMessage *payload, int force_broadcast)
{
- int ret;
-
if (payload->giaddr)
- ret = send_packet_to_relay(payload);
- else ret = send_packet_to_client(payload, force_broadcast);
- return ret;
+ return send_packet_to_relay(payload);
+ return send_packet_to_client(payload, force_broadcast);
}
static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type)
{
- init_header(packet, type);
+ udhcp_init_header(packet, type);
packet->xid = oldpacket->xid;
memcpy(packet->chaddr, oldpacket->chaddr, 16);
packet->flags = oldpacket->flags;
@@ -96,78 +92,82 @@ static void add_bootp_options(struct dhcpMessage *packet)
{
packet->siaddr = server_config.siaddr;
if (server_config.sname)
- strncpy(packet->sname, server_config.sname, sizeof(packet->sname) - 1);
+ strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
if (server_config.boot_file)
- strncpy(packet->file, server_config.boot_file, sizeof(packet->file) - 1);
+ strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
}
-
+
/* send a DHCP OFFER to a DHCP DISCOVER */
-int sendOffer(struct dhcpMessage *oldpacket)
+int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
{
struct dhcpMessage packet;
- struct dhcpOfferedAddr *lease = NULL;
- u_int32_t req_align, lease_time_align = server_config.lease;
- unsigned char *req, *lease_time;
+ uint32_t req_align;
+ uint32_t lease_time_aligned = server_config.lease;
+ uint32_t static_lease_ip;
+ uint8_t *req, *lease_time, *p_host_name;
struct option_set *curr;
struct in_addr addr;
init_packet(&packet, oldpacket, DHCPOFFER);
-
+
+ static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr);
+
/* ADDME: if static, short circuit */
- /* the client is in our lease/offered table */
- if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) {
- if (!lease_expired(lease))
- lease_time_align = lease->expires - time(0);
- packet.yiaddr = lease->yiaddr;
-
- /* Or the client has a requested ip */
- } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) &&
-
- /* Don't look here (ugly hackish thing to do) */
- memcpy(&req_align, req, 4) &&
-
- /* and the ip is in the lease range */
- ntohl(req_align) >= ntohl(server_config.start) &&
- ntohl(req_align) <= ntohl(server_config.end) &&
-
- /* and its not already taken/offered */ /* ADDME: check that its not a static lease */
- ((!(lease = find_lease_by_yiaddr(req_align)) ||
-
- /* or its taken, but expired */ /* ADDME: or maybe in here */
- lease_expired(lease)))) {
- packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */
-
- /* otherwise, find a free IP */ /*ADDME: is it a static lease? */
+ if (!static_lease_ip) {
+ struct dhcpOfferedAddr *lease;
+
+ lease = find_lease_by_chaddr(oldpacket->chaddr);
+ /* the client is in our lease/offered table */
+ if (lease) {
+ signed_leasetime_t tmp = lease->expires - time(NULL);
+ if (tmp >= 0)
+ lease_time_aligned = tmp;
+ packet.yiaddr = lease->yiaddr;
+ /* Or the client has requested an ip */
+ } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
+ /* Don't look here (ugly hackish thing to do) */
+ && (move_from_unaligned32(req_align, req), 1)
+ /* and the ip is in the lease range */
+ && ntohl(req_align) >= server_config.start_ip
+ && ntohl(req_align) <= server_config.end_ip
+ /* and is not already taken/offered */
+ && (!(lease = find_lease_by_yiaddr(req_align))
+ /* or its taken, but expired */
+ || lease_expired(lease))
+ ) {
+ packet.yiaddr = req_align;
+ /* otherwise, find a free IP */
+ } else {
+ packet.yiaddr = find_free_or_expired_address();
+ }
+
+ if (!packet.yiaddr) {
+ bb_error_msg("no IP addresses to give - OFFER abandoned");
+ return -1;
+ }
+ p_host_name = get_option(oldpacket, DHCP_HOST_NAME);
+ if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) {
+ bb_error_msg("lease pool is full - OFFER abandoned");
+ return -1;
+ }
+ lease_time = get_option(oldpacket, DHCP_LEASE_TIME);
+ if (lease_time) {
+ move_from_unaligned32(lease_time_aligned, lease_time);
+ lease_time_aligned = ntohl(lease_time_aligned);
+ if (lease_time_aligned > server_config.lease)
+ lease_time_aligned = server_config.lease;
+ }
+
+ /* Make sure we aren't just using the lease time from the previous offer */
+ if (lease_time_aligned < server_config.min_lease)
+ lease_time_aligned = server_config.min_lease;
} else {
- packet.yiaddr = find_address(0);
-
- /* try for an expired lease */
- if (!packet.yiaddr) packet.yiaddr = find_address(1);
- }
-
- if(!packet.yiaddr) {
- LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned");
- return -1;
- }
-
- if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
- LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned");
- return -1;
- }
-
- if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
- memcpy(&lease_time_align, lease_time, 4);
- lease_time_align = ntohl(lease_time_align);
- if (lease_time_align > server_config.lease)
- lease_time_align = server_config.lease;
+ /* It is a static lease... use it */
+ packet.yiaddr = static_lease_ip;
}
- /* Make sure we aren't just using the lease time from the previous offer */
- if (lease_time_align < server_config.min_lease)
- lease_time_align = server_config.lease;
- /* ADDME: end of short circuit */
- add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
+ add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_aligned));
curr = server_config.options;
while (curr) {
@@ -177,46 +177,48 @@ int sendOffer(struct dhcpMessage *oldpacket)
}
add_bootp_options(&packet);
-
+
addr.s_addr = packet.yiaddr;
- LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr));
+ bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
return send_packet(&packet, 0);
}
-int sendNAK(struct dhcpMessage *oldpacket)
+int FAST_FUNC send_NAK(struct dhcpMessage *oldpacket)
{
struct dhcpMessage packet;
init_packet(&packet, oldpacket, DHCPNAK);
-
- DEBUG(LOG_INFO, "sending NAK");
+
+ DEBUG("Sending NAK");
return send_packet(&packet, 1);
}
-int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr)
+int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr)
{
struct dhcpMessage packet;
struct option_set *curr;
- unsigned char *lease_time;
- u_int32_t lease_time_align = server_config.lease;
+ uint8_t *lease_time;
+ uint32_t lease_time_aligned = server_config.lease;
struct in_addr addr;
+ uint8_t *p_host_name;
init_packet(&packet, oldpacket, DHCPACK);
packet.yiaddr = yiaddr;
-
- if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
- memcpy(&lease_time_align, lease_time, 4);
- lease_time_align = ntohl(lease_time_align);
- if (lease_time_align > server_config.lease)
- lease_time_align = server_config.lease;
- else if (lease_time_align < server_config.min_lease)
- lease_time_align = server_config.lease;
+
+ lease_time = get_option(oldpacket, DHCP_LEASE_TIME);
+ if (lease_time) {
+ move_from_unaligned32(lease_time_aligned, lease_time);
+ lease_time_aligned = ntohl(lease_time_aligned);
+ if (lease_time_aligned > server_config.lease)
+ lease_time_aligned = server_config.lease;
+ else if (lease_time_aligned < server_config.min_lease)
+ lease_time_aligned = server_config.min_lease;
}
-
- add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
-
+
+ add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_aligned));
+
curr = server_config.options;
while (curr) {
if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
@@ -227,24 +229,29 @@ int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr)
add_bootp_options(&packet);
addr.s_addr = packet.yiaddr;
- LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr));
+ bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
- if (send_packet(&packet, 0) < 0)
+ if (send_packet(&packet, 0) < 0)
return -1;
- add_lease(packet.chaddr, packet.yiaddr, lease_time_align);
+ p_host_name = get_option(oldpacket, DHCP_HOST_NAME);
+ add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned, p_host_name);
+ if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
+ /* rewrite the file with leases at every new acceptance */
+ write_leases();
+ }
return 0;
}
-int send_inform(struct dhcpMessage *oldpacket)
+int FAST_FUNC send_inform(struct dhcpMessage *oldpacket)
{
struct dhcpMessage packet;
struct option_set *curr;
init_packet(&packet, oldpacket, DHCPACK);
-
+
curr = server_config.options;
while (curr) {
if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
diff --git a/release/src/router/busybox/networking/udhcp/serverpacket.h b/release/src/router/busybox/networking/udhcp/serverpacket.h
deleted file mode 100644
index 5a4fb276..00000000
--- a/release/src/router/busybox/networking/udhcp/serverpacket.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _SERVERPACKET_H
-#define _SERVERPACKET_H
-
-
-int sendOffer(struct dhcpMessage *oldpacket);
-int sendNAK(struct dhcpMessage *oldpacket);
-int sendACK(struct dhcpMessage *oldpacket, u_int32_t yiaddr);
-int send_inform(struct dhcpMessage *oldpacket);
-
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/signalpipe.c b/release/src/router/busybox/networking/udhcp/signalpipe.c
new file mode 100644
index 00000000..a025bd8b
--- /dev/null
+++ b/release/src/router/busybox/networking/udhcp/signalpipe.c
@@ -0,0 +1,82 @@
+/* vi: set sw=4 ts=4: */
+/* signalpipe.c
+ *
+ * Signal pipe infrastructure. A reliable way of delivering signals.
+ *
+ * Russ Dill <Russ.Dill@asu.edu> December 2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "common.h"
+
+
+static struct fd_pair signal_pipe;
+
+static void signal_handler(int sig)
+{
+ unsigned char ch = sig; /* use char, avoid dealing with partial writes */
+ if (write(signal_pipe.wr, &ch, 1) != 1)
+ bb_perror_msg("cannot send signal");
+}
+
+
+/* Call this before doing anything else. Sets up the socket pair
+ * and installs the signal handler */
+void FAST_FUNC udhcp_sp_setup(void)
+{
+ /* was socketpair, but it needs AF_UNIX in kernel */
+ xpiped_pair(signal_pipe);
+ close_on_exec_on(signal_pipe.rd);
+ close_on_exec_on(signal_pipe.wr);
+ ndelay_on(signal_pipe.wr);
+ bb_signals(0
+ + (1 << SIGUSR1)
+ + (1 << SIGUSR2)
+ + (1 << SIGTERM)
+ , signal_handler);
+}
+
+
+/* Quick little function to setup the rfds. Will return the
+ * max_fd for use with select. Limited in that you can only pass
+ * one extra fd */
+int FAST_FUNC udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
+{
+ FD_ZERO(rfds);
+ FD_SET(signal_pipe.rd, rfds);
+ if (extra_fd >= 0) {
+ close_on_exec_on(extra_fd);
+ FD_SET(extra_fd, rfds);
+ }
+ return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd;
+}
+
+
+/* Read a signal from the signal pipe. Returns 0 if there is
+ * no signal, -1 on error (and sets errno appropriately), and
+ * your signal on success */
+int FAST_FUNC udhcp_sp_read(const fd_set *rfds)
+{
+ unsigned char sig;
+
+ if (!FD_ISSET(signal_pipe.rd, rfds))
+ return 0;
+
+ if (safe_read(signal_pipe.rd, &sig, 1) != 1)
+ return -1;
+
+ return sig;
+}
diff --git a/release/src/router/busybox/networking/udhcp/socket.c b/release/src/router/busybox/networking/udhcp/socket.c
index a51a7436..edf4355b 100644
--- a/release/src/router/busybox/networking/udhcp/socket.c
+++ b/release/src/router/busybox/networking/udhcp/socket.c
@@ -1,3 +1,4 @@
+/* vi: set sw=4 ts=4: */
/*
* socket.c -- DHCP server client/server socket creation
*
@@ -22,17 +23,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <unistd.h>
-#include <string.h>
-#include <arpa/inet.h>
#include <net/if.h>
-#include <errno.h>
#include <features.h>
-#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
+#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
@@ -43,113 +36,76 @@
#include "common.h"
-int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp)
+
+int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp)
{
int fd;
struct ifreq ifr;
struct sockaddr_in *our_ip;
- memset(&ifr, 0, sizeof(struct ifreq));
- if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
- ifr.ifr_addr.sa_family = AF_INET;
- strcpy(ifr.ifr_name, interface);
+ memset(&ifr, 0, sizeof(ifr));
+ fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
- if (addr) {
- if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
- our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
- *addr = our_ip->sin_addr.s_addr;
- DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
- } else {
- LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %m");
- return -1;
- }
+ ifr.ifr_addr.sa_family = AF_INET;
+ strncpy_IFNAMSIZ(ifr.ifr_name, interface);
+ if (addr) {
+ if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr,
+ "is interface %s up and configured?", interface)
+ ) {
+ close(fd);
+ return -1;
}
-
- if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
- DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
- *ifindex = ifr.ifr_ifindex;
- } else {
- LOG(LOG_ERR, "SIOCGIFINDEX failed!: %m");
+ our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
+ *addr = our_ip->sin_addr.s_addr;
+ DEBUG("ip of %s = %s", interface, inet_ntoa(our_ip->sin_addr));
+ }
+
+ if (ifindex) {
+ if (ioctl_or_warn(fd, SIOCGIFINDEX, &ifr) != 0) {
+ close(fd);
return -1;
}
- if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
- memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
- DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
- arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
- } else {
- LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %m");
+ DEBUG("adapter index %d", ifr.ifr_ifindex);
+ *ifindex = ifr.ifr_ifindex;
+ }
+
+ if (arp) {
+ if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) {
+ close(fd);
return -1;
}
- } else {
- LOG(LOG_ERR, "socket failed!: %m");
- return -1;
+ memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
+ DEBUG("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
+ arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
}
+
close(fd);
return 0;
}
-
-int listen_socket(unsigned int ip, int port, char *inf)
+/* 1. None of the callers expects it to ever fail */
+/* 2. ip was always INADDR_ANY */
+int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
{
- struct ifreq interface;
int fd;
struct sockaddr_in addr;
- int n = 1;
-
- DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf);
- if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- DEBUG(LOG_ERR, "socket call failed: %m");
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = ip;
-
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) {
- close(fd);
- return -1;
- }
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) {
- close(fd);
- return -1;
- }
-
- strncpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ);
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) {
- close(fd);
- return -1;
- }
- if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
+ DEBUG("Opening listen socket on *:%d %s", port, inf);
+ fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ setsockopt_reuseaddr(fd);
+ if (setsockopt_broadcast(fd) == -1)
+ bb_perror_msg_and_die("SO_BROADCAST");
-int raw_socket(int ifindex)
-{
- int fd;
- struct sockaddr_ll sock;
+ /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
+ if (setsockopt_bindtodevice(fd, inf))
+ xfunc_die(); /* warning is already printed */
- DEBUG(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
- if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
- DEBUG(LOG_ERR, "socket call failed: %m");
- return -1;
- }
-
- sock.sll_family = AF_PACKET;
- sock.sll_protocol = htons(ETH_P_IP);
- sock.sll_ifindex = ifindex;
- if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
- DEBUG(LOG_ERR, "bind call failed: %m");
- close(fd);
- return -1;
- }
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ /* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */
+ xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
return fd;
}
diff --git a/release/src/router/busybox/networking/udhcp/socket.h b/release/src/router/busybox/networking/udhcp/socket.h
deleted file mode 100644
index 333994b8..00000000
--- a/release/src/router/busybox/networking/udhcp/socket.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* socket.h */
-#ifndef _SOCKET_H
-#define _SOCKET_H
-
-int read_interface(char *interface, int *ifindex, u_int32_t *addr, unsigned char *arp);
-int listen_socket(unsigned int ip, int port, char *inf);
-int raw_socket(int ifindex);
-
-#endif
diff --git a/release/src/router/busybox/networking/udhcp/static_leases.c b/release/src/router/busybox/networking/udhcp/static_leases.c
new file mode 100644
index 00000000..1e77a58f
--- /dev/null
+++ b/release/src/router/busybox/networking/udhcp/static_leases.c
@@ -0,0 +1,79 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * static_leases.c -- Couple of functions to assist with storing and
+ * retrieving data for static leases
+ *
+ * Wade Berrier <wberrier@myrealbox.com> September 2004
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "common.h"
+#include "dhcpd.h"
+
+
+/* Takes the address of the pointer to the static_leases linked list,
+ * Address to a 6 byte mac address
+ * Address to a 4 byte ip address */
+void FAST_FUNC addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t ip)
+{
+ struct static_lease *new_static_lease;
+
+ /* Build new node */
+ new_static_lease = xzalloc(sizeof(struct static_lease));
+ memcpy(new_static_lease->mac, mac, 6);
+ new_static_lease->ip = ip;
+ /*new_static_lease->next = NULL;*/
+
+ /* If it's the first node to be added... */
+ if (*lease_struct == NULL) {
+ *lease_struct = new_static_lease;
+ } else {
+ struct static_lease *cur = *lease_struct;
+ while (cur->next)
+ cur = cur->next;
+ cur->next = new_static_lease;
+ }
+}
+
+/* Check to see if a mac has an associated static lease */
+uint32_t FAST_FUNC getIpByMac(struct static_lease *lease_struct, void *mac)
+{
+ while (lease_struct) {
+ if (memcmp(lease_struct->mac, mac, 6) == 0)
+ return lease_struct->ip;
+ lease_struct = lease_struct->next;
+ }
+
+ return 0;
+}
+
+/* Check to see if an ip is reserved as a static ip */
+int FAST_FUNC reservedIp(struct static_lease *lease_struct, uint32_t ip)
+{
+ while (lease_struct) {
+ if (lease_struct->ip == ip)
+ return 1;
+ lease_struct = lease_struct->next;
+ }
+
+ return 0;
+}
+
+#if ENABLE_UDHCP_DEBUG
+/* Print out static leases just to check what's going on */
+/* Takes the address of the pointer to the static_leases linked list */
+void FAST_FUNC printStaticLeases(struct static_lease **arg)
+{
+ struct static_lease *cur = *arg;
+
+ while (cur) {
+ printf("PrintStaticLeases: Lease mac Value: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ cur->mac[0], cur->mac[1], cur->mac[2],
+ cur->mac[3], cur->mac[4], cur->mac[5]
+ );
+ printf("PrintStaticLeases: Lease ip Value: %x\n", cur->ip);
+ cur = cur->next;
+ }
+}
+#endif
diff --git a/release/src/router/busybox/networking/udhcp/version.h b/release/src/router/busybox/networking/udhcp/version.h
deleted file mode 100644
index 3862539f..00000000
--- a/release/src/router/busybox/networking/udhcp/version.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _UDHCP_VERSION_H
-#define _UDHCP_VERSION_H
-
-#define VERSION "0.9.9-pre"
-
-#endif