Commit Graph
100 Commits
Author SHA1 Message Date
Nicholas J. Kain 6047f04a12 Guard against carrier being spuriously set down.
Corrects a possible regression introduced by the previous patch.
2022-01-11 22:16:44 -05:00
Nicholas J. Kain f3766990f9 Speed up interface carrier checking.
This is done by performing one synchronous query for carrier state at
the start of the program; after that, we just monitor the nlsocket for
carrier state changes and update the cached state accordingly.

The benefit is that ifchd needs to do a lot less work and this should
reduce the CPU cycle consumption; prior to this commit, the CPU time
ends up being a few CPU-minutes per month.
2021-04-25 05:55:01 -04:00
Nicholas J. Kain ad1546ecb0 ifchd: Minor corrections in informative prints 2021-04-25 05:45:21 -04:00
Nicholas J. Kain d61902cad4 ifchd: Better handle incomplete command buffers.
Before the handling would constantly acculmulate a prefix of previous
incomplete commands.  Now it still has a latent defect where the entire
buffer will be discarded given a spurious command, but ndhc shouldn't
generate such commands so it shouldn't matter.
2021-04-25 05:45:21 -04:00
Nicholas J. Kain eb463ab086 poll() revents bits are reset by poll() 2021-04-25 05:45:21 -04:00
Nicholas J. Kain c8eb238f31 ifchd-parse: Simplify leftover-buffer copying. 2021-04-24 20:50:08 -04:00
Nicholas J. Kain b8bffa16c5 Build without -fno-strict-overflow.
I only built with this flag to mitigate accidental UB.  Now that
UBSan exists, there's no point as UBSan does better and actually
allows offending code to be located and fixed easily.
2020-11-25 04:44:26 -05:00
Nicholas J. Kain 28e1b34bac Simplify logging and fix some format specifiers. 2020-11-24 21:02:51 -05:00
Nicholas J. Kain 2e3c504cc5 Add and use safe_ftruncate() wrapper. 2020-11-06 18:47:51 -05:00
Nicholas J. Kain a91b1d34ac Check and clear events from poll() even if interrupted by signal. 2020-11-06 18:32:38 -05:00
Nicholas J. Kain 1e60b4b8e7 Optimize internet checksum to use 32-bit fetches.
It's actually not very hard to do everything with 32-bit fetches
and 32-bit registers, aside from the necessary bit fetches for
tails.
2020-11-01 01:06:58 -04:00
Nicholas J. Kain ff8b910222 Rename net_checksum161c to net_checksum16.
How many characters are summed at a time is an irrelevant
implementation detail.
2020-10-27 14:45:15 -04:00
Nicholas J. Kain 918555219b Make fingerprinting more robust with rapid carrier state changes.
The existing code tracked the fingerprinting completion state with
a bool, which is insufficient; what is required is a tristate
(none|inprogress|done) where the inprogress state reverts to
none on carrier down, but done state stays done on carrier down.
2020-10-27 14:14:18 -04:00
Nicholas J. Kain d07469a5fa Optimize internet checksum to use 16-bit fetches.
We could use 32-bit fetches with the same technique on 64-bit
architectures, or SIMD could be used to do very fast 128-bit
fetches, but this isn't a performance bottleneck and this
method is very simple and relatively fast.
2020-10-24 17:14:20 -04:00
Nicholas J. Kain 5fdf3bd83e Remove unused definitions from CMakeLists.txt. 2020-10-24 15:45:57 -04:00
Nicholas J. Kain b86735c478 Minor signal handling fixes. 2020-10-21 09:49:22 -04:00
Nicholas J. Kain d58338b70b serverid checks for RENEW and REBIND DHCP(ACK|NAK) were too strict.
Use the same test that is already used for the DHCPACK sent by
the server in the REQUESTING state.
2020-10-21 06:47:11 -04:00
Nicholas J. Kain b07ebb60a2 Revert bb7841f3ee.
That trivial warning fix causes warnings with -Wcast-qual, which
is a more valid warning than whatever was causing the warnings
under -Wall -pedantic with the normal Makefile.
2020-10-20 07:55:47 -04:00
Nicholas J. Kain 48bbb0b805 Add a missing newline to an error message.
I'm almost certain I remember adding this before, but I guess
it somehow got lost.
2020-10-20 07:53:23 -04:00
Nicholas J. Kain bb7841f3ee Trivial warning fix. 2020-10-20 07:18:49 -04:00
Nicholas J. Kain e6b5247d54 Update the plain Makefile. 2020-10-20 07:18:19 -04:00
Nicholas J. Kain 1ba7c9a2ba Documentation update -- signalfd and epoll aren't used anymore. 2020-10-20 07:06:19 -04:00
Nicholas J. Kain f1e20305ba Don't depend on external ncmlib. 2020-10-20 07:00:20 -04:00
Nicholas J. Kain 4575f74164 Remove legacy support for exiting after obtaining a DHCP lease. 2020-10-20 06:55:04 -04:00
Nicholas J. Kain ade4e988af Remove legacy support for forking to background. 2020-10-20 06:55:04 -04:00
Nicholas J. Kain 58067200d6 Remove legacy support for writing a pidfile. 2020-10-20 06:55:04 -04:00
Nicholas J. Kain 4d33c00e04 Use poll() instead of epoll() for ndhc-master. 2020-10-20 05:58:29 -04:00
Nicholas J. Kain af9d45719f Use poll() instead of epoll() for ifchd and sockd.
poll() is simpler, portable, and the scalability advantages of
epoll are inapplicable here.
2020-10-20 05:41:09 -04:00
Nicholas J. Kain 06a541261e Stop using signalfd and audit signal handling code.
There's really no advantage to using signalfd in ndhc, particularly
since the normal POSIX signal API is now used for handling SIGCHLD in
ndhc-master.  So just use the tried and true volatile sig_atomic_t set
and check approach.

The only intended behavior change is in the dhcp RELEASE state --
before there would be a spurious attempt at renewing a nonexistent
lease when the RENEW signal was received.
2020-10-20 04:42:58 -04:00
Nicholas J. Kain 8d89ca9f19 Reliably force restart when a subprocess has a fatal error.
Suppose a system call such as bind() fails in the sockd subprocess in
request_sockd_fd().  sockd will suicide().  This will send a SIGCHLD to
the master process, which the master process should respond to by
calling suicide(), forcing a process supervisor to respawn the entire
ndhc program.

But, this doesn't reliably happen prior to this commit because of the
interaction between request_sock_fd() and signalfd() [or equivalently
self-pipe-trick] signal handling.

request_sock_fd() makes ndhc-master synchronously wait for a response
from sockd via safe_recvmsg().  The normal goto-like signal handling
path is suppressed when using signalfd() , so when SIGCHLD is received,
it will not be handled until io is dispatched for the signalfd or pipe.
But such code will never be reached because ndhc-master is waiting in
safe_recvmsg() and thus never polls signal fd status.

So, revert to using traditional POSIX sigaction() for SIGCHLD, which
provides exactly the required behavior for proper functioning.
2020-10-20 04:41:51 -04:00
Nicholas J. Kain f0340b1475 Correct ba046c02c7.
Apparently I had forgotten the counter-intuitive semantics of
signalfd(): it's necessary to BLOCK the signals that will be
handled exclusively by signalfd() so that the default POSIX
signal handling mechanism won't intercept the signals first.

The lack of response to ctrl+c is a legitimate bug that is
now properly fixed; ba046c02c7 fixed that issue, but
regressed the handling of other signals.
2020-10-19 13:03:35 -04:00
Nicholas J. Kain 32bc422d0e Add a heuristic to detect when server ignores dhcp renews.
If we get no response to three renews (unicast), switch to sending
rebinds (broadcast).  Servers are supposed to always reply with
a DHCPACK or DHCPNAK even if the server doesn't update its internal
lease duration database, so this behavior should be RFC compliant.
2020-10-19 07:03:03 -04:00
Nicholas J. Kain f4365897bc Make renew and rebinding directly track whether DHCPREQUEST was sent.
Before it was inferred by examining timeouts.  Also, simplify
the associated timeout code so that there are no longer effectively
two redundant paths.
2020-10-19 06:36:26 -04:00
Nicholas J. Kain 4df035ced3 Make sure xids in packets sent conform to RFC2131 pg36 table5. 2020-10-19 05:48:52 -04:00
Nicholas J. Kain 5dc35eca6d Merge send_renew() and send_rebind() into send_renew_or_rebind(). 2020-10-19 05:26:47 -04:00
Nicholas J. Kain 23d23c108a DHCPREQUEST in REBINDING state shouldn't have reqip option.
See RFC2131 pg31 paragraph 6.
2020-10-19 05:13:47 -04:00
Nicholas J. Kain 9b8c63d998 Give up on fingerprinting router/gateway if it doesn't reply. 2020-10-19 04:28:06 -04:00
Nicholas J. Kain 87ac82fa45 Add back project() for CMake. Corrects regression in c5a1edd5f6. 2020-10-19 04:28:06 -04:00
Nicholas J. Kain b2af308647 Trivial refactoring. 2020-10-19 04:28:06 -04:00
Nicholas J. Kain 7bd551d564 Give up on fingerprinting relay agent/server if it doesn't reply.
Try to send/wait three times; then if there's no response, then
assume that the relay agent is ignoring or firewalled from
receiving ARP requests.
2020-10-19 04:28:06 -04:00
Nicholas J. Kain ba046c02c7 Make custom SIGUSR signals work again.
These were broken long ago when converting from signal()
to sigprocmask().  This change also makes ctrl+c work again.
2020-09-02 21:04:59 -04:00
Nicholas J. Kain fb143995d2 Silence unused variable warnings in Ragel-generated code. 2019-01-01 01:10:34 -05:00
Nicholas J. Kain 253a97662d sockd: Preserve a const qualifier. 2018-10-26 13:07:37 -04:00
Nicholas J. Kain 3f5285b7ce options.c: Remove an unnecessary cast. 2018-10-26 13:07:19 -04:00
Nicholas J. Kain c5a1edd5f6 Use more modern CMake syntax. 2018-10-26 13:07:05 -04:00
Nicholas J. Kain 56b6ae2cd3 Quit using NULL macro. 2018-10-26 07:17:39 -04:00
Nicholas J. Kain 05a075aeb2 Replace '(c)' with 'Copyright'.
'(c)' may not be a valid substitute for 'Copyright' in some legal
domains/interpretations.  So be safe, since I obviously am asserting
copyright on my legal work.
2018-10-26 07:11:16 -04:00
Nicholas J. Kain 8983df3c86 Update copyright dates. 2018-02-18 08:25:10 -05:00
Nicholas J. Kain a66f007931 Trivial documentation updates. 2018-02-18 08:25:10 -05:00
Nicholas J. Kain e08d3b15b5 Remove seccomp support.
It breaks with the existing whitelists on the latest glibc and is
just too much maintenance burden.  It also causes the most questions
for new users.

Something like openbsd's pledge() would be fine, but I have no
intention of maintaining such a thing.

Most of the value-gain would come from disallowing high-risk
syscalls like ptrace() and the perf syscalls, anyway.

ndhc already uses extensive defense-in-depth and wasn't using
seccomp on non-(x86|x86-64) platforms, so it's not a huge loss.
2018-02-09 03:33:04 -05:00
Nicholas J. Kain e8d97205e9 Compile cleanly with -Wsign-conversion.
I didn't notice anything that worried me.
2018-02-09 03:16:59 -05:00
Nicholas J. Kain c8dd123a5d README.md: Trivial fix to download links. 2017-10-04 05:33:36 -04:00
Nicholas J. Kain 3e4812eb35 README.md: Cosmetic improvements. 2017-09-23 15:17:59 -04:00
Nicholas J. Kain 8bb00c9c36 Convert the README to Markdown README.md. 2017-09-23 12:18:28 -04:00
Nicholas J. Kain b6dda8f4f8 Update README. Mention the ncmlib requirement and make it more succinct. 2017-08-24 14:06:56 -04:00
Nicholas J. Kain 759b6bd831 Update to the new ncmlib random API. 2017-08-24 02:36:31 -04:00
Nicholas J. Kain 0732ed5f84 Disable GCC7 warning implicit-fallthrough and unused-const-variable 2017-05-13 13:14:35 -04:00
Nicholas J. Kain ed44a90114 state: Faster recovery when carrier lost during DHCP init.
If carrier is lost before network fingerprinting is complete, we
have a few problems; first, we don't know whether the network has
changed underneath us.  Second, we've not yet configured the
interface properties, and it is not unlikely that doing so will
fail as the underlying network device may have been destroyed
and recreated during this time (eg, if ethtool has been run at
start-up time).

Thus, the safest reaction is to terminate and force a supervisor
respawn.  It is best to do this once carrier recovers, not when
the carrier is lost, as it is more likely to minimize delays.
2017-04-10 10:07:34 -04:00
Nicholas J. Kain 369ff59cab arp: Take extra care to preserve last received ARP packet. 2017-04-10 10:07:34 -04:00
Nicholas J. Kain 7af3e64a99 arp: Remove reply_offset, and keep previous ARP packet after epoll.
ARP packets aren't split across multiple receive events, so
reply_offset is pointless, and we implicitly assume that the
previous ARP packet data is still available after a forced sleep.
2017-04-10 08:56:11 -04:00
Nicholas J. Kain bdad082a62 Remove -Wformat=2 -Wformat-nonliteral for C++. 2017-03-16 23:05:23 -04:00
Nicholas J. Kain 3633d55296 Enable -fno-strict-overflow just to be safer. 2017-03-16 21:59:55 -04:00
Nicholas J. Kain 348e975f2d reinit_shared_deconfig() was not fully resetting arp state. 2017-02-27 11:30:35 -05:00
Nicholas J. Kain 8ca0d28f61 reinit_shared_deconfig() was not resetting state completely.
Newer flags were not being restored properly.
2017-02-27 11:10:14 -05:00
Nicholas J. Kain 2a26acacdd Handle possible clock_gettime() errors in curms().
Use curms() instead of new clock_gettime() call points, too.
2017-02-24 08:51:36 -05:00
Nicholas J. Kain a39f1dabfe Fix a typo in clock_gettime error path print that I somehow overlooked. 2017-02-24 08:39:27 -05:00
Nicholas J. Kain 7f08d4b6fb arp: Handle initial gateway query asynchronously and retry failures.
The gateway/router MAC fingerprinting could perhaps be done more
robustly in the face of suspend or carrier loss, but the time window
in which things could get confused is very small and I would rather
just rely on supervisor respawn in that case.

Even this case I don't think I've ever seen.
2017-02-24 07:39:14 -05:00
Nicholas J. Kain 7080850f38 Silence a spurious ARP defense message from previous commit. 2017-02-24 06:57:10 -05:00
Nicholas J. Kain 34a8cd7ad9 arp: Handle initial announcement asynchronously and retry failures.
We need to send two ARP announcements, so these are now done via a
timeout callback so that failures can be handled properly.
2017-02-24 06:57:10 -05:00
Nicholas J. Kain 4d87d5075a Handle carrier interruptions in arp_collision_timeout() better.
Still not ideal; we need to note and retry these errors, but these
changes are preparatory and do not introduce regressions.
2017-02-24 05:36:05 -05:00
Nicholas J. Kain 09d5e9ad3c arp: If first ARP announce fails, rely on the second announce.
The previous approach would desynchronize the state machine if the
carrier is paused after receiving the lease but before sending the
announce, since we have received a lease already.

This change is an improvement but is still not ideal.
2017-02-24 04:57:33 -05:00
Nicholas J. Kain fa1c5d3a0c Add a comment describing link_set_flags() return values. 2017-01-19 05:22:22 -05:00
Nicholas J. Kain 1c2a39c544 Reorder client_config_t members to reduce structure padding. 2017-01-19 05:20:29 -05:00
Nicholas J. Kain 4fdde404aa Remove unused client_config_t foreground variable. 2017-01-19 05:18:04 -05:00
Nicholas J. Kain c38fd2be9b Convert logical booleans in client_config_t to bool type. 2017-01-19 05:13:30 -05:00
Nicholas J. Kain 571b22c4b2 Rename client_state_t init variable to program_init.
Easier to grep.  No functional change.
2017-01-19 05:05:35 -05:00
Nicholas J. Kain 931530786b Convert logically boolean client_state_t variables from uint8_t to bool. 2017-01-19 05:01:23 -05:00
Nicholas J. Kain b8ee0bd5c2 Update copyright dates to 2017. 2017-01-13 20:15:27 -05:00
Nicholas J. Kain 29498f5341 Remove ifsPrevState and set non-infinite timeout on a send error.
We instead check carrier status as needed.  This approach is more
robust.  For a simple example, imagine link state changes that happen
while the machine is suspended.
2017-01-13 20:15:27 -05:00
Nicholas J. Kain c47630ffca Rename check_carrier() to carrier_isup() and use bool return. 2017-01-12 05:25:15 -05:00
Nicholas J. Kain 1fc7bd3144 Eliminate fopen() in cfg.rl. Use unbuffered i/o instead.
This is fairly tricky, but fopen() almost surely interally calls malloc
when it creates the FILE* that it returns.  I did promise that
ndhc doesn't call malloc after initialization, besides what libc may
do internally, but it feels a bit dishonest given that fopen() is
basically sure to do so on any general-purpose libc.

Thus, eliminate it and just use direct POSIX i/o.

With the previous pidfile changes, ndhc doesn't use C fopen() at all.

In practice, this change won't really be noticeable as most libcs,
particularly with dynamic linking, will end up calling malloc themselves
during program initialization before main() is invoked.
2016-05-06 18:21:13 -04:00
Nicholas J. Kain 04ec7c8f4b Update to latest write_pid semantics and don't write pidfile by default.
There was no way to disable writing pidfiles before.

pidfiles are an unreliable method of tracking processes, anyway; process
supervisors are strongly recommended.  If a pidfile is really needed, it
can be explicitly specified.
2016-05-06 15:00:31 -04:00
Nicholas J. Kain a47a2feea1 Support resolv_conf.head and resolv_conf.tail.
These will be used if they exist at initialization.
Operations are all done by acting on pre-opened fds.
2016-05-06 06:45:16 -04:00
Nicholas J. Kain 313da14518 Update nl.[ch] to latest. No functional change for ndhc. 2016-05-06 06:36:01 -04:00
Nicholas J. Kain a4ea869a54 README: Trivial style edits. 2015-12-27 01:00:18 -05:00
Nicholas J. Kain 5ab36719f1 If a fd closes unexpectedly in epoll, print error and exit with failure.
Before the exit code would be success and no error message would print,
and it required a bit of control flow tracing to determine what would
actually happen.

No direct functional change (unless the supervising process cares about
the return code of ndhc on exit).
2015-12-25 02:44:54 -05:00
Nicholas J. Kain ae16e26d00 arp: Fix case where changing interface properties consistently fails.
If changing interface properties fails after getting a lease, it is
possible under some strange conditions for the failure to be
persistent.  This seems to happen if the carrier cycles off and on
several times during ndhc initialization.

Since this issue is very hard to replicate, the most conservative
thing to do here is to simply have ndhc suicide itself so it can
be respawned by a process supervisor.

Logs of the issue in practice:

(carrier is down while the daemon is started here, it seems)

16:57:09.638979845 ndhc-ifch seccomp filter installed.  Please disable seccomp if you
16:57:09.638989136 Discovering DHCP servers...
16:57:09.638991371 (send_dhcp_raw) carrier down; sendto would fail
16:57:09.638993318 Failed to send a discover request packet.
 ...
16:57:13.636519925 Discovering DHCP servers...
16:57:13.651462476 Received IP offer: X from server Y via Z
 ...
16:57:13.912592571  wan0: Gateway router set to: A
16:57:13.912607463  wan0: arp: Searching for dhcp server and gw addresses...
16:57:14.635532676  wan0: Carrier down.
17:04:32.983897760  wan0: arp: Still looking for gateway hardware address...
17:04:32.984158226  wan0: arp: Still looking for DHCP agent hardware address...
17:04:32.984781255  wan0: Interface is back.  Revalidating lease...
17:04:32.985585501  wan0: arp: Gateway hardware address B
17:04:32.985590436  wan0: arp: DHCP agent hardware address C
17:04:38.234857403  wan0: arp: Still waiting for gateway to reply to arp ping...
17:04:38.235109016  wan0: arp: Still waiting for DHCP agent to reply to arp ping...
16:57:24.165620224  wan0: arp: Still waiting for gateway to reply to arp ping...
16:57:29.169621070  wan0: arp: DHCP agent and gateway didn't reply.  Getting new lease.
16:57:29.217710616  wan0: Discovering DHCP servers...
16:57:29.249645130  wan0: Received IP offer: X from server Y via Z
16:57:29.249657203  wan0: Sending a selection request for X...
16:57:29.285632973  wan0: Received ACK: X from server Y via Z
16:57:29.297717159  wan0: arp: Probing for hosts that may conflict with our lease...
16:57:29.360249458  wan0: arp: Probing for hosts that may conflict with our lease...
16:57:29.435114526  wan0: arp: Probing for hosts that may conflict with our lease...
16:57:29.500473345  wan0: Lease of X obtained.  Lease time is D seconds.
16:57:29.500485894  wan0: Failed to set the interface IP address and properties!
 ...
And the final two errors repeat.  Restarting ndhc by hand instantly
fixes the issue.

So there's a lot going on -- bizzare clock skew, and carrier flickering
on and off.
2015-10-28 20:20:21 -04:00
Nicholas J. Kain e0b5ff8eaf perform_carrier() should not cause ifchd to terminate on failure.
This requires execute_buffer() and its callers to distinguish between
fatal and non-fatal errors.  The -99 return value was already used for
non-recoverable errors that should force the daemon to restart, but the
execute_buffer() callers treated any non-success return as a fatal
error.

There a judgement call here on how to handle various error types.  I
choose to assume that failures to set the IP address, netmask, broadcast
address, or default router are fatal errors.  ndhc should be run from
process supervision, and this will trigger a daemon restart, which will
allow the machine to recover as soon as the problem (probably on the
dhcp server or local kernel state outside of ndhc's control) is
corrected.

This change corrects errors such as:

Discovering DHCP servers...
(process_client_socket) received invalid commands: 'carrier:;'
(send_dhcp_raw) carrier down; sendto would fail
Failed to send a discover request packet.

which happened if ndhc is started on a machine where the network
interface is down.  After this change, ndhc should function as intended
by going to sleep until the carrier returns rather than terminating
itself to be restarted by the process supervisor until carrier returns.
2015-07-03 00:49:13 -04:00
Nicholas J. Kain 12d8af4c67 Convert remaining ull time-types to ll.
Thus signed/unsigned conversion issues can't be a problem.

The extra range provided by ull isn't useful, either, since
we're dealing with uint32_t time_t seconds converted to ns,
which doesn't come close to exhausting the amount of post-epoch
ns that will be consumed until after 2100AD.
2015-05-27 23:40:28 -04:00
Nicholas J. Kain 277f0f67c5 When converting timeout from ll to int, also guard against underflow. 2015-05-27 15:00:02 -04:00
Nicholas J. Kain e02d30dcc5 renewTime, rebindTime should be unsigned long long.
While we're at it, rearrange the client state struct to
save some space lost to padding.
2015-05-27 13:11:23 -04:00
Nicholas J. Kain abb1b54bfe Fix an overflow that can cause spuriously short epoll timeouts.
Lease times and arp timeouts are all calculated using long long,
but epoll takes its timeout argument as an int.  Guard against
timeouts > INT_MAX but < UINT_MAX wrapping and causing spuriously
short timeouts when converted to a signed int.

This problem has been observed in the wild.  Thanks to thypon
for a detailed strace that pointed me towards this issue.
2015-05-27 12:58:42 -04:00
Nicholas J. Kain ba875d4b2e Failsafe should only trigger is the new timeout is also zero.
This is what I get for rushing!
2015-05-27 12:35:16 -04:00
Nicholas J. Kain f061a78a18 Fix dumb mistake in patch before last; epoll timeout is in ms, not s. 2015-05-27 12:29:46 -04:00
Nicholas J. Kain 2057d7cd18 Improve compatibility with clang. 2015-05-27 12:23:50 -04:00
Nicholas J. Kain 8273b383ab Add a failsafe to prevent epoll busy-spin. 2015-05-27 12:23:16 -04:00
Nicholas J. Kain 6c136c3f85 Make add_option_(vendor|hostname)() not use ndhc internals.
This change makes it easier to fuzz test, but should have no
functional effect on ndhc's behavior.
2015-02-20 03:58:25 -05:00
Nicholas J. Kain 646931a2bf xid should be regenerated whenever we start a new discover cycle.
Somewhere along the line it quit being set at the start of discovery
and was always 0.  This is clearly not desired behavior.

Found by manual examination of packets while fuzzing the options
parser.
2015-02-20 03:48:13 -05:00
Nicholas J. Kain b8df1b33f5 Fix the timeouts for rebinding and renewing.
Now renew/rebind requests will be sent every 60+/-10s.
2015-02-18 11:03:58 -05:00
Nicholas J. Kain b3bd13d45f Fix the return values of dhcp_packet_get and arp_packet_get.
This corrects a bug where stale dhcp packets would get reprocessed,
causing very bad behavior; an issue that was introduced in the
coroutine conversion.
2015-02-18 11:02:13 -05:00