summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNiklas Goby2011-11-23 11:56:19 +0100
committerNiklas Goby2011-11-23 11:56:19 +0100
commitc0b6b199a9878bc1e95907200501211c09c1e66c (patch)
tree0079c34c6536e5f1d0414aebde1793db60a78f35 /src
parentdeleted the NetworkDiscovery and UnixDomainSocketServer folder (diff)
downloadfbgui-c0b6b199a9878bc1e95907200501211c09c1e66c.tar.gz
fbgui-c0b6b199a9878bc1e95907200501211c09c1e66c.tar.xz
fbgui-c0b6b199a9878bc1e95907200501211c09c1e66c.zip
created modules
Diffstat (limited to 'src')
-rw-r--r--src/common/fbgui.h30
-rw-r--r--src/customdhcpcd/.gitignore5
-rw-r--r--src/customdhcpcd/CMakeLists.txt17
-rw-r--r--src/customdhcpcd/README45
-rw-r--r--src/customdhcpcd/arp.c284
-rw-r--r--src/customdhcpcd/arp.h39
-rw-r--r--src/customdhcpcd/client.c1149
-rw-r--r--src/customdhcpcd/client.h35
-rw-r--r--src/customdhcpcd/common.c249
-rw-r--r--src/customdhcpcd/common.h68
-rw-r--r--src/customdhcpcd/config.h133
-rw-r--r--src/customdhcpcd/configure.c814
-rw-r--r--src/customdhcpcd/configure.h38
-rw-r--r--src/customdhcpcd/dhcp.c933
-rw-r--r--src/customdhcpcd/dhcp.h215
-rw-r--r--src/customdhcpcd/dhcpcd.c671
-rw-r--r--src/customdhcpcd/dhcpcd.h108
-rw-r--r--src/customdhcpcd/dhcpcd.sh46
-rw-r--r--src/customdhcpcd/discover.c7
-rw-r--r--src/customdhcpcd/discover.h12
-rw-r--r--src/customdhcpcd/duid.c118
-rw-r--r--src/customdhcpcd/duid.h42
-rw-r--r--src/customdhcpcd/info.c472
-rw-r--r--src/customdhcpcd/info.h42
-rw-r--r--src/customdhcpcd/interface.c1060
-rw-r--r--src/customdhcpcd/interface.h173
-rw-r--r--src/customdhcpcd/ipv4ll.c70
-rw-r--r--src/customdhcpcd/ipv4ll.h39
-rw-r--r--src/customdhcpcd/logger.c154
-rw-r--r--src/customdhcpcd/logger.h48
-rw-r--r--src/customdhcpcd/logwriter.c260
-rw-r--r--src/customdhcpcd/logwriter.h40
-rw-r--r--src/customdhcpcd/signal.c183
-rw-r--r--src/customdhcpcd/signal.h40
-rw-r--r--src/customdhcpcd/socket.c647
-rw-r--r--src/customdhcpcd/socket.h46
-rw-r--r--src/customdhcpcd/version.h1
-rw-r--r--src/fbgui/downloadmanager.cpp (renamed from src/downloadmanager.cpp)0
-rw-r--r--src/fbgui/downloadmanager.h (renamed from src/downloadmanager.h)0
-rw-r--r--src/fbgui/fbgui.cpp (renamed from src/fbgui.cpp)0
-rw-r--r--src/fbgui/fbgui.h (renamed from src/fbgui.h)0
-rw-r--r--src/fbgui/fbgui.pro (renamed from src/fbgui.pro)0
-rw-r--r--src/fbgui/fbgui.qrc (renamed from src/fbgui.qrc)0
-rw-r--r--src/fbgui/html/background.png (renamed from src/html/background.png)bin364392 -> 364392 bytes
-rw-r--r--src/fbgui/html/continueBoot.html (renamed from src/html/continueBoot.html)0
-rw-r--r--src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png (renamed from src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png)bin260 -> 260 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png (renamed from src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png)bin251 -> 251 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png (renamed from src/html/css/images/ui-bg_flat_10_000000_40x100.png)bin178 -> 178 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png (renamed from src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png)bin104 -> 104 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png (renamed from src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png)bin125 -> 125 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png (renamed from src/html/css/images/ui-bg_glass_65_ffffff_1x400.png)bin105 -> 105 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png (renamed from src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png)bin3762 -> 3762 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png (renamed from src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png)bin90 -> 90 bytes
-rw-r--r--src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png (renamed from src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png)bin129 -> 129 bytes
-rw-r--r--src/fbgui/html/css/images/ui-icons_222222_256x240.png (renamed from src/html/css/images/ui-icons_222222_256x240.png)bin4369 -> 4369 bytes
-rw-r--r--src/fbgui/html/css/images/ui-icons_228ef1_256x240.png (renamed from src/html/css/images/ui-icons_228ef1_256x240.png)bin4369 -> 4369 bytes
-rw-r--r--src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png (renamed from src/html/css/images/ui-icons_ef8c08_256x240.png)bin4369 -> 4369 bytes
-rw-r--r--src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png (renamed from src/html/css/images/ui-icons_ffd27a_256x240.png)bin4369 -> 4369 bytes
-rw-r--r--src/fbgui/html/css/images/ui-icons_ffffff_256x240.png (renamed from src/html/css/images/ui-icons_ffffff_256x240.png)bin4369 -> 4369 bytes
-rw-r--r--src/fbgui/html/css/jquery-ui-1.8.16.css (renamed from src/html/css/jquery-ui-1.8.16.css)0
-rw-r--r--src/fbgui/html/images/loading.gif (renamed from src/html/images/loading.gif)bin8787 -> 8787 bytes
-rw-r--r--src/fbgui/html/js/jquery-1.6.4.min.js (renamed from src/html/js/jquery-1.6.4.min.js)0
-rw-r--r--src/fbgui/html/js/jquery-ui-1.8.16.min.js (renamed from src/html/js/jquery-ui-1.8.16.min.js)0
-rw-r--r--src/fbgui/html/js/networkDiscovery.js (renamed from src/html/js/networkDiscovery.js)0
-rw-r--r--src/fbgui/html/loadsystem.css (renamed from src/html/loadsystem.css)0
-rw-r--r--src/fbgui/html/loadsystem.html (renamed from src/html/loadsystem.html)0
-rw-r--r--src/fbgui/html/networkdiscovery.css (renamed from src/html/networkdiscovery.css)0
-rw-r--r--src/fbgui/html/networkdiscovery.html (renamed from src/html/networkdiscovery.html)0
-rw-r--r--src/fbgui/html/networkdiscovery_debug.html (renamed from src/html/networkdiscovery_debug.html)0
-rw-r--r--src/fbgui/html/networkdiscovery_userchoice.html (renamed from src/html/networkdiscovery_userchoice.html)0
-rw-r--r--src/fbgui/html/networkdiscovery_userchoice_debug.html (renamed from src/html/networkdiscovery_userchoice_debug.html)0
-rw-r--r--src/fbgui/html/old.png (renamed from src/html/old.png)bin316905 -> 316905 bytes
-rw-r--r--src/fbgui/html/preload-debug.html (renamed from src/html/preload-debug.html)0
-rw-r--r--src/fbgui/html/preload.css (renamed from src/html/preload.css)0
-rw-r--r--src/fbgui/html/preload.html (renamed from src/html/preload.html)0
-rw-r--r--src/fbgui/interfaceconfiguration.cpp (renamed from src/interfaceconfiguration.cpp)0
-rw-r--r--src/fbgui/interfaceconfiguration.h (renamed from src/interfaceconfiguration.h)0
-rw-r--r--src/fbgui/javascriptinterface.cpp (renamed from src/javascriptinterface.cpp)0
-rw-r--r--src/fbgui/javascriptinterface.h (renamed from src/javascriptinterface.h)0
-rw-r--r--src/fbgui/loggerengine.cpp (renamed from src/loggerengine.cpp)0
-rw-r--r--src/fbgui/loggerengine.h (renamed from src/loggerengine.h)0
-rw-r--r--src/fbgui/main.cpp (renamed from src/main.cpp)0
-rw-r--r--src/fbgui/ndgui.cpp (renamed from src/ndgui.cpp)0
-rw-r--r--src/fbgui/ndgui.h (renamed from src/ndgui.h)0
-rw-r--r--src/fbgui/networkdiscovery.cpp (renamed from src/networkdiscovery.cpp)0
-rw-r--r--src/fbgui/networkdiscovery.h (renamed from src/networkdiscovery.h)0
-rw-r--r--src/fbgui/networkmanager.cpp (renamed from src/networkmanager.cpp)0
-rw-r--r--src/fbgui/networkmanager.h (renamed from src/networkmanager.h)0
-rw-r--r--src/fbgui/sysinfo.cpp (renamed from src/sysinfo.cpp)0
-rw-r--r--src/fbgui/sysinfo.h (renamed from src/sysinfo.h)0
90 files changed, 8333 insertions, 0 deletions
diff --git a/src/common/fbgui.h b/src/common/fbgui.h
new file mode 100644
index 0000000..9e2c0be
--- /dev/null
+++ b/src/common/fbgui.h
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2010,2011 - RZ Uni Freiburg
+ * Copyright (c) 2010,2011 - OpenSLX Project
+ *
+ * This program/file is free software distributed under the GPL version 2.
+ * See http://openslx.org/COPYING
+ *
+ * If you have any feedback please consult http://openslx.org/feedback and
+ * send your feedback to feedback@openslx.org
+ *
+ * General information about OpenSLX can be found under http://openslx.org
+ */
+
+
+
+#ifndef COMMON_FBGUI_H
+#define COMMON_FBGUI_H
+
+#define DEFAULT_INTERFACE_CONF_LOCATION "/var/tmp/conf_"
+#define DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default"
+#define DHCP_MESSAGE_SIZE 2048
+#define ACK_SIZE 4
+
+#define DHCPCD_EXIT 9
+#define DHCPCD_ARP_TEST 10
+#define DHCPCD_CONFIGURE 11
+#define DHCPCD_WRITE 12
+#define DHCPCD_LOG 13
+
+#endif // COMMON_FBGUI_H
diff --git a/src/customdhcpcd/.gitignore b/src/customdhcpcd/.gitignore
new file mode 100644
index 0000000..e531d2b
--- /dev/null
+++ b/src/customdhcpcd/.gitignore
@@ -0,0 +1,5 @@
+*.o
+dhcpcd
+dhcpcd.8
+dhcpcd-*.bz2
+build
diff --git a/src/customdhcpcd/CMakeLists.txt b/src/customdhcpcd/CMakeLists.txt
new file mode 100644
index 0000000..a716a5a
--- /dev/null
+++ b/src/customdhcpcd/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(customdhcpdcd)
+
+set(CMAKE_C_FLAGS "-lrt")
+
+set(CUSTOMDHCPCD_SOURCES arp.c configure.c info.c logger.c socket.c client.c discover.c interface.c logwriter.c
+common.c dhcp.c duid.c ipv4ll.c signal.c)
+
+#file(GLOB_RECURSE CUSTOMDHCPCD_SOURCES *.c)
+file(GLOB_RECURSE CUSTOMDHCPCD_HEADERS *.h)
+
+add_library(customdhcpcd SHARED ${CUSTOMDHCPCD_SOURCES} ${CUSTOMDHCPCD_HEADERS})
+
+#add_executable(customdhcpcd ${CUSTOMDHCPCD_SOURCES})
+add_executable(cdhcpcd dhcpcd.c)
+target_link_libraries(cdhcpcd customdhcpcd )
diff --git a/src/customdhcpcd/README b/src/customdhcpcd/README
new file mode 100644
index 0000000..9089ec6
--- /dev/null
+++ b/src/customdhcpcd/README
@@ -0,0 +1,45 @@
+dhcpcd-3 - DHCP client daemon
+Copyright 2006-2008 Roy Marples <roy@marples.name>
+
+
+Installation
+------------
+Edit config.h to match your building requirements.
+
+Take special note of ENABLE_DUID and unset it if the target media is
+volatile, like say a LiveCD.
+
+Then just make; make install
+
+man dhcpcd for command line options
+
+
+Notes
+-----
+If you're cross compiling you may need to send HAVE_FORK=yes or HAVE_FORK=no
+to the make command to avoid to automatic test.
+
+We try and detect how to restart ntp and ypbind, you can override this with
+HAVE_INIT=no or force one of these values
+OPENRC (OpenRC as used by Gentoo (forked from baselayout))
+BSDRC (BSD RC system - /etc/rc.d/ntpd restart )
+SERVICE (RedHat service command - service ntpd restart)
+SLACKRC (Slackware RC system - /etc/rc.d/rc.ntpd restart)
+SYSV (SYSV style - /etc/init.d/ntpd restart)
+
+You can change the default dir where dhcpcd stores it's .info files with
+INFODIR=/var/db
+
+We now default to using -std=c99. For 64-bit linux, this always works, but
+for 32-bit linux it requires either gnu99 or a patch to asm/types.h.
+Most distros patch linux headers so this should work fine.
+linux-2.6.24 finally ships with a working 32-bit header.
+If your linux headers are older, or your distro hasn't patched them you can
+set CSTD=gnu99 to work around this.
+
+
+ChangeLog
+---------
+We no longer supply a ChangeLog.
+However, you're more than welcome to read the git commit comments at
+http://git.marples.name/?p=dhcpcd/.git;a=summary
diff --git a/src/customdhcpcd/arp.c b/src/customdhcpcd/arp.c
new file mode 100644
index 0000000..794850c
--- /dev/null
+++ b/src/customdhcpcd/arp.c
@@ -0,0 +1,284 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in_systm.h>
+#ifdef __linux__
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+#endif
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "arp.h"
+#include "interface.h"
+#include "logger.h"
+#include "signal.h"
+#include "socket.h"
+
+/* These are really for IPV4LL */
+#define NPROBES 3
+#define PROBE_INTERVAL 200
+#define NCLAIMS 2
+#define CLAIM_INTERVAL 200
+
+/* Linux does not seem to define these handy macros */
+#ifndef ar_sha
+#define ar_sha(ap) (((caddr_t) ((ap) + 1)) + 0)
+#define ar_spa(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln)
+#define ar_tha(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln + (ap)->ar_pln)
+#define ar_tpa(ap) (((caddr_t) ((ap) + 1)) + 2 * (ap)->ar_hln + (ap)->ar_pln)
+#endif
+
+#ifndef arphdr_len
+#define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + \
+ 2 * (ar_hln) + 2 * (ar_pln))
+#define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln))
+#endif
+
+#ifdef ENABLE_ARP
+
+static int send_arp (const interface_t *iface, int op, struct in_addr sip,
+ const unsigned char *taddr, struct in_addr tip)
+{
+ struct arphdr *arp;
+ size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip));
+ caddr_t tha;
+ int retval;
+
+ arp = xzalloc (arpsize);
+ arp->ar_hrd = htons (iface->family);
+ arp->ar_pro = htons (ETHERTYPE_IP);
+ arp->ar_hln = iface->hwlen;
+ arp->ar_pln = sizeof (sip);
+ arp->ar_op = htons (op);
+ memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln);
+ memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln);
+ if (taddr) {
+ /* NetBSD can return NULL from ar_tha, which is probably wrong
+ * but we still need to deal with it */
+ if (! (tha = ar_tha (arp))) {
+ free (arp);
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy (tha, taddr, (size_t) arp->ar_hln);
+ }
+ memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln);
+
+ retval = send_packet (iface, ETHERTYPE_ARP,
+ (unsigned char *) arp, arphdr_len (arp));
+ free (arp);
+ return (retval);
+}
+
+int arp_claim (interface_t *iface, struct in_addr address)
+{
+ struct arphdr *reply = NULL;
+ long timeout = 0;
+ unsigned char *buffer;
+ int retval = -1;
+ int nprobes = 0;
+ int nclaims = 0;
+ struct in_addr null_address;
+ struct pollfd fds[] = {
+ { -1, POLLIN, 0 },
+ { -1, POLLIN, 0 }
+ };
+
+ if (! iface)
+ return (-1);
+
+ if (! iface->arpable) {
+ logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name);
+ return (0);
+ }
+
+ if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) &&
+ ! IN_LINKLOCAL (ntohl (address.s_addr)))
+ logger (LOG_INFO,
+ "checking %s is available on attached networks",
+ inet_ntoa (address));
+
+ if (! open_socket (iface, ETHERTYPE_ARP))
+ return (-1);
+
+ fds[0].fd = signal_fd ();
+ fds[1].fd = iface->fd;
+
+ memset (&null_address, 0, sizeof (null_address));
+
+ buffer = xmalloc (iface->buffer_length);
+ reply = xmalloc (iface->buffer_length);
+
+ for (;;) {
+ size_t bufpos = 0;
+ size_t buflen = iface->buffer_length;
+ int bytes;
+ int s = 0;
+ struct timeval stopat;
+ struct timeval now;
+
+ /* Only poll if we have a timeout */
+ if (timeout > 0) {
+ s = poll (fds, 2, timeout);
+ if (s == -1) {
+ if (errno == EINTR) {
+ if (signal_exists (NULL) == -1) {
+ errno = 0;
+ continue;
+ } else
+ break;
+ }
+
+ logger (LOG_ERR, "poll: `%s'",
+ strerror (errno));
+ break;
+ }
+ }
+
+ /* Timed out */
+ if (s == 0) {
+ if (nprobes < NPROBES) {
+ nprobes ++;
+ timeout = PROBE_INTERVAL;
+ logger (LOG_DEBUG, "sending ARP probe #%d",
+ nprobes);
+ if (send_arp (iface, ARPOP_REQUEST,
+ null_address, NULL,
+ address) == -1)
+ break;
+
+ /* IEEE1394 cannot set ARP target address
+ * according to RFC2734 */
+ if (nprobes >= NPROBES &&
+ iface->family == ARPHRD_IEEE1394)
+ nclaims = NCLAIMS;
+ } else if (nclaims < NCLAIMS) {
+ nclaims ++;
+ timeout = CLAIM_INTERVAL;
+ logger (LOG_DEBUG, "sending ARP claim #%d",
+ nclaims);
+ if (send_arp (iface, ARPOP_REQUEST,
+ address, iface->hwaddr,
+ address) == -1)
+ break;
+ } else {
+ /* No replies, so done */
+ retval = 0;
+ break;
+ }
+
+ /* Setup our stop time */
+ if (get_time (&stopat) != 0)
+ break;
+ stopat.tv_usec += timeout;
+
+ continue;
+ }
+
+ /* We maybe ARP flooded, so check our time */
+ if (get_time (&now) != 0)
+ break;
+ if (timercmp (&now, &stopat, >)) {
+ timeout = 0;
+ continue;
+ }
+
+ if (! fds[1].revents & POLLIN)
+ continue;
+
+ memset (buffer, 0, buflen);
+ do {
+ union {
+ unsigned char *c;
+ struct in_addr *a;
+ } rp;
+ union {
+ unsigned char *c;
+ struct ether_addr *a;
+ } rh;
+
+ memset (reply, 0, iface->buffer_length);
+ if ((bytes = get_packet (iface, (unsigned char *) reply,
+ buffer,
+ &buflen, &bufpos)) == -1)
+ break;
+
+ /* Only these types are recognised */
+ if (reply->ar_op != htons (ARPOP_REPLY))
+ continue;
+
+ /* Protocol must be IP. */
+ if (reply->ar_pro != htons (ETHERTYPE_IP))
+ continue;
+ if (reply->ar_pln != sizeof (address))
+ continue;
+ if ((unsigned) bytes < sizeof (reply) +
+ 2 * (4 + reply->ar_hln))
+ continue;
+
+ rp.c = (unsigned char *) ar_spa (reply);
+ rh.c = (unsigned char *) ar_sha (reply);
+
+ /* Ensure the ARP reply is for the our address */
+ if (rp.a->s_addr != address.s_addr)
+ continue;
+
+ /* Some systems send a reply back from our hwaddress,
+ * which is wierd */
+ if (reply->ar_hln == iface->hwlen &&
+ memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0)
+ continue;
+
+ logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)",
+ inet_ntoa (*rp.a),
+ hwaddr_ntoa (rh.c, (size_t) reply->ar_hln));
+ retval = -1;
+ goto eexit;
+ } while (bufpos != 0);
+ }
+
+eexit:
+ close (iface->fd);
+ iface->fd = -1;
+ free (buffer);
+ free (reply);
+ return (retval);
+}
+#endif
diff --git a/src/customdhcpcd/arp.h b/src/customdhcpcd/arp.h
new file mode 100644
index 0000000..3b7e8ef
--- /dev/null
+++ b/src/customdhcpcd/arp.h
@@ -0,0 +1,39 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ARP_H
+#define ARP_H
+
+#ifdef ENABLE_ARP
+#include <netinet/in.h>
+
+#include "interface.h"
+
+int arp_claim (interface_t *iface, struct in_addr address);
+#endif
+
+#endif
diff --git a/src/customdhcpcd/client.c b/src/customdhcpcd/client.c
new file mode 100644
index 0000000..b007fd6
--- /dev/null
+++ b/src/customdhcpcd/client.c
@@ -0,0 +1,1149 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#ifdef __linux__
+# include <netinet/ether.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#ifdef ENABLE_ARP
+# include "arp.h"
+#endif
+#include "client.h"
+#include "configure.h"
+#include "dhcp.h"
+#include "dhcpcd.h"
+#include "info.h"
+#include "interface.h"
+#ifdef ENABLE_IPV4LL
+# include "ipv4ll.h"
+#endif
+#include "logger.h"
+#include "signal.h"
+#include "socket.h"
+
+#include "logwriter.h"
+
+#ifdef ENABLE_DUID
+# include "duid.h"
+#endif
+
+#ifdef ENABLE_INFO
+# include "info.h"
+#endif
+
+#ifdef THERE_IS_NO_FORK
+# ifndef ENABLE_INFO
+ # error "Non MMU requires ENABLE_INFO to work"
+# endif
+#endif
+
+/* Some platforms don't define INFTIM */
+#ifndef INFTIM
+# define INFTIM -1
+#endif
+
+/* This is out mini timeout.
+ * Basically we resend the last request every TIMEOUT_MINI seconds. */
+#define TIMEOUT_MINI 3
+/* Except for an infinite timeout. We keep adding TIMEOUT_MINI to
+ * ourself until TIMEOUT_MINI_INF is reached. */
+#define TIMEOUT_MINI_INF 60
+
+#define STATE_INIT 0
+#define STATE_REQUESTING 1
+#define STATE_BOUND 2
+#define STATE_RENEWING 3
+#define STATE_REBINDING 4
+#define STATE_REBOOT 5
+#define STATE_RENEW_REQUESTED 6
+#define STATE_RELEASED 7
+
+/* We should define a maximum for the NAK exponential backoff */
+#define NAKOFF_MAX 60
+
+#define SOCKET_CLOSED 0
+#define SOCKET_OPEN 1
+
+/* Indexes for pollfds */
+#define POLLFD_SIGNAL 0
+#define POLLFD_IFACE 1
+
+typedef struct _state {
+ int *pidfd;
+ bool forked;
+ int state;
+ uint32_t xid;
+ dhcp_t *dhcp;
+ int socket;
+ interface_t *interface;
+ time_t start;
+ time_t last_sent;
+ time_t last_type;
+ long timeout;
+ time_t nakoff;
+ bool daemonised;
+ bool persistent;
+ unsigned char *buffer;
+ size_t buffer_len;
+ size_t buffer_pos;
+} state_t;
+
+static pid_t daemonise (int *pidfd)
+{
+ pid_t pid;
+ sigset_t full;
+ sigset_t old;
+#ifdef THERE_IS_NO_FORK
+ char **argv;
+ int i;
+#endif
+
+ sigfillset (&full);
+ sigprocmask (SIG_SETMASK, &full, &old);
+
+#ifndef THERE_IS_NO_FORK
+ logger (LOG_DEBUG, "forking to background");
+ switch (pid = fork()) {
+ case -1:
+ logger (LOG_ERR, "fork: %s", strerror (errno));
+ exit (EXIT_FAILURE);
+ /* NOT REACHED */
+ case 0:
+ setsid ();
+ close_fds ();
+ break;
+ default:
+ /* Reset our signals as we're the parent about to exit. */
+ signal_reset ();
+ break;
+ }
+#else
+ logger (LOG_INFO, "forking to background");
+
+ /* We need to add --daemonise to our options */
+ argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 4));
+ argv[0] = dhcpcd;
+ for (i = 1; i < dhcpcd_argc; i++)
+ argv[i] = dhcpcd_argv[i];
+ argv[i] = (char *) "--daemonised";
+ if (dhcpcd_skiproutes) {
+ argv[++i] = (char *) "--skiproutes";
+ argv[++i] = dhcpcd_skiproutes;
+ }
+ argv[i + 1] = NULL;
+
+ switch (pid = vfork ()) {
+ case -1:
+ logger (LOG_ERR, "vfork: %s", strerror (errno));
+ _exit (EXIT_FAILURE);
+ case 0:
+ signal_reset ();
+ sigprocmask (SIG_SETMASK, &old, NULL);
+ execvp (dhcpcd, argv);
+ logger (LOG_ERR, "execl `%s': %s", dhcpcd,
+ strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ free (argv);
+#endif
+
+ /* Done with the fd now */
+ if (pid != 0) {
+ writepid (*pidfd, pid);
+ close (*pidfd);
+ *pidfd = -1;
+
+ }
+
+ sigprocmask (SIG_SETMASK, &old, NULL);
+ return (pid);
+}
+
+#ifdef ENABLE_INFO
+static bool get_old_lease (state_t *state, const options_t *options)
+{
+ interface_t *iface = state->interface;
+ dhcp_t *dhcp = state->dhcp;
+ struct timeval tv;
+ unsigned int offset = 0;
+
+ if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)))
+ logger (LOG_INFO, "trying to use old lease in `%s'",
+ iface->infofile);
+ if (! read_info (iface, dhcp))
+ return (false);
+
+ /* Vitaly important we remove the server information here */
+ memset (&dhcp->serveraddress, 0, sizeof (dhcp->serveraddress));
+ memset (dhcp->servername, 0, sizeof (dhcp->servername));
+
+#ifdef ENABLE_ARP
+ /* Check that no-one is using the address */
+ if ((options->dolastlease ||
+ (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) &&
+ (! options->doipv4ll ||
+ arp_claim (iface, dhcp->address)))))
+ {
+ memset (&dhcp->address, 0, sizeof (dhcp->address));
+ memset (&dhcp->netmask, 0, sizeof (dhcp->netmask));
+ memset (&dhcp->broadcast, 0, sizeof (dhcp->broadcast));
+ return (false);
+ }
+
+ /* Ok, lets use this */
+ if (IN_LINKLOCAL (dhcp->address.s_addr))
+ return (true);
+#endif
+
+ /* Ensure that we can still use the lease */
+ if (gettimeofday (&tv, NULL) == -1) {
+ logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
+ return (false);
+ }
+
+ offset = tv.tv_sec - dhcp->leasedfrom;
+ if (dhcp->leasedfrom &&
+ tv.tv_sec - dhcp->leasedfrom > dhcp->leasetime)
+ {
+ logger (LOG_ERR, "lease expired %u seconds ago",
+ offset + dhcp->leasetime);
+ return (false);
+ }
+
+ if (dhcp->leasedfrom == 0)
+ offset = 0;
+ state->timeout = dhcp->renewaltime - offset;
+ iface->start_uptime = uptime ();
+ return (true);
+}
+#endif
+
+#ifdef THERE_IS_NO_FORK
+static void remove_skiproutes (dhcp_t *dhcp, interface_t *iface)
+{
+ int i = -1;
+ route_t *route;
+ route_t *newroute;
+
+ free_route (iface->previous_routes);
+ iface->previous_routes = NULL;
+
+ NSTAILQ_FOREACH (route, dhcp->routes, entries) {
+ i++;
+
+ /* Check that we did add this route or not */
+ if (dhcpcd_skiproutes) {
+ char *sk = xstrdup (dhcpcd_skiproutes);
+ char *skp = sk;
+ char *token;
+ bool found = false;
+
+ while ((token = strsep (&skp, ","))) {
+ if (isdigit (*token) && atoi (token) == i) {
+ found = true;
+ break;
+ }
+ }
+ free (sk);
+ if (found)
+ continue;
+ }
+
+ if (! iface->previous_routes) {
+ iface->previous_routes = xmalloc (sizeof (*iface->previous_routes));
+ STAILQ_INIT (iface->previous_routes);
+ }
+
+ newroute = xmalloc (sizeof (*newroute));
+ memcpy (newroute, route, sizeof (*newroute));
+ STAILQ_INSERT_TAIL (iface->previous_routes, newroute, entries);
+ }
+
+ /* We no longer need this argument */
+ free (dhcpcd_skiproutes);
+ dhcpcd_skiproutes = NULL;
+}
+#endif
+
+static bool client_setup (state_t *state, const options_t *options)
+{
+ dhcp_t *dhcp = state->dhcp;
+ interface_t *iface = state->interface;
+
+ state->state = STATE_INIT;
+ state->last_type = DHCP_DISCOVER;
+ state->nakoff = 1;
+ state->daemonised = options->daemonised;
+ state->persistent = options->persistent;
+
+ if (options->request_address.s_addr == 0 &&
+ (options->doinform || options->dorequest || options->daemonised))
+ {
+#ifdef ENABLE_INFO
+ if (! get_old_lease (state, options))
+#endif
+ {
+ free (dhcp);
+ return (false);
+ }
+ state->timeout = 0;
+
+ if (! options->daemonised &&
+ IN_LINKLOCAL (ntohl (dhcp->address.s_addr)))
+ {
+ logger (LOG_ERR, "cannot request a link local address");
+ return (false);
+ }
+#ifdef THERE_IS_NO_FORK
+ if (options->daemonised) {
+ state->state = STATE_BOUND;
+ state->timeout = dhcp->renewaltime;
+ iface->previous_address = dhcp->address;
+ iface->previous_netmask = dhcp->netmask;
+ remove_skiproutes (dhcp, iface);
+ }
+#endif
+
+ } else {
+ dhcp->address = options->request_address;
+ dhcp->netmask = options->request_netmask;
+ if (dhcp->netmask.s_addr == 0)
+ dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr);
+ dhcp->broadcast.s_addr = dhcp->address.s_addr |
+ ~dhcp->netmask.s_addr;
+ }
+
+ /* Remove all existing addresses.
+ * After all, we ARE a DHCP client whose job it is to configure the
+ * interface. We only do this on start, so persistent addresses
+ * can be added afterwards by the user if needed. */
+ if (! options->test && ! options->daemonised) {
+ if (! options->doinform) {
+ flush_addresses (iface->name);
+ } else {
+ /* The inform address HAS to be configured for it to
+ * work with most DHCP servers */
+ if (options->doinform &&
+ has_address (iface->name, dhcp->address) < 1)
+ {
+ add_address (iface->name, dhcp->address,
+ dhcp->netmask, dhcp->broadcast);
+ iface->previous_address = dhcp->address;
+ iface->previous_netmask = dhcp->netmask;
+ }
+ }
+ }
+
+ if (*options->clientid) {
+ /* Attempt to see if the ClientID is a hardware address */
+ iface->clientid_len = hwaddr_aton (NULL, options->clientid);
+ if (iface->clientid_len) {
+ iface->clientid = xmalloc (iface->clientid_len);
+ hwaddr_aton (iface->clientid, options->clientid);
+ } else {
+ /* Nope, so mark it as-is */
+ iface->clientid_len = strlen (options->clientid) + 1;
+ iface->clientid = xmalloc (iface->clientid_len);
+ *iface->clientid = '\0';
+ memcpy (iface->clientid + 1,
+ options->clientid, iface->clientid_len - 1);
+ }
+ } else {
+#ifdef ENABLE_DUID
+ unsigned char *duid = NULL;
+ size_t duid_len = 0;
+
+ if (options->doduid) {
+ duid = xmalloc (DUID_LEN);
+ duid_len = get_duid (duid, iface);
+ }
+
+ if (duid_len > 0) {
+ logger (LOG_INFO, "DUID = %s", hwaddr_ntoa (duid, duid_len));
+
+ iface->clientid_len = duid_len + 5;
+ iface->clientid = xmalloc (iface->clientid_len);
+ *iface->clientid = 255; /* RFC 4361 */
+
+ /* IAID is 4 bytes, so if the iface name is 4 bytes use it */
+ if (strlen (iface->name) == 4) {
+ memcpy (iface->clientid + 1, iface->name, 4);
+ } else {
+ /* Name isn't 4 bytes, so use the index */
+ uint32_t ul = htonl (if_nametoindex (iface->name));
+ memcpy (iface->clientid + 1, &ul, 4);
+ }
+
+ memcpy (iface->clientid + 5, duid, duid_len);
+ free (duid);
+ } else {
+#else
+ {
+#endif
+ iface->clientid_len = iface->hwlen + 1;
+ iface->clientid = xmalloc (iface->clientid_len);
+ *iface->clientid = iface->family;
+ memcpy (iface->clientid + 1, iface->hwaddr, iface->hwlen);
+ }
+ }
+
+ return (true);
+}
+
+static bool do_socket (state_t *state, int mode)
+{
+ if (state->interface->fd >= 0)
+ close (state->interface->fd);
+#ifdef __linux
+ if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) {
+ close (state->interface->listen_fd);
+ state->interface->listen_fd = -1;
+ }
+#endif
+
+ state->interface->fd = -1;
+ if (mode == SOCKET_OPEN)
+ if (open_socket (state->interface, ETHERTYPE_IP) == -1)
+ return (false);
+ state->socket = mode;
+ return (true);
+}
+
+static bool _send_message (state_t *state, int type, const options_t *options)
+{
+ ssize_t retval;
+
+ state->last_type = type;
+ state->last_sent = uptime ();
+ logSendToQt(type);
+ retval = send_message (state->interface, state->dhcp, state->xid,
+ type, options);
+ return (retval == -1 ? false : true);
+}
+
+static void drop_config (state_t *state, const options_t *options)
+{
+ if (! state->persistent)
+ configure (options, state->interface, state->dhcp, false);
+
+ free_dhcp (state->dhcp);
+ memset (state->dhcp, 0, sizeof (*state->dhcp));
+}
+
+static int wait_for_packet (struct pollfd *fds, state_t *state,
+ const options_t *options)
+{
+ dhcp_t *dhcp = state->dhcp;
+ interface_t *iface = state->interface;
+ int timeout = 0;
+ int retval = 0;
+
+ if (! (state->timeout > 0 ||
+ (options->timeout == 0 &&
+ (state->state != STATE_INIT || state->xid)))) {
+ /* We need to zero our signal fd, otherwise we will block
+ * trying to read a signal. */
+ fds[POLLFD_SIGNAL].revents = 0;
+ return (0);
+ }
+
+ fds[POLLFD_IFACE].fd = iface->fd;
+
+ if ((options->timeout == 0 && state->xid) ||
+ (dhcp->leasetime == (unsigned) -1 &&
+ state->state == STATE_BOUND))
+ {
+ logger (LOG_DEBUG, "waiting for infinity");
+ while (retval == 0) {
+ if (iface->fd == -1)
+ retval = poll (fds, 1, INFTIM);
+ else {
+ /* Slow down our requests */
+ if (timeout < TIMEOUT_MINI_INF)
+ timeout += TIMEOUT_MINI;
+ else if (timeout > TIMEOUT_MINI_INF)
+ timeout = TIMEOUT_MINI_INF;
+
+ retval = poll (fds, 2, timeout * 1000);
+ if (retval == -1 && errno == EINTR) {
+ /* If interupted, continue as normal as
+ * the signal will be delivered down
+ * the pipe */
+ retval = 0;
+ continue;
+ }
+ if (retval == 0)
+ _send_message (state, state->last_type,
+ options);
+ }
+ }
+
+ return (retval);
+ }
+
+ /* Resend our message if we're getting loads of packets.
+ * As we use BPF or LPF, we shouldn't hit this as much, but it's
+ * still nice to have. */
+ if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI)
+ _send_message (state, state->last_type, options);
+
+ logger (LOG_DEBUG, "waiting for %ld seconds",
+ (unsigned long) state->timeout);
+ /* If we're waiting for a reply, then we re-send the last
+ * DHCP request periodically in-case of a bad line */
+ retval = 0;
+ while (state->timeout > 0 && retval == 0) {
+ if (iface->fd == -1)
+ timeout = (int) state->timeout;
+ else {
+ timeout = TIMEOUT_MINI;
+ if (state->timeout < timeout)
+ timeout = (int) state->timeout;
+ }
+ timeout *= 1000;
+ state->start = uptime ();
+ retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout);
+ state->timeout -= uptime () - state->start;
+ if (retval == -1 && errno == EINTR) {
+ /* If interupted, continue as normal as the signal
+ * will be delivered down the pipe */
+ retval = 0;
+ continue;
+ }
+ if (retval == 0 && iface->fd != -1 && state->timeout > 0)
+ _send_message (state, state->last_type, options);
+ }
+
+ return (retval);
+}
+
+static bool handle_signal (int sig, state_t *state, const options_t *options)
+{
+ switch (sig) {
+ case SIGINT:
+ logger (LOG_INFO, "received SIGINT, stopping");
+ return (false);
+ case SIGTERM:
+ logger (LOG_INFO, "received SIGTERM, stopping");
+ return (false);
+
+ case SIGALRM:
+ logger (LOG_INFO, "received SIGALRM, renewing lease");
+ switch (state->state) {
+ case STATE_BOUND:
+ case STATE_RENEWING:
+ case STATE_REBINDING:
+ state->state = STATE_RENEW_REQUESTED;
+ break;
+ case STATE_RENEW_REQUESTED:
+ case STATE_REQUESTING:
+ case STATE_RELEASED:
+ state->state = STATE_INIT;
+ break;
+ }
+ state->timeout = 0;
+ state->xid = 0;
+ return (true);
+
+ case SIGHUP:
+ if (state->state != STATE_BOUND &&
+ state->state != STATE_RENEWING &&
+ state->state != STATE_REBINDING)
+ {
+ logger (LOG_ERR,
+ "received SIGHUP, but we no have lease to release");
+ return (false);
+ }
+
+ logger (LOG_INFO, "received SIGHUP, releasing lease");
+ if (! IN_LINKLOCAL (ntohl (state->dhcp->address.s_addr))) {
+ do_socket (state, SOCKET_OPEN);
+ state->xid = (uint32_t) random ();
+ if ((open_socket (state->interface, false)) >= 0) {
+ _send_message (state, DHCP_RELEASE, options);
+ }
+ do_socket (state, SOCKET_CLOSED);
+ }
+ unlink (state->interface->infofile);
+ return (false);
+
+ default:
+ logger (LOG_ERR,
+ "received signal %d, but don't know what to do with it",
+ sig);
+ }
+
+ return (false);
+}
+
+static int handle_timeout (state_t *state, const options_t *options)
+{
+ dhcp_t *dhcp = state->dhcp;
+ interface_t *iface = state->interface;
+
+ /* No NAK, so reset the backoff */
+ state->nakoff = 1;
+
+ if (state->state == STATE_INIT && state->xid != 0) {
+ if (iface->previous_address.s_addr != 0 &&
+ ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) &&
+ ! options->doinform)
+ {
+ logger (LOG_ERR, "lost lease");
+ if (! options->persistent)
+ drop_config (state, options);
+ } else if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)))
+ logger (LOG_ERR, "timed out");
+
+ do_socket (state, SOCKET_CLOSED);
+ free_dhcp (dhcp);
+ memset (dhcp, 0, sizeof (*dhcp));
+
+#ifdef ENABLE_INFO
+ if (! options->test &&
+ (options->doipv4ll || options->dolastlease))
+ {
+ errno = 0;
+ if (! get_old_lease (state, options))
+ {
+ if (errno == EINTR)
+ return (0);
+ if (options->dolastlease)
+ return (-1);
+ free_dhcp (dhcp);
+ memset (dhcp, 0, sizeof (*dhcp));
+ } else if (errno == EINTR)
+ return (0);
+ }
+#endif
+
+#ifdef ENABLE_IPV4LL
+ if (! options->test && options->doipv4ll &&
+ (! dhcp->address.s_addr ||
+ (! IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) &&
+ ! options->dolastlease)))
+ {
+ logger (LOG_INFO, "probing for an IPV4LL address");
+ free_dhcp (dhcp);
+ memset (dhcp, 0, sizeof (*dhcp));
+ if (ipv4ll_get_address (iface, dhcp) == -1) {
+ if (! state->daemonised)
+ return (-1);
+
+ /* start over */
+ state->xid = 0;
+ return (0);
+ }
+ state->timeout = dhcp->renewaltime;
+ }
+#endif
+
+#if defined (ENABLE_INFO) || defined (ENABLE_IPV4LL)
+ if (dhcp->address.s_addr) {
+ if (! state->daemonised &&
+ IN_LINKLOCAL (ntohl (dhcp->address.s_addr)))
+ logger (LOG_WARNING, "using IPV4LL address %s",
+ inet_ntoa (dhcp->address));
+ if (configure (options, iface, dhcp, true) == -1 &&
+ ! state->daemonised)
+ return (-1);
+
+ state->state = STATE_BOUND;
+ if (! state->daemonised && options->daemonise) {
+ switch (daemonise (state->pidfd)) {
+ case -1:
+ return (-1);
+ case 0:
+ state->daemonised = true;
+ return (0);
+ default:
+ state->persistent = true;
+ state->forked = true;
+ return (-1);
+ }
+ }
+
+ state->timeout = dhcp->renewaltime;
+ state->xid = 0;
+ return (0);
+ }
+#endif
+
+ if (! state->daemonised)
+ return (-1);
+ }
+
+ switch (state->state) {
+ case STATE_INIT:
+ state->xid = (uint32_t) random ();
+ do_socket (state, SOCKET_OPEN);
+ state->timeout = options->timeout;
+ iface->start_uptime = uptime ();
+ if (dhcp->address.s_addr == 0) {
+ if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)))
+ logger (LOG_INFO, "broadcasting for a lease");
+ _send_message (state, DHCP_DISCOVER, options);
+ } else if (options->doinform) {
+ logger (LOG_INFO, "broadcasting inform for %s",
+ inet_ntoa (dhcp->address));
+ _send_message (state, DHCP_INFORM, options);
+ state->state = STATE_REQUESTING;
+ } else {
+ logger (LOG_INFO, "broadcasting for a lease of %s",
+ inet_ntoa (dhcp->address));
+ _send_message (state, DHCP_REQUEST, options);
+ state->state = STATE_REQUESTING;
+ }
+
+ break;
+ case STATE_BOUND:
+ case STATE_RENEW_REQUESTED:
+ if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) {
+ memset (&dhcp->address, 0, sizeof (dhcp->address));
+ state->state = STATE_INIT;
+ state->xid = 0;
+ break;
+ }
+ state->state = STATE_RENEWING;
+ state->xid = (uint32_t) random ();
+ /* FALLTHROUGH */
+ case STATE_RENEWING:
+ iface->start_uptime = uptime ();
+ logger (LOG_INFO, "renewing lease of %s", inet_ntoa
+ (dhcp->address));
+ do_socket (state, SOCKET_OPEN);
+ _send_message (state, DHCP_REQUEST, options);
+ state->timeout = dhcp->rebindtime - dhcp->renewaltime;
+ state->state = STATE_REBINDING;
+ break;
+ case STATE_REBINDING:
+ logger (LOG_ERR, "lost lease, attemping to rebind");
+ memset (&dhcp->address, 0, sizeof (dhcp->address));
+ do_socket (state, SOCKET_OPEN);
+ if (state->xid == 0)
+ state->xid = (uint32_t) random ();
+ dhcp->serveraddress.s_addr = 0;
+ _send_message (state, DHCP_REQUEST, options);
+ state->timeout = dhcp->leasetime - dhcp->rebindtime;
+ state->state = STATE_REQUESTING;
+ break;
+ case STATE_REQUESTING:
+ state->state = STATE_INIT;
+ do_socket (state, SOCKET_CLOSED);
+ state->timeout = 0;
+ break;
+
+ case STATE_RELEASED:
+ dhcp->leasetime = 0;
+ break;
+ }
+
+ return (0);
+}
+
+
+static int handle_dhcp (state_t *state, int type, const options_t *options)
+{
+ struct timespec ts;
+ interface_t *iface = state->interface;
+ dhcp_t *dhcp = state->dhcp;
+
+ /* We should restart on a NAK */
+ if (type == DHCP_NAK) {
+ logger (LOG_INFO, "received NAK: %s", dhcp->message);
+ logToQt(LOG_INFO, DHCP_NAK, "");
+ state->state = STATE_INIT;
+ state->timeout = 0;
+ state->xid = 0;
+ free_dhcp (dhcp);
+ memset (dhcp, 0, sizeof (*dhcp));
+
+ /* If we constantly get NAKS then we should slowly back off */
+ if (state->nakoff > 0) {
+ logger (LOG_DEBUG, "sleeping for %ld seconds",
+ (long) state->nakoff);
+ ts.tv_sec = state->nakoff;
+ ts.tv_nsec = 0;
+ state->nakoff *= 2;
+ if (state->nakoff > NAKOFF_MAX)
+ state->nakoff = NAKOFF_MAX;
+ nanosleep (&ts, NULL);
+ }
+
+ return (0);
+ }
+
+ /* No NAK, so reset the backoff */
+ state->nakoff = 1;
+
+ if (type == DHCP_OFFER && state->state == STATE_INIT) {
+ char *addr = strdup (inet_ntoa (dhcp->address));
+ if (dhcp->servername[0])
+ logger (LOG_INFO, "offered %s from %s `%s'",
+ addr, inet_ntoa (dhcp->serveraddress),
+ dhcp->servername);
+ else
+ logger (LOG_INFO, "offered %s from %s",
+ addr, inet_ntoa (dhcp->serveraddress));
+ free (addr);
+
+ logToQt(LOG_INFO, DHCP_OFFER, "");
+
+#ifdef ENABLE_INFO
+ if (options->test) {
+ write_info (iface, dhcp, options, false);
+ errno = 0;
+ return (-1);
+ }
+#endif
+
+ _send_message (state, DHCP_REQUEST, options);
+ state->state = STATE_REQUESTING;
+
+ return (0);
+ }
+
+ if (type == DHCP_OFFER) {
+ logger (LOG_INFO, "got subsequent offer of %s, ignoring ",
+ inet_ntoa (dhcp->address));
+ return (0);
+ }
+
+ /* We should only be dealing with acks */
+ if (type != DHCP_ACK) {
+ logger (LOG_ERR, "%d not an ACK or OFFER", type);
+ return (0);
+ }
+
+ /* if we are here, than we received an ACK and can go on with configuration */
+ logToQt(LOG_INFO, DHCP_ACK, "");
+
+ switch (state->state) {
+ case STATE_RENEW_REQUESTED:
+ case STATE_REQUESTING:
+ case STATE_RENEWING:
+ case STATE_REBINDING:
+ break;
+ default:
+ logger (LOG_ERR, "wrong state %d", state->state);
+ }
+
+ do_socket (state, SOCKET_CLOSED);
+
+#ifdef ENABLE_ARP
+ if (options->doarp && iface->previous_address.s_addr !=
+ dhcp->address.s_addr)
+ {
+ errno = 0;
+ logToQt(LOG_INFO, DHCPCD_ARP_TEST, "");
+ if (arp_claim (iface, dhcp->address)) {
+ do_socket (state, SOCKET_OPEN);
+ _send_message (state, DHCP_DECLINE, options);
+ do_socket (state, SOCKET_CLOSED);
+
+ free_dhcp (dhcp);
+ memset (dhcp, 0, sizeof (*dhcp));
+ state->xid = 0;
+ state->timeout = 0;
+ state->state = STATE_INIT;
+
+ /* RFC 2131 says that we should wait for 10 seconds
+ * before doing anything else */
+ logger (LOG_INFO, "sleeping for 10 seconds");
+ ts.tv_sec = 10;
+ ts.tv_nsec = 0;
+ nanosleep (&ts, NULL);
+ return (0);
+ } else if (errno == EINTR)
+ return (0);
+ }
+#endif
+
+ if (options->doinform) {
+ if (options->request_address.s_addr != 0)
+ dhcp->address = options->request_address;
+ else
+ dhcp->address = iface->previous_address;
+
+ logger (LOG_INFO, "received approval for %s",
+ inet_ntoa (dhcp->address));
+ if (iface->previous_netmask.s_addr != dhcp->netmask.s_addr) {
+ add_address (iface->name, dhcp->address,
+ dhcp->netmask, dhcp->broadcast);
+ iface->previous_netmask.s_addr = dhcp->netmask.s_addr;
+ }
+ state->timeout = options->leasetime;
+ if (state->timeout == 0)
+ state->timeout = DEFAULT_LEASETIME;
+ state->state = STATE_INIT;
+ } else if (dhcp->leasetime == (unsigned) -1) {
+ dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime;
+ state->timeout = 1; /* So we wait for infinity */
+ logger (LOG_INFO, "leased %s for infinity",
+ inet_ntoa (dhcp->address));
+ state->state = STATE_BOUND;
+ } else {
+ if (! dhcp->leasetime) {
+ dhcp->leasetime = DEFAULT_LEASETIME;
+ logger(LOG_INFO,
+ "no lease time supplied, assuming %d seconds",
+ dhcp->leasetime);
+ }
+ logger (LOG_INFO, "leased %s for %u seconds",
+ inet_ntoa (dhcp->address), dhcp->leasetime);
+
+ if (dhcp->rebindtime >= dhcp->leasetime) {
+ dhcp->rebindtime = (dhcp->leasetime * 0.875);
+ logger (LOG_ERR,
+ "rebind time greater than lease "
+ "time, forcing to %u seconds",
+ dhcp->rebindtime);
+ }
+
+ if (dhcp->renewaltime > dhcp->rebindtime) {
+ dhcp->renewaltime = (dhcp->leasetime * 0.5);
+ logger (LOG_ERR,
+ "renewal time greater than rebind time, "
+ "forcing to %u seconds",
+ dhcp->renewaltime);
+ }
+
+ if (! dhcp->renewaltime) {
+ dhcp->renewaltime = (dhcp->leasetime * 0.5);
+ logger (LOG_INFO,
+ "no renewal time supplied, assuming %d seconds",
+ dhcp->renewaltime);
+ } else
+ logger (LOG_DEBUG, "renew in %u seconds",
+ dhcp->renewaltime);
+
+ if (! dhcp->rebindtime) {
+ dhcp->rebindtime = (dhcp->leasetime * 0.875);
+ logger (LOG_INFO,
+ "no rebind time supplied, assuming %d seconds",
+ dhcp->rebindtime);
+ } else
+ logger (LOG_DEBUG, "rebind in %u seconds",
+ dhcp->rebindtime);
+
+ state->timeout = dhcp->renewaltime;
+ state->state = STATE_BOUND;
+ }
+
+ state->xid = 0;
+
+ logToQt(LOG_INFO, DHCPCD_CONFIGURE, "");
+ if (configure (options, iface, dhcp, true) == -1 &&
+ ! state->daemonised)
+ return (-1);
+
+ if (! state->daemonised && options->daemonise) {
+ switch (daemonise (state->pidfd)) {
+ case 0:
+ state->daemonised = true;
+ return (0);
+ case -1:
+ return (-1);
+ default:
+ state->persistent = true;
+ state->forked = true;
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static int handle_packet (state_t *state, const options_t *options)
+{
+ interface_t *iface = state->interface;
+ bool valid = false;
+ int type;
+ struct dhcp_t *new_dhcp;
+ dhcpmessage_t message;
+
+ /* Allocate our buffer space for BPF.
+ * We cannot do this until we have opened our socket as we don't
+ * know how much of a buffer we need until then. */
+ if (! state->buffer)
+ state->buffer = xmalloc (iface->buffer_length);
+ state->buffer_len = iface->buffer_length;
+ state->buffer_pos = 0;
+
+ /* We loop through until our buffer is empty.
+ * The benefit is that if we get >1 DHCP packet in our buffer and
+ * the first one fails for any reason, we can use the next. */
+
+ memset (&message, 0, sizeof (message));
+ new_dhcp = xmalloc (sizeof (*new_dhcp));
+
+ do {
+ if (get_packet (iface, (unsigned char *) &message,
+ state->buffer,
+ &state->buffer_len, &state->buffer_pos) == -1)
+ break;
+
+ if (state->xid != message.xid) {
+ logger (LOG_DEBUG,
+ "ignoring packet with xid 0x%x as it's not ours (0x%x)",
+ message.xid, state->xid);
+ continue;
+ }
+
+ logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid);
+ memset (new_dhcp, 0, sizeof (*new_dhcp));
+ type = parse_dhcpmessage (new_dhcp, &message);
+ if (type == -1) {
+ logger (LOG_ERR, "failed to parse packet");
+ free_dhcp (new_dhcp);
+ /* We don't abort on this, so return zero */
+ return (0);
+ }
+
+ /* If we got here then the DHCP packet is valid and appears to
+ * be for us, so let's clear the buffer as we don't care about
+ * any more DHCP packets at this point. */
+ valid = true;
+ break;
+ } while (state->buffer_pos != 0);
+
+ /* No packets for us, so wait until we get one */
+ if (! valid) {
+ free (new_dhcp);
+ return (0);
+ }
+
+ /* new_dhcp is now our master DHCP message */
+ free_dhcp (state->dhcp);
+ free (state->dhcp);
+ state->dhcp = new_dhcp;
+ new_dhcp = NULL;
+
+ return (handle_dhcp (state, type, options));
+}
+
+int dhcp_run (const options_t *options, int *pidfd)
+{
+ interface_t *iface;
+ state_t *state = NULL;
+ struct pollfd fds[] = {
+ { -1, POLLIN, 0 },
+ { -1, POLLIN, 0 }
+ };
+ int retval = -1;
+ int sig;
+
+ if (! options)
+ return (-1);
+
+ /*read_interface : defined in interface.c*/
+ iface = read_interface (options->interface, options->metric);
+ if (! iface)
+ goto eexit;
+
+ state = xzalloc (sizeof (*state));
+ state->dhcp = xzalloc (sizeof (*state->dhcp));
+ state->pidfd = pidfd;
+ state->interface = iface;
+
+ if (! client_setup (state, options))
+ goto eexit;
+
+ if (signal_init () == -1)
+ goto eexit;
+ if (signal_setup () == -1)
+ goto eexit;
+
+ fds[POLLFD_SIGNAL].fd = signal_fd ();
+
+ for (;;) {
+ retval = wait_for_packet (fds, state, options);
+
+ /* We should always handle our signals first */
+ if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) {
+ if (handle_signal (sig, state, options))
+ retval = 0;
+ else
+ retval = -1;
+ } else if (retval == 0)
+ retval = handle_timeout (state, options);
+ else if (retval > 0 &&
+ state->socket != SOCKET_CLOSED &&
+ fds[POLLFD_IFACE].revents & POLLIN)
+ retval = handle_packet (state, options);
+ else if (retval == -1 && errno == EINTR) {
+ /* The interupt will be handled above */
+ retval = 0;
+ } else {
+ logger (LOG_ERR, "poll: %s", strerror (errno));
+ retval = -1;
+ }
+
+ if (retval != 0)
+ break;
+ }
+
+eexit:
+ if (iface) {
+ do_socket (state, SOCKET_CLOSED);
+ drop_config (state, options);
+ free_route (iface->previous_routes);
+ free (iface->clientid);
+ free (iface);
+ }
+
+ if (state) {
+ if (state->forked)
+ retval = 0;
+
+ if (state->daemonised)
+ unlink (options->pidfile);
+
+ free_dhcp (state->dhcp);
+ free (state->dhcp);
+ free (state->buffer);
+ free (state);
+ }
+
+ return (retval);
+}
diff --git a/src/customdhcpcd/client.h b/src/customdhcpcd/client.h
new file mode 100644
index 0000000..fa6ea9b
--- /dev/null
+++ b/src/customdhcpcd/client.h
@@ -0,0 +1,35 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include "dhcpcd.h"
+
+int dhcp_run (const options_t *options, int *pidfd);
+
+#endif
diff --git a/src/customdhcpcd/common.c b/src/customdhcpcd/common.c
new file mode 100644
index 0000000..99471bc
--- /dev/null
+++ b/src/customdhcpcd/common.c
@@ -0,0 +1,249 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "logger.h"
+
+/* Handy routine to read very long lines in text files.
+ * This means we read the whole line and avoid any nasty buffer overflows. */
+char *get_line (FILE *fp)
+{
+ char *line = NULL;
+ char *p;
+ size_t len = 0;
+ size_t last = 0;
+
+ if (feof (fp))
+ return (NULL);
+
+ do {
+ len += BUFSIZ;
+ line = xrealloc (line, sizeof (char) * len);
+ p = line + last;
+ memset (p, 0, BUFSIZ);
+ fgets (p, BUFSIZ, fp);
+ last += strlen (p);
+ } while (! feof (fp) && line[last - 1] != '\n');
+
+ /* Trim the trailing newline */
+ if (*line && line[--last] == '\n')
+ line[last] = '\0';
+
+ return (line);
+}
+
+/* OK, this should be in dhcpcd.c
+ * It's here to make dhcpcd more readable */
+#ifndef HAVE_SRANDOMDEV
+void srandomdev (void)
+{
+ int fd;
+ unsigned long seed;
+
+ fd = open ("/dev/urandom", 0);
+ if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) {
+ logger (LOG_WARNING, "Could not read from /dev/urandom: %s",
+ strerror (errno));
+ seed = time (0);
+ }
+ if (fd >= 0)
+ close(fd);
+
+ srandom (seed);
+}
+#endif
+
+/* strlcpy is nice, shame glibc does not define it */
+#ifndef HAVE_STRLCPY
+size_t strlcpy (char *dst, const char *src, size_t size)
+{
+ const char *s = src;
+ size_t n = size;
+
+ if (n && --n)
+ do {
+ if (! (*dst++ = *src++))
+ break;
+ } while (--n);
+
+ if (! n) {
+ if (size)
+ *dst = '\0';
+ while (*src++);
+ }
+
+ return (src - s - 1);
+}
+#endif
+
+/* Close our fd's */
+int close_fds (void)
+{
+ int fd;
+
+ if ((fd = open ("/dev/null", O_RDWR)) == -1) {
+ logger (LOG_ERR, "open `/dev/null': %s", strerror (errno));
+ return (-1);
+ }
+
+ dup2 (fd, fileno (stdin));
+ dup2 (fd, fileno (stdout));
+ dup2 (fd, fileno (stderr));
+ if (fd > 2)
+ close (fd);
+ return (0);
+}
+
+int close_on_exec (int fd)
+{
+ int flags;
+
+ if ((flags = fcntl (fd, F_GETFD, 0)) == -1
+ || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ {
+ logger (LOG_ERR, "fcntl: %s", strerror (errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/* Handy function to get the time.
+ * We only care about time advancements, not the actual time itself
+ * Which is why we use CLOCK_MONOTONIC, but it is not available on all
+ * platforms.
+ */
+int get_time (struct timeval *tp)
+{
+#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+ static clockid_t posix_clock;
+ static int posix_clock_set = 0;
+
+ if (! posix_clock_set) {
+ if (sysconf (_SC_MONOTONIC_CLOCK) >= 0)
+ posix_clock = CLOCK_MONOTONIC;
+ else
+ posix_clock = CLOCK_REALTIME;
+ posix_clock_set = 1;
+ }
+
+ if (clock_gettime (posix_clock, &ts) == -1) {
+ logger (LOG_ERR, "clock_gettime: %s", strerror (errno));
+ return (-1);
+ }
+
+ tp->tv_sec = ts.tv_sec;
+ tp->tv_usec = ts.tv_nsec / 1000;
+ return (0);
+#else
+ if (gettimeofday (tp, NULL) == -1) {
+ logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
+ return (-1);
+ }
+ return (0);
+#endif
+}
+
+time_t uptime (void)
+{
+ struct timeval tp;
+
+ if (get_time (&tp) == -1)
+ return (-1);
+
+ return (tp.tv_sec);
+}
+
+void writepid (int fd, pid_t pid)
+{
+ char spid[16];
+ if (ftruncate (fd, (off_t) 0) == -1) {
+ logger (LOG_ERR, "ftruncate: %s", strerror (errno));
+ } else {
+ ssize_t len;
+ snprintf (spid, sizeof (spid), "%u", pid);
+ len = pwrite (fd, spid, strlen (spid), (off_t) 0);
+ if (len != (ssize_t) strlen (spid))
+ logger (LOG_ERR, "pwrite: %s", strerror (errno));
+ }
+}
+
+void *xmalloc (size_t s)
+{
+ void *value = malloc (s);
+
+ if (value)
+ return (value);
+
+ logger (LOG_ERR, "memory exhausted");
+
+ exit (EXIT_FAILURE);
+ /* NOTREACHED */
+}
+
+void *xzalloc (size_t s)
+{
+ void *value = xmalloc (s);
+ memset (value, 0, s);
+ return (value);
+}
+
+void *xrealloc (void *ptr, size_t s)
+{
+ void *value = realloc (ptr, s);
+
+ if (value)
+ return (value);
+
+ logger (LOG_ERR, "memory exhausted");
+ exit (EXIT_FAILURE);
+ /* NOTREACHED */
+}
+
+char *xstrdup (const char *str)
+{
+ char *value;
+
+ if (! str)
+ return (NULL);
+
+ if ((value = strdup (str)))
+ return (value);
+
+ logger (LOG_ERR, "memory exhausted");
+ exit (EXIT_FAILURE);
+ /* NOTREACHED */
+}
diff --git a/src/customdhcpcd/common.h b/src/customdhcpcd/common.h
new file mode 100644
index 0000000..46f1886
--- /dev/null
+++ b/src/customdhcpcd/common.h
@@ -0,0 +1,68 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+/* string.h pulls in features.h so the below define checks work */
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+
+#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
+# define _unused __attribute__((__unused__))
+#else
+# define _unused
+#endif
+
+#define HAVE_STRLCPY
+/* Only GLIBC doesn't support strlcpy */
+#ifdef __GLIBC__
+# if ! defined(__UCLIBC__) && ! defined (__dietlibc__)
+# undef HAVE_STRLCPY
+size_t strlcpy (char *dst, const char *src, size_t size);
+# endif
+#endif
+
+#define HAVE_SRANDOMDEV
+#if defined(__GLIBC__) || defined(__NetBSD__)
+# undef HAVE_SRANDOMDEV
+void srandomdev (void);
+#endif
+
+int close_fds (void);
+int close_on_exec (int fd);
+char *get_line (FILE *fp);
+int get_time (struct timeval *tp);
+time_t uptime (void);
+void writepid (int fd, pid_t pid);
+void *xrealloc (void *ptr, size_t size);
+void *xmalloc (size_t size);
+void *xzalloc (size_t size);
+char *xstrdup (const char *str);
+
+#endif
diff --git a/src/customdhcpcd/config.h b/src/customdhcpcd/config.h
new file mode 100644
index 0000000..2c0991b
--- /dev/null
+++ b/src/customdhcpcd/config.h
@@ -0,0 +1,133 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* You can enable/disable various chunks of optional code here.
+ * You would only do this to try and shrink the end binary if dhcpcd
+ * was running on a low memory device */
+
+#define ENABLE_ARP
+#define ENABLE_NTP
+#define ENABLE_NIS
+#define ENABLE_INFO
+/* Define this to enable some compatability with 1.x and 2.x info files */
+/* #define ENABLE_INFO_COMPAT */
+
+/* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927.
+ * Needs ARP. */
+#define ENABLE_IPV4LL
+
+/* We will auto create a DUID_LLT file if it doesn't exist.
+ * You can always create your own DUID file that just contains the
+ * hex string that represents the DUID.
+ * See RFC 3315 for details on this. */
+#define ENABLE_DUID
+
+/* resolvconf is framework for multiple interfaces to manage resolv.conf */
+#define ENABLE_RESOLVCONF
+
+/* Some systems do not have a working fork.
+ * The Makefile will attempt to work it out, but if it fails to feel free to
+ * define it here. */
+/* #define THERE_IS_NO_FORK */
+
+/* Packname name and pathname definitions. */
+
+#define PACKAGE "dhcpcd"
+
+#define ETCDIR "/etc"
+#define RESOLVFILE ETCDIR "/resolv.conf"
+
+#define NISFILE ETCDIR "/yp.conf"
+
+#define NTPFILE ETCDIR "/ntp.conf"
+#define NTPDRIFTFILE ETCDIR "/ntp.drift"
+#define NTPLOGFILE "/var/log/ntp.log"
+
+#define OPENNTPFILE ETCDIR "/ntpd.conf"
+
+#define DEFAULT_SCRIPT ETCDIR "/" PACKAGE ".sh"
+
+#define STATEDIR "/var"
+#define PIDFILE STATEDIR "/run/" PACKAGE "-%s.pid"
+
+#ifndef INFODIR
+# define INFODIR "/var/lib/dhcpcd"
+#endif
+#define INFOFILE INFODIR "/" PACKAGE "-%s.info"
+#define DUIDFILE INFODIR "/" PACKAGE ".duid"
+
+/* OPENRC is Open Run Control, forked from Gentoo's baselayout package
+ * BSDRC is BSD style Run Control
+ * SLACKRC is Slackware Run Control
+ * SERVICE is RedHat service command
+ * SYSV should cover everthing else */
+#ifdef ENABLE_OPENRC
+# define SERVICE "OPENRC"
+# define NISSERVICE ETCDIR "/init.d/ypbind"
+# define NISRESTARTARGS "--nodeps", "--quiet", "conditionalrestart"
+# define NTPSERVICE ETCDIR "/init.d/ntpd"
+# define NTPRESTARTARGS "--nodeps", "--quiet", "conditionalrestart"
+#endif
+#if ENABLE_BSDRC
+# define SERVICE "BSDRC"
+# define NISSERVICE ETCDIR "/rc.d/ypbind"
+# define NISRESTARTARGS "restart"
+# define NTPSERVICE ETCDIR "/rc.d/ntpd"
+# define NTPRESTARTARGS "restart"
+#endif
+#if ENABLE_SLACKRC
+# define SERVICE "SLACKRC"
+# define NISSERVICE ETCDIR "/rc.d/rc.ypbind"
+# define NISRESTARTARGS "restart"
+# define NTPSERVICE ETCDIR "/rc.d/rc.ntpd"
+# define NTPRESTARTARGS "restart"
+#endif
+#if ENABLE_SERVICE
+# define SERVICE "SERVICE"
+# define NISSERVICE "service"
+# define NISRESTARTARGS "ypbind", "restart"
+# define NTPSERVICE "service"
+# define NTPRESTARTARGS "ntpd", "restart"
+#endif
+#if ENABLE_SYSV
+# define SERVICE "SYSV"
+# define NISSERVICE ETCDIR "/init.d/ypbind"
+# define NISRESTARTARGS "restart"
+# define NTPSERVICE ETCDIR "/init.d/ntpd"
+# define NTPRESTARTARGS "restart"
+#endif
+
+#ifndef NISSERVICE
+# undef ENABLE_NIS
+#endif
+#ifndef NTPSERVICE
+# undef ENABLE_NTP
+#endif
+
+#endif
diff --git a/src/customdhcpcd/configure.c b/src/customdhcpcd/configure.c
new file mode 100644
index 0000000..b69ccdc
--- /dev/null
+++ b/src/customdhcpcd/configure.c
@@ -0,0 +1,814 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#ifdef __linux__
+# include <netinet/ether.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcp.h"
+#ifdef ENABLE_INFO
+# include "info.h"
+#endif
+#include "interface.h"
+#include "dhcpcd.h"
+#include "logger.h"
+#include "signal.h"
+#include "socket.h"
+
+#include "logwriter.h"
+
+static int file_in_path (const char *file)
+{
+ char *p = getenv ("PATH");
+ char *path;
+ char *token;
+ struct stat s;
+ char mypath[PATH_MAX];
+ int retval = -1;
+
+ if (! p) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ path = strdup (p);
+ p = path;
+ while ((token = strsep (&p, ":"))) {
+ snprintf (mypath, PATH_MAX, "%s/%s", token, file);
+ if (stat (mypath, &s) == 0) {
+ retval = 0;
+ break;
+ }
+ }
+ free (path);
+ return (retval);
+}
+
+/* IMPORTANT: Ensure that the last parameter is NULL when calling */
+static int exec_cmd (const char *cmd, const char *args, ...)
+{
+ va_list va;
+ char **argv;
+ int n = 1;
+ int ret = 0;
+ pid_t pid;
+ sigset_t full;
+ sigset_t old;
+
+ va_start (va, args);
+ while (va_arg (va, char *) != NULL)
+ n++;
+ va_end (va);
+ argv = xmalloc (sizeof (char *) * (n + 2));
+
+ va_start (va, args);
+ n = 2;
+ argv[0] = (char *) cmd;
+ argv[1] = (char *) args;
+ while ((argv[n] = va_arg (va, char *)) != NULL)
+ n++;
+ va_end (va);
+
+ /* OK, we need to block signals */
+ sigfillset (&full);
+ sigprocmask (SIG_SETMASK, &full, &old);
+
+#ifdef THERE_IS_NO_FORK
+ signal_reset ();
+ pid = vfork ();
+#else
+ pid = fork();
+#endif
+
+ switch (pid) {
+ case -1:
+ logger (LOG_ERR, "vfork: %s", strerror (errno));
+ ret = -1;
+ break;
+ case 0:
+#ifndef THERE_IS_NO_FORK
+ signal_reset ();
+#endif
+ sigprocmask (SIG_SETMASK, &old, NULL);
+ if (execvp (cmd, argv) && errno != ENOENT)
+ logger (LOG_ERR, "error executing \"%s\": %s",
+ cmd, strerror (errno));
+ _exit (111);
+ /* NOTREACHED */
+ }
+
+#ifdef THERE_IS_NO_FORK
+ signal_setup ();
+#endif
+
+ /* Restore our signals */
+ sigprocmask (SIG_SETMASK, &old, NULL);
+
+ free (argv);
+ return (ret);
+}
+
+static void exec_script (const char *script, const char *infofile,
+ const char *arg)
+{
+ struct stat buf;
+
+ if (! script || ! infofile || ! arg)
+ return;
+
+ if (stat (script, &buf) == -1) {
+ if (strcmp (script, DEFAULT_SCRIPT) != 0)
+ logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT));
+ return;
+ }
+
+#ifdef ENABLE_INFO
+ logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg);
+ exec_cmd (script, infofile, arg, (char *) NULL);
+#else
+ logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg);
+ exec_cmd (script, "", arg, (char *) NULL);
+#endif
+}
+
+static int make_resolv (const char *ifname, const dhcp_t *dhcp)
+{
+ FILE *f = NULL;
+ address_t *address;
+
+#ifdef ENABLE_RESOLVCONF
+ char *resolvconf = NULL;
+
+ if (file_in_path ("resolvconf") == 0) {
+ size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1;
+ resolvconf = xmalloc (sizeof (char) * len);
+ snprintf (resolvconf, len, "resolvconf -a %s", ifname);
+ if ((f = popen (resolvconf , "w")))
+ logger (LOG_DEBUG,
+ "sending DNS information to resolvconf");
+ else if (errno == EEXIST)
+ logger (LOG_ERR, "popen: %s", strerror (errno));
+
+ if (ferror (f))
+ logger (LOG_ERR, "ferror");
+ free (resolvconf);
+ }
+#endif
+ if (! f) {
+ logger (LOG_DEBUG, "writing "RESOLVFILE);
+ if (! (f = fopen(RESOLVFILE, "w")))
+ logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno));
+ }
+
+ if (! f)
+ return (-1);
+
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+ if (dhcp->dnssearch)
+ fprintf (f, "search %s\n", dhcp->dnssearch);
+ else if (dhcp->dnsdomain) {
+ fprintf (f, "search %s\n", dhcp->dnsdomain);
+ }
+
+ STAILQ_FOREACH (address, dhcp->dnsservers, entries)
+ fprintf (f, "nameserver %s\n", inet_ntoa (address->address));
+
+#ifdef ENABLE_RESOLVCONF
+ if (resolvconf)
+ pclose (f);
+ else
+#endif
+ fclose (f);
+
+ /* Refresh the local resolver */
+ res_init ();
+ return (0);
+}
+
+static void restore_resolv (const char *ifname)
+{
+#ifdef ENABLE_RESOLVCONF
+ if (file_in_path ("resolvconf") == 0) {
+ logger (LOG_DEBUG, "removing information from resolvconf");
+ exec_cmd("resolvconf", "-d", ifname, (char *) NULL);
+ }
+#endif
+}
+
+static bool in_addresses (const struct address_head *addresses,
+ struct in_addr address)
+{
+ const address_t *addr;
+
+ STAILQ_FOREACH (addr, addresses, entries)
+ if (addr->address.s_addr == address.s_addr)
+ return (true);
+
+ return (false);
+}
+
+static bool in_routes (const struct route_head *routes, route_t *route)
+{
+ const route_t *r;
+
+ if (! routes)
+ return (false);
+
+ STAILQ_FOREACH (r, routes, entries)
+ if (r->destination.s_addr == route->destination.s_addr &&
+ r->netmask.s_addr == route->netmask.s_addr &&
+ r->gateway.s_addr == route->gateway.s_addr)
+ return (true);
+
+ return (false);
+}
+
+#ifdef ENABLE_NTP
+static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp)
+{
+ FILE *f;
+ address_t *address;
+ char *a;
+ char *line;
+ int tomatch = 0;
+ char *token;
+ bool ntp = false;
+
+ STAILQ_FOREACH (address, dhcp->ntpservers, entries)
+ tomatch++;
+
+ /* Check that we really need to update the servers.
+ * We do this because ntp has to be restarted to
+ * work with a changed config. */
+ if (! (f = fopen (file, "r"))) {
+ if (errno != ENOENT) {
+ logger (LOG_ERR, "fopen `%s': %s",
+ file, strerror (errno));
+ return (-1);
+ }
+ } else {
+ while (tomatch != 0 && (line = get_line (f))) {
+ struct in_addr addr;
+
+ a = line;
+ token = strsep (&a, " ");
+ if (! token || strcmp (token, "server") != 0)
+ goto next;
+
+ if ((token = strsep (&a, " \n")) == NULL)
+ goto next;
+
+ if (inet_aton (token, &addr) == 1 &&
+ in_addresses (dhcp->ntpservers, addr))
+ tomatch--;
+
+next:
+ free (line);
+ }
+ fclose (f);
+
+ /* File has the same name servers that we do,
+ * so no need to restart ntp */
+ if (tomatch == 0) {
+ logger (LOG_DEBUG, "%s already configured, skipping",
+ file);
+ return (0);
+ }
+ }
+
+ logger (LOG_DEBUG, "writing %s", file);
+ if (! (f = fopen (file, "w"))) {
+ logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
+ return (-1);
+ }
+
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+#ifdef NTPFILE
+ if (strcmp (file, NTPFILE) == 0) {
+ ntp = true;
+ fprintf (f, "restrict default noquery notrust nomodify\n");
+ fprintf (f, "restrict 127.0.0.1\n");
+ }
+#endif
+
+ STAILQ_FOREACH (address, dhcp->ntpservers, entries) {
+ a = inet_ntoa (address->address);
+ if (ntp)
+ fprintf (f, "restrict %s nomodify notrap noquery\n", a);
+ fprintf (f, "server %s\n", a);
+ }
+ fclose (f);
+
+ return (1);
+}
+
+static int make_ntp (const char *ifname, const dhcp_t *dhcp)
+{
+ /* On some systems we have only have one ntp service, but we don't
+ * know which configuration file we're using. So we need to write
+ * to both and restart accordingly. */
+
+ bool restart_ntp = false;
+ bool restart_openntp = false;
+ int retval = 0;
+
+#ifdef NTPFILE
+ if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
+ restart_ntp = true;
+#endif
+
+#ifdef OPENNTPFILE
+ if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
+ restart_openntp = true;
+#endif
+
+#ifdef NTPSERVICE
+ if (restart_ntp) {
+#ifdef NTPCHECK
+ if (system (NTPCHECK) == 0)
+#endif
+ retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS,
+ (char *) NULL);
+ }
+#endif
+
+#if defined (NTPSERVICE) && defined (OPENNTPSERVICE)
+ if (restart_openntp &&
+ (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
+ {
+#ifdef OPENNTPCHECK
+ if (system (OPENNTPCHECK) == 0)
+#endif
+ retval += exec_cmd (OPENNTPSERVICE,
+ OPENNTPRESTARTARGS, (char *) NULL);
+ }
+#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE)
+ if (restart_openntp) {
+#ifdef OPENNTPCHECK
+ if (system (OPENNTPCHECK) == 0)
+#endif
+ retval += exec_cmd (OPENNTPSERVICE,
+ OPENNTPRESTARTARGS, (char *) NULL);
+ }
+#endif
+
+ return (retval);
+}
+#endif
+
+#ifdef ENABLE_NIS
+#define PREFIXSIZE 256
+static int make_nis (const char *ifname, const dhcp_t *dhcp)
+{
+ FILE *f;
+ address_t *address;
+ char *prefix;
+
+ logger (LOG_DEBUG, "writing "NISFILE);
+ if (! (f = fopen(NISFILE, "w"))) {
+ logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno));
+ return (-1);
+ }
+
+ prefix = xmalloc (sizeof (char) * PREFIXSIZE);
+ *prefix = '\0';
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+
+ if (dhcp->nisdomain) {
+ setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain));
+
+ if (dhcp->nisservers)
+ snprintf (prefix, PREFIXSIZE, "domain %s server",
+ dhcp->nisdomain);
+ else
+ fprintf (f, "domain %s broadcast\n", dhcp->nisdomain);
+ }
+ else
+ snprintf (prefix, PREFIXSIZE, "%s", "ypserver");
+
+ NSTAILQ_FOREACH (address, dhcp->nisservers, entries)
+ fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address));
+
+ free (prefix);
+ fclose (f);
+
+#ifdef NISCHECK
+ if (system (NISCHECK) == 0)
+#endif
+ exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL);
+ return (0);
+}
+#endif
+
+static char *lookuphostname (char *hostname, const dhcp_t *dhcp,
+ const options_t *options)
+{
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ } su;
+ socklen_t salen;
+ char *addr;
+ struct addrinfo hints;
+ struct addrinfo *res = NULL;
+ int result;
+ char *p;
+
+ logger (LOG_DEBUG, "Looking up hostname via DNS");
+ addr = xmalloc (sizeof (char) * NI_MAXHOST);
+ salen = sizeof (su.sa);
+ memset (&su.sa, 0, salen);
+ su.sin.sin_family = AF_INET;
+ memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr));
+
+ if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST,
+ NULL, 0, NI_NAMEREQD)) != 0) {
+ logger (LOG_ERR,
+ "Failed to lookup hostname via DNS: %s",
+ gai_strerror (result));
+ free (addr);
+ return (NULL);
+ }
+
+ /* Check for a malicious PTR record */
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ result = getaddrinfo (addr, "0", &hints, &res);
+ if (res)
+ freeaddrinfo (res);
+ if (result == 0)
+ logger (LOG_ERR, "malicious PTR record detected");
+ if (result == 0 || ! *addr) {
+ free (addr);
+ return (NULL);
+ }
+
+ p = strchr (addr, '.');
+ if (p) {
+ switch (options->dohostname) {
+ case 1: /* -H */
+ case 4: /* -HHHH */
+ break;
+ case 2: /* -HH */
+ case 5: /* -HHHHH */
+ /* Strip out the domain if it matches */
+ p++;
+ if (*p && dhcp->dnssearch) {
+ char *s = xstrdup (dhcp->dnssearch);
+ char *sp = s;
+ char *t;
+
+ while ((t = strsep (&sp, " ")))
+ if (strcmp (t, p) == 0) {
+ *--p = '\0';
+ break;
+ }
+ free (s);
+ } else if (dhcp->dnsdomain) {
+ if (strcmp (dhcp->dnsdomain, p) == 0)
+ *--p = '\0';
+ }
+ break;
+ case 3: /* -HHH */
+ case 6: /* -HHHHHH */
+ /* Just strip the domain */
+ *p = '\0';
+ break;
+ default: /* Too many H! */
+ break;
+ }
+ }
+
+ strlcpy (hostname, addr, MAXHOSTNAMELEN);
+ free (addr);
+ return (hostname);
+}
+
+int configure (const options_t *options, interface_t *iface,
+ const dhcp_t *dhcp, bool up)
+{
+ route_t *route = NULL;
+ struct route_head *new_routes = NULL;
+ route_t *new_route = NULL;
+ char *newhostname = NULL;
+ char *curhostname = NULL;
+ int remember;
+#ifdef ENABLE_IPV4LL
+ bool haslinklocal = false;
+#endif
+#ifdef THERE_IS_NO_FORK
+ int skip = 0;
+ size_t skiplen;
+ char *skipp;
+#endif
+
+ if (! options || ! iface || ! dhcp)
+ return (-1);
+
+ if (dhcp->address.s_addr == 0)
+ up = 0;
+
+ logGatewayToFile(iface, dhcp);
+
+ /* Remove old routes.
+ * Always do this as the interface may have >1 address not added by us
+ * so the routes we added may still exist. */
+ NSTAILQ_FOREACH (route, iface->previous_routes, entries)
+ if ((route->destination.s_addr || options->dogateway) &&
+ (! up || ! in_routes (dhcp->routes, route)))
+ del_route (iface->name, route->destination,
+ route->netmask, route->gateway,
+ options->metric);
+ /* If we aren't up, then reset the interface as much as we can */
+ if (! up) {
+ if (iface->previous_routes) {
+ free_route (iface->previous_routes);
+ iface->previous_routes = NULL;
+ }
+
+ /* Restore the original MTU value */
+ if (iface->mtu && iface->previous_mtu != iface->mtu) {
+ set_mtu (iface->name, iface->mtu);
+ iface->previous_mtu = iface->mtu;
+ }
+
+#ifdef ENABLE_INFO
+ /* If we haven't created an info file, do so now */
+ if (! dhcp->frominfo)
+ write_info (iface, dhcp, options, false);
+#endif
+
+ /* Only reset things if we had set them before */
+ if (iface->previous_address.s_addr != 0) {
+ if (! options->keep_address) {
+ del_address (iface->name,
+ iface->previous_address,
+ iface->previous_netmask);
+ memset (&iface->previous_address,
+ 0, sizeof (iface->previous_address));
+ memset (&iface->previous_netmask,
+ 0, sizeof (iface->previous_netmask));
+ }
+ }
+
+ restore_resolv (iface->name);
+ exec_script (options->script, iface->infofile, "down");
+
+ return (0);
+ }
+
+ /* Set the MTU requested.
+ * If the DHCP server no longer sends one OR it's invalid then
+ * we restore the original MTU */
+ if (options->domtu) {
+ unsigned short mtu = iface->mtu;
+ if (dhcp->mtu)
+ mtu = dhcp->mtu;
+
+ if (mtu != iface->previous_mtu) {
+ if (set_mtu (iface->name, mtu) == 0)
+ iface->previous_mtu = mtu;
+ }
+ }
+
+ /* This also changes netmask */
+ if (! options->doinform || ! has_address (iface->name, dhcp->address))
+ if (add_address (iface->name, dhcp->address, dhcp->netmask,
+ dhcp->broadcast) == -1 && errno != EEXIST)
+ return (false);
+
+ /* Now delete the old address if different */
+ if (iface->previous_address.s_addr != dhcp->address.s_addr &&
+ iface->previous_address.s_addr != 0 &&
+ ! options->keep_address)
+ del_address (iface->name,
+ iface->previous_address, iface->previous_netmask);
+
+#ifdef __linux__
+ /* On linux, we need to change the subnet route to have our metric. */
+ if (iface->previous_address.s_addr != dhcp->address.s_addr &&
+ options->metric > 0 &&
+ dhcp->netmask.s_addr != INADDR_BROADCAST)
+ {
+ struct in_addr td;
+ struct in_addr tg;
+ memset (&td, 0, sizeof (td));
+ memset (&tg, 0, sizeof (tg));
+ td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
+ add_route (iface->name, td, dhcp->netmask, tg, options->metric);
+ del_route (iface->name, td, dhcp->netmask, tg, 0);
+ }
+#endif
+
+#ifdef THERE_IS_NO_FORK
+ free (dhcpcd_skiproutes);
+ /* We can never have more than 255 routes. So we need space
+ * for 255 3 digit numbers and commas */
+ skiplen = 255 * 4 + 1;
+ skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen);
+ *skipp = '\0';
+#endif
+
+ /* Remember added routes */
+ NSTAILQ_FOREACH (route, dhcp->routes, entries) {
+#ifdef ENABLE_IPV4LL
+ /* Check if we have already got a link locale route dished
+ * out by the DHCP server */
+ if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) &&
+ route->netmask.s_addr == htonl (LINKLOCAL_MASK))
+ haslinklocal = true;
+#endif
+ /* Don't set default routes if not asked to */
+ if (route->destination.s_addr == 0 &&
+ route->netmask.s_addr == 0 &&
+ ! options->dogateway)
+ continue;
+
+ remember = add_route (iface->name, route->destination,
+ route->netmask, route->gateway,
+ options->metric);
+ /* If we failed to add the route, we may have already added it
+ ourselves. If so, remember it again. */
+ if (remember < 0 && in_routes (iface->previous_routes, route))
+ remember = 1;
+
+ if (remember >= 0) {
+ if (! new_routes) {
+ new_routes = xmalloc (sizeof (*new_routes));
+ STAILQ_INIT (new_routes);
+ }
+ new_route = xmalloc (sizeof (route_t));
+ memcpy (new_route, route, sizeof (*new_route));
+ STAILQ_INSERT_TAIL (new_routes, new_route, entries);
+ }
+#ifdef THERE_IS_NO_FORK
+ /* If we have daemonised yet we need to record which routes
+ * we failed to add so we can skip them */
+ else if (! options->daemonised) {
+ /* We can never have more than 255 / 4 routes,
+ * so 3 chars is plently */
+ if (*skipp)
+ *skipp++ = ',';
+ skipp += snprintf (skipp,
+ dhcpcd_skiproutes + skiplen - skipp,
+ "%d", skip);
+ }
+ skip++;
+#endif
+ }
+
+#ifdef THERE_IS_NO_FORK
+ if (*dhcpcd_skiproutes)
+ *skipp = '\0';
+ else {
+ free (dhcpcd_skiproutes);
+ dhcpcd_skiproutes = NULL;
+ }
+#endif
+
+#ifdef ENABLE_IPV4LL
+ /* Ensure we always add the link local route if we got a private
+ * address and isn't link local itself */
+ if (options->doipv4ll &&
+ ! haslinklocal &&
+ IN_PRIVATE (ntohl (dhcp->address.s_addr)))
+ {
+ struct in_addr dest;
+ struct in_addr mask;
+ struct in_addr gate;
+
+ dest.s_addr = htonl (LINKLOCAL_ADDR);
+ mask.s_addr = htonl (LINKLOCAL_MASK);
+ gate.s_addr = 0;
+ remember = add_route (iface->name, dest, mask, gate,
+ options->metric);
+
+ if (remember >= 0) {
+ if (! new_routes) {
+ new_routes = xmalloc (sizeof (*new_routes));
+ STAILQ_INIT (new_routes);
+ }
+ new_route = xmalloc (sizeof (*new_route));
+ new_route->destination.s_addr = dest.s_addr;
+ new_route->netmask.s_addr = mask.s_addr;
+ new_route->gateway.s_addr = gate.s_addr;
+ STAILQ_INSERT_TAIL (new_routes, new_route, entries);
+ }
+ }
+#endif
+
+ if (iface->previous_routes)
+ free_route (iface->previous_routes);
+ iface->previous_routes = new_routes;
+
+ logToQt(LOG_INFO, DHCPCD_WRITE, "");
+ if (options->dodns && dhcp->dnsservers)
+ make_resolv(iface->name, dhcp);
+ else
+ logger (LOG_DEBUG, "no dns information to write");
+
+#ifdef ENABLE_NTP
+ if (options->dontp && dhcp->ntpservers)
+ make_ntp(iface->name, dhcp);
+#endif
+
+#ifdef ENABLE_NIS
+ if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
+ make_nis(iface->name, dhcp);
+#endif
+
+ curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN);
+ *curhostname = '\0';
+
+ gethostname (curhostname, MAXHOSTNAMELEN);
+ if (options->dohostname ||
+ strlen (curhostname) == 0 ||
+ strcmp (curhostname, "(none)") == 0 ||
+ strcmp (curhostname, "localhost") == 0)
+ {
+ newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN);
+
+ if (dhcp->hostname)
+ strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN);
+ else
+ *newhostname = '\0';
+
+ /* Now we have made a resolv.conf we can obtain a hostname
+ * if we need it */
+ if (! *newhostname || options->dohostname > 3)
+ lookuphostname (newhostname, dhcp, options);
+
+ if (*newhostname) {
+ logger (LOG_INFO, "setting hostname to `%s'",
+ newhostname);
+ sethostname (newhostname, (int) strlen (newhostname));
+ }
+
+ free (newhostname);
+ }
+
+ free (curhostname);
+
+#ifdef ENABLE_INFO
+ if (! dhcp->frominfo)
+ write_info (iface, dhcp, options, true);
+#endif
+
+ if (iface->previous_address.s_addr != dhcp->address.s_addr ||
+ iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
+ {
+ memcpy (&iface->previous_address,
+ &dhcp->address, sizeof (iface->previous_address));
+ memcpy (&iface->previous_netmask,
+ &dhcp->netmask, sizeof (iface->previous_netmask));
+ exec_script (options->script, iface->infofile, "new");
+ } else
+ exec_script (options->script, iface->infofile, "up");
+
+ return (0);
+}
diff --git a/src/customdhcpcd/configure.h b/src/customdhcpcd/configure.h
new file mode 100644
index 0000000..3166947
--- /dev/null
+++ b/src/customdhcpcd/configure.h
@@ -0,0 +1,38 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCPCONFIG_H
+#define DHCPCONFIG_H
+
+#include "dhcpcd.h"
+#include "interface.h"
+#include "dhcp.h"
+
+int configure (const options_t *options, interface_t *iface,
+ const dhcp_t *dhcp, bool up);
+
+#endif
diff --git a/src/customdhcpcd/dhcp.c b/src/customdhcpcd/dhcp.c
new file mode 100644
index 0000000..f625e8f
--- /dev/null
+++ b/src/customdhcpcd/dhcp.c
@@ -0,0 +1,933 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <net/if_arp.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "common.h"
+#include "dhcpcd.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+#include "socket.h"
+
+#ifndef STAILQ_CONCAT
+#define STAILQ_CONCAT(head1, head2) do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+} while (0)
+#endif
+
+typedef struct message {
+ int value;
+ const char *name;
+} dhcp_message_t;
+
+static dhcp_message_t dhcp_messages[] = {
+ { DHCP_DISCOVER, "DHCP_DISCOVER" },
+ { DHCP_OFFER, "DHCP_OFFER" },
+ { DHCP_REQUEST, "DHCP_REQUEST" },
+ { DHCP_DECLINE, "DHCP_DECLINE" },
+ { DHCP_ACK, "DHCP_ACK" },
+ { DHCP_NAK, "DHCP_NAK" },
+ { DHCP_RELEASE, "DHCP_RELEASE" },
+ { DHCP_INFORM, "DHCP_INFORM" },
+ { -1, NULL }
+};
+
+static const char *dhcp_message (int type)
+{
+ dhcp_message_t *d;
+ for (d = dhcp_messages; d->name; d++)
+ if (d->value == type)
+ return (d->name);
+
+ return (NULL);
+}
+
+ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp,
+ uint32_t xid, char type, const options_t *options)
+{
+ struct udp_dhcp_packet *packet;
+ dhcpmessage_t *message;
+ unsigned char *m;
+ unsigned char *p;
+ unsigned char *n_params = NULL;
+ size_t l;
+ struct in_addr from;
+ struct in_addr to;
+ time_t up = uptime() - iface->start_uptime;
+ uint32_t ul;
+ uint16_t sz;
+ size_t message_length;
+ ssize_t retval;
+
+ if (!iface || !options || !dhcp)
+ return -1;
+
+ memset (&from, 0, sizeof (from));
+ memset (&to, 0, sizeof (to));
+
+ if (type == DHCP_RELEASE)
+ to.s_addr = dhcp->serveraddress.s_addr;
+
+ message = xzalloc (sizeof (*message));
+ m = (unsigned char *) message;
+ p = (unsigned char *) &message->options;
+
+ if ((type == DHCP_INFORM ||
+ type == DHCP_RELEASE ||
+ type == DHCP_REQUEST) &&
+ ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)))
+ {
+ message->ciaddr = iface->previous_address.s_addr;
+ from.s_addr = iface->previous_address.s_addr;
+
+ /* Just incase we haven't actually configured the address yet */
+ if (type == DHCP_INFORM && iface->previous_address.s_addr == 0)
+ message->ciaddr = dhcp->address.s_addr;
+
+ /* Zero the address if we're currently on a different subnet */
+ if (type == DHCP_REQUEST &&
+ iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
+ message->ciaddr = from.s_addr = 0;
+
+ if (from.s_addr != 0)
+ to.s_addr = dhcp->serveraddress.s_addr;
+ }
+
+ message->op = DHCP_BOOTREQUEST;
+ message->hwtype = iface->family;
+ switch (iface->family) {
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE802:
+ message->hwlen = ETHER_ADDR_LEN;
+ memcpy (&message->chaddr, &iface->hwaddr,
+ ETHER_ADDR_LEN);
+ break;
+ case ARPHRD_IEEE1394:
+ case ARPHRD_INFINIBAND:
+ message->hwlen = 0;
+ if (message->ciaddr == 0)
+ message->flags = htons (BROADCAST_FLAG);
+ break;
+ default:
+ logger (LOG_ERR, "dhcp: unknown hardware type %d",
+ iface->family);
+ }
+
+ if (up < 0 || up > (time_t) UINT16_MAX)
+ message->secs = htons ((uint16_t) UINT16_MAX);
+ else
+ message->secs = htons (up);
+ message->xid = xid;
+ message->cookie = htonl (MAGIC_COOKIE);
+
+ *p++ = DHCP_MESSAGETYPE;
+ *p++ = 1;
+ *p++ = type;
+
+ if (type == DHCP_REQUEST) {
+ *p++ = DHCP_MAXMESSAGESIZE;
+ *p++ = 2;
+ sz = get_mtu (iface->name);
+ if (sz < MTU_MIN) {
+ if (set_mtu (iface->name, MTU_MIN) == 0)
+ sz = MTU_MIN;
+ }
+ sz = htons (sz);
+ memcpy (p, &sz, 2);
+ p += 2;
+ }
+
+ *p++ = DHCP_CLIENTID;
+ *p++ = iface->clientid_len;
+ memcpy (p, iface->clientid, iface->clientid_len);
+ p+= iface->clientid_len;
+
+ if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
+ if (options->userclass_len > 0) {
+ *p++ = DHCP_USERCLASS;
+ *p++ = options->userclass_len;
+ memcpy (p, &options->userclass, options->userclass_len);
+ p += options->userclass_len;
+ }
+
+ if (*options->classid > 0) {
+ *p++ = DHCP_CLASSID;
+ *p++ = l = strlen (options->classid);
+ memcpy (p, options->classid, l);
+ p += l;
+ }
+ }
+
+ if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
+#define PUTADDR(_type, _val) { \
+ *p++ = _type; \
+ *p++ = 4; \
+ memcpy (p, &_val.s_addr, 4); \
+ p += 4; \
+}
+ if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)))
+ logger (LOG_ERR,
+ "cannot request a link local address");
+ else {
+ if (dhcp->address.s_addr &&
+ dhcp->address.s_addr !=
+ iface->previous_address.s_addr)
+ {
+ PUTADDR (DHCP_ADDRESS, dhcp->address);
+ if (dhcp->serveraddress.s_addr)
+ PUTADDR (DHCP_SERVERIDENTIFIER,
+ dhcp->serveraddress);
+ }
+ }
+#undef PUTADDR
+
+ if (options->leasetime != 0) {
+ *p++ = DHCP_LEASETIME;
+ *p++ = 4;
+ ul = htonl (options->leasetime);
+ memcpy (p, &ul, 4);
+ p += 4;
+ }
+ }
+
+ if (type == DHCP_DISCOVER ||
+ type == DHCP_INFORM ||
+ type == DHCP_REQUEST)
+ {
+ if (options->hostname[0]) {
+ if (options->fqdn == FQDN_DISABLE) {
+ *p++ = DHCP_HOSTNAME;
+ *p++ = l = strlen (options->hostname);
+ memcpy (p, options->hostname, l);
+ p += l;
+ } else {
+ /* Draft IETF DHC-FQDN option (81) */
+ *p++ = DHCP_FQDN;
+ *p++ = (l = strlen (options->hostname)) + 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
+ * E: 1 => Name data is DNS format
+ * N: 1 => Client requests Server to not
+ * update DNS
+ */
+ *p++ = options->fqdn & 0x9;
+ *p++ = 0; /* from server for PTR RR */
+ *p++ = 0; /* from server for A RR if S=1 */
+ memcpy (p, options->hostname, l);
+ p += l;
+ }
+ }
+
+ *p++ = DHCP_PARAMETERREQUESTLIST;
+ n_params = p;
+ *p++ = 0;
+ /* Only request DNSSERVER in discover to keep the packets small.
+ * RFC2131 Section 3.5 states that the REQUEST must include the
+ * list from the DISCOVER message, so I think this is ok. */
+
+ if (type == DHCP_DISCOVER && ! options->test)
+ *p++ = DHCP_DNSSERVER;
+ else {
+ if (type != DHCP_INFORM) {
+ *p++ = DHCP_RENEWALTIME;
+ *p++ = DHCP_REBINDTIME;
+ }
+ *p++ = DHCP_NETMASK;
+ *p++ = DHCP_BROADCAST;
+
+ /* -S means request CSR and MSCSR
+ * -SS means only request MSCSR incase DHCP message
+ * is too big */
+ if (options->domscsr < 2)
+ *p++ = DHCP_CSR;
+ if (options->domscsr > 0)
+ *p++ = DHCP_MSCSR;
+ /* RFC 3442 states classless static routes should be
+ * before routers and static routes as classless static
+ * routes override them both */
+ *p++ = DHCP_STATICROUTE;
+ *p++ = DHCP_ROUTERS;
+ *p++ = DHCP_HOSTNAME;
+ *p++ = DHCP_DNSSEARCH;
+ *p++ = DHCP_DNSDOMAIN;
+ *p++ = DHCP_DNSSERVER;
+#ifdef ENABLE_NIS
+ *p++ = DHCP_NISDOMAIN;
+ *p++ = DHCP_NISSERVER;
+#endif
+#ifdef ENABLE_NTP
+ *p++ = DHCP_NTPSERVER;
+#endif
+ *p++ = DHCP_MTU;
+#ifdef ENABLE_INFO
+ *p++ = DHCP_ROOTPATH;
+ *p++ = DHCP_SIPSERVER;
+#endif
+ }
+
+ *n_params = p - n_params - 1;
+ }
+ *p++ = DHCP_END;
+
+#ifdef BOOTP_MESSAGE_LENTH_MIN
+ /* Some crappy DHCP servers think they have to obey the BOOTP minimum
+ * message length.
+ * They are wrong, but we should still cater for them. */
+ while (p - m < BOOTP_MESSAGE_LENTH_MIN)
+ *p++ = DHCP_PAD;
+#endif
+
+ message_length = p - m;
+
+ packet = xzalloc (sizeof (*packet));
+ make_dhcp_packet (packet, (unsigned char *) message, message_length,
+ from, to);
+ free (message);
+
+ logger (LOG_DEBUG, "sending %s with xid 0x%x",
+ dhcp_message (type), xid);
+ retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet,
+ message_length +
+ sizeof (packet->ip) + sizeof (packet->udp));
+ free (packet);
+ return (retval);
+}
+
+/* Decode an RFC3397 DNS search order option into a space
+ * seperated string. Returns length of string (including
+ * terminating zero) or zero on error. out may be NULL
+ * to just determine output length. */
+static unsigned int decode_search (const unsigned char *p, int len, char *out)
+{
+ const unsigned char *r, *q = p;
+ unsigned int count = 0, l, hops;
+
+ while (q - p < len) {
+ r = NULL;
+ hops = 0;
+ while ((l = *q++)) {
+ unsigned int label_type = l & 0xc0;
+ if (label_type == 0x80 || label_type == 0x40)
+ return 0;
+ else if (label_type == 0xc0) { /* pointer */
+ l = (l & 0x3f) << 8;
+ l |= *q++;
+
+ /* save source of first jump. */
+ if (!r)
+ r = q;
+
+ hops++;
+ if (hops > 255)
+ return 0;
+
+ q = p + l;
+ if (q - p >= len)
+ return 0;
+ } else {
+ /* straightforward name segment, add with '.' */
+ count += l + 1;
+ if (out) {
+ memcpy (out, q, l);
+ out += l;
+ *out++ = '.';
+ }
+ q += l;
+ }
+ }
+
+ /* change last dot to space */
+ if (out)
+ *(out - 1) = ' ';
+
+ if (r)
+ q = r;
+ }
+
+ /* change last space to zero terminator */
+ if (out)
+ *(out - 1) = 0;
+
+ return count;
+}
+
+/* Add our classless static routes to the routes variable
+ * and return the last route set */
+static struct route_head *decode_CSR (const unsigned char *p, int len)
+{
+ const unsigned char *q = p;
+ unsigned int cidr;
+ unsigned int ocets;
+ struct route_head *routes = NULL;
+ route_t *route;
+
+ /* Minimum is 5 -first is CIDR and a router length of 4 */
+ if (len < 5)
+ return NULL;
+
+ while (q - p < len) {
+ if (! routes) {
+ routes = xmalloc (sizeof (*routes));
+ STAILQ_INIT (routes);
+ }
+
+ route = xzalloc (sizeof (*route));
+
+ cidr = *q++;
+ if (cidr > 32) {
+ logger (LOG_ERR,
+ "invalid CIDR of %d in classless static route",
+ cidr);
+ free_route (routes);
+ return (NULL);
+ }
+ ocets = (cidr + 7) / 8;
+
+ if (ocets > 0) {
+ memcpy (&route->destination.s_addr, q, (size_t) ocets);
+ q += ocets;
+ }
+
+ /* Now enter the netmask */
+ if (ocets > 0) {
+ memset (&route->netmask.s_addr, 255, (size_t) ocets - 1);
+ memset ((unsigned char *) &route->netmask.s_addr +
+ (ocets - 1),
+ (256 - (1 << (32 - cidr) % 8)), 1);
+ }
+
+ /* Finally, snag the router */
+ memcpy (&route->gateway.s_addr, q, 4);
+ q += 4;
+
+ STAILQ_INSERT_TAIL (routes, route, entries);
+ }
+
+ return (routes);
+}
+
+void free_dhcp (dhcp_t *dhcp)
+{
+ if (! dhcp)
+ return;
+
+ free_route (dhcp->routes);
+ free (dhcp->hostname);
+ free_address (dhcp->dnsservers);
+ free (dhcp->dnsdomain);
+ free (dhcp->dnssearch);
+ free_address (dhcp->ntpservers);
+ free (dhcp->nisdomain);
+ free_address (dhcp->nisservers);
+ free (dhcp->rootpath);
+ free (dhcp->sipservers);
+ if (dhcp->fqdn) {
+ free (dhcp->fqdn->name);
+ free (dhcp->fqdn);
+ }
+}
+
+
+static bool dhcp_add_address (struct address_head **addresses,
+ const unsigned char *data,
+ int length)
+{
+ int i;
+ address_t *address;
+
+ for (i = 0; i < length; i += 4) {
+ /* Sanity check */
+ if (i + 4 > length) {
+ logger (LOG_ERR, "invalid address length");
+ return (false);
+ }
+
+ if (*addresses == NULL) {
+ *addresses = xmalloc (sizeof (**addresses));
+ STAILQ_INIT (*addresses);
+ }
+ address = xzalloc (sizeof (*address));
+ memcpy (&address->address.s_addr, data + i, 4);
+ STAILQ_INSERT_TAIL (*addresses, address, entries);
+ }
+
+ return (true);
+}
+
+#ifdef ENABLE_INFO
+static char *decode_sipservers (const unsigned char *data, int length)
+{
+ char *sip = NULL;
+ char *p;
+ const char encoding = *data++;
+ struct in_addr addr;
+ size_t len;
+
+ length--;
+
+ switch (encoding) {
+ case 0:
+ if ((len = decode_search (data, length, NULL)) > 0) {
+ sip = xmalloc (len);
+ decode_search (data, length, sip);
+ }
+ break;
+
+ case 1:
+ if (length == 0 || length % 4 != 0) {
+ logger (LOG_ERR,
+ "invalid length %d for option 120",
+ length + 1);
+ break;
+ }
+ len = ((length / 4) * (4 * 4)) + 1;
+ sip = p = xmalloc (len);
+ while (length != 0) {
+ memcpy (&addr.s_addr, data, 4);
+ data += 4;
+ p += snprintf (p, len - (p - sip),
+ "%s ", inet_ntoa (addr));
+ length -= 4;
+ }
+ *--p = '\0';
+ break;
+
+ default:
+ logger (LOG_ERR, "unknown sip encoding %d", encoding);
+ break;
+ }
+
+ return (sip);
+}
+#endif
+
+/* This calculates the netmask that we should use for static routes.
+ * This IS different from the calculation used to calculate the netmask
+ * for an interface address. */
+static uint32_t route_netmask (uint32_t ip_in)
+{
+ /* used to be unsigned long - check if error */
+ uint32_t p = ntohl (ip_in);
+ uint32_t t;
+
+ if (IN_CLASSA (p))
+ t = ~IN_CLASSA_NET;
+ else {
+ if (IN_CLASSB (p))
+ t = ~IN_CLASSB_NET;
+ else {
+ if (IN_CLASSC (p))
+ t = ~IN_CLASSC_NET;
+ else
+ t = 0;
+ }
+ }
+
+ while (t & p)
+ t >>= 1;
+
+ return (htonl (~t));
+}
+
+static struct route_head *decode_routes (const unsigned char *data, int length)
+{
+ int i;
+ struct route_head *head = NULL;
+ route_t *route;
+
+ for (i = 0; i < length; i += 8) {
+ if (! head) {
+ head = xmalloc (sizeof (*head));
+ STAILQ_INIT (head);
+ }
+ route = xzalloc (sizeof (*route));
+ memcpy (&route->destination.s_addr, data + i, 4);
+ memcpy (&route->gateway.s_addr, data + i + 4, 4);
+ route->netmask.s_addr =
+ route_netmask (route->destination.s_addr);
+ STAILQ_INSERT_TAIL (head, route, entries);
+ }
+
+ return (head);
+}
+
+static struct route_head *decode_routers (const unsigned char *data, int length)
+{
+ int i;
+ struct route_head *head = NULL;
+ route_t *route = NULL;
+
+ for (i = 0; i < length; i += 4) {
+ if (! head) {
+ head = xmalloc (sizeof (*head));
+ STAILQ_INIT (head);
+ }
+ route = xzalloc (sizeof (*route));
+ memcpy (&route->gateway.s_addr, data + i, 4);
+ STAILQ_INSERT_TAIL (head, route, entries);
+ }
+
+ return (head);
+}
+
+int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message)
+{
+ const unsigned char *p = message->options;
+ const unsigned char *end = p; /* Add size later for gcc-3 issue */
+ unsigned char option;
+ unsigned char length;
+ unsigned int len = 0;
+ int retval = -1;
+ struct timeval tv;
+ struct route_head *routers = NULL;
+ struct route_head *routes = NULL;
+ struct route_head *csr = NULL;
+ struct route_head *mscsr = NULL;
+ bool in_overload = false;
+ bool parse_sname = false;
+ bool parse_file = false;
+
+ end += sizeof (message->options);
+
+ if (gettimeofday (&tv, NULL) == -1) {
+ logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
+ return (-1);
+ }
+
+ dhcp->address.s_addr = message->yiaddr;
+ dhcp->leasedfrom = tv.tv_sec;
+ dhcp->frominfo = false;
+ dhcp->address.s_addr = message->yiaddr;
+ strlcpy (dhcp->servername, (char *) message->servername,
+ sizeof (dhcp->servername));
+
+#define LEN_ERR \
+ { \
+ logger (LOG_ERR, "invalid length %d for option %d", \
+ length, option); \
+ p += length; \
+ continue; \
+ }
+
+parse_start:
+ while (p < end) {
+ option = *p++;
+ if (! option)
+ continue;
+
+ if (option == DHCP_END)
+ goto eexit;
+
+ length = *p++;
+
+ if (option != DHCP_PAD && length == 0) {
+ logger (LOG_ERR, "option %d has zero length", option);
+ retval = -1;
+ goto eexit;
+ }
+
+ if (p + length >= end) {
+ logger (LOG_ERR, "dhcp option exceeds message length");
+ retval = -1;
+ goto eexit;
+ }
+
+ switch (option) {
+ case DHCP_MESSAGETYPE:
+ retval = (int) *p;
+ p += length;
+ continue;
+
+ default:
+ if (length == 0) {
+ logger (LOG_DEBUG,
+ "option %d has zero length, skipping",
+ option);
+ continue;
+ }
+ }
+
+#define LENGTH(_length) \
+ if (length != _length) \
+ LEN_ERR;
+#define MIN_LENGTH(_length) \
+ if (length < _length) \
+ LEN_ERR;
+#define MULT_LENGTH(_mult) \
+ if (length % _mult != 0) \
+ LEN_ERR;
+#define GET_UINT8(_val) \
+ LENGTH (sizeof (uint8_t)); \
+ memcpy (&_val, p, sizeof (uint8_t));
+#define GET_UINT16(_val) \
+ LENGTH (sizeof (uint16_t)); \
+ memcpy (&_val, p, sizeof (uint16_t));
+#define GET_UINT32(_val) \
+ LENGTH (sizeof (uint32_t)); \
+ memcpy (&_val, p, sizeof (uint32_t));
+#define GET_UINT16_H(_val) \
+ GET_UINT16 (_val); \
+ _val = ntohs (_val);
+#define GET_UINT32_H(_val) \
+ GET_UINT32 (_val); \
+ _val = ntohl (_val);
+
+ switch (option) {
+ case DHCP_ADDRESS:
+ GET_UINT32 (dhcp->address.s_addr);
+ break;
+ case DHCP_NETMASK:
+ GET_UINT32 (dhcp->netmask.s_addr);
+ break;
+ case DHCP_BROADCAST:
+ GET_UINT32 (dhcp->broadcast.s_addr);
+ break;
+ case DHCP_SERVERIDENTIFIER:
+ GET_UINT32 (dhcp->serveraddress.s_addr);
+ break;
+ case DHCP_LEASETIME:
+ GET_UINT32_H (dhcp->leasetime);
+ break;
+ case DHCP_RENEWALTIME:
+ GET_UINT32_H (dhcp->renewaltime);
+ break;
+ case DHCP_REBINDTIME:
+ GET_UINT32_H (dhcp->rebindtime);
+ break;
+ case DHCP_MTU:
+ GET_UINT16_H (dhcp->mtu);
+ /* Minimum legal mtu is 68 accoridng to
+ * RFC 2132. In practise it's 576 which is the
+ * minimum maximum message size. */
+ if (dhcp->mtu < MTU_MIN) {
+ logger (LOG_DEBUG,
+ "MTU %d is too low, minimum is %d; ignoring",
+ dhcp->mtu, MTU_MIN);
+ dhcp->mtu = 0;
+ }
+ break;
+
+#undef GET_UINT32_H
+#undef GET_UINT32
+#undef GET_UINT16_H
+#undef GET_UINT16
+#undef GET_UINT8
+
+#define GETSTR(_var) { \
+ MIN_LENGTH (sizeof (char)); \
+ if (_var) free (_var); \
+ _var = xmalloc ((size_t) length + 1); \
+ memcpy (_var, p, (size_t) length); \
+ memset (_var + length, 0, 1); \
+}
+ case DHCP_HOSTNAME:
+ GETSTR (dhcp->hostname);
+ break;
+ case DHCP_DNSDOMAIN:
+ GETSTR (dhcp->dnsdomain);
+ break;
+ case DHCP_MESSAGE:
+ GETSTR (dhcp->message);
+ break;
+#ifdef ENABLE_INFO
+ case DHCP_ROOTPATH:
+ GETSTR (dhcp->rootpath);
+ break;
+#endif
+#ifdef ENABLE_NIS
+ case DHCP_NISDOMAIN:
+ GETSTR (dhcp->nisdomain);
+ break;
+#endif
+#undef GETSTR
+
+#define GETADDR(_var) \
+ MULT_LENGTH (4); \
+ if (! dhcp_add_address (&_var, p, length)) \
+ { \
+ retval = -1; \
+ goto eexit; \
+ }
+ case DHCP_DNSSERVER:
+ GETADDR (dhcp->dnsservers);
+ break;
+#ifdef ENABLE_NTP
+ case DHCP_NTPSERVER:
+ GETADDR (dhcp->ntpservers);
+ break;
+#endif
+#ifdef ENABLE_NIS
+ case DHCP_NISSERVER:
+ GETADDR (dhcp->nisservers);
+ break;
+#endif
+#undef GETADDR
+
+ case DHCP_DNSSEARCH:
+ MIN_LENGTH (1);
+ free (dhcp->dnssearch);
+ len = decode_search (p, length, NULL);
+ if (len > 0) {
+ dhcp->dnssearch = xmalloc (len);
+ decode_search (p, length,
+ dhcp->dnssearch);
+ }
+ break;
+
+ case DHCP_CSR:
+ MIN_LENGTH (5);
+ free_route (csr);
+ csr = decode_CSR (p, length);
+ break;
+
+ case DHCP_MSCSR:
+ MIN_LENGTH (5);
+ free_route (mscsr);
+ mscsr = decode_CSR (p, length);
+ break;
+
+#ifdef ENABLE_INFO
+ case DHCP_SIPSERVER:
+ free (dhcp->sipservers);
+ dhcp->sipservers = decode_sipservers (p,length);
+ break;
+#endif
+
+ case DHCP_STATICROUTE:
+ MULT_LENGTH (8);
+ free_route (routes);
+ routes = decode_routes (p, length);
+ break;
+
+ case DHCP_ROUTERS:
+ MULT_LENGTH (4);
+ free_route (routers);
+ routers = decode_routers (p, length);
+ break;
+
+ case DHCP_OPTIONSOVERLOADED:
+ LENGTH (1);
+ /* The overloaded option in an overloaded option
+ * should be ignored, overwise we may get an
+ * infinite loop */
+ if (! in_overload) {
+ if (*p & 1)
+ parse_file = true;
+ if (*p & 2)
+ parse_sname = true;
+ }
+ break;
+
+ case DHCP_FQDN:
+ /* We ignore replies about FQDN */
+ break;
+
+#undef LENGTH
+#undef MIN_LENGTH
+#undef MULT_LENGTH
+
+ default:
+ logger (LOG_DEBUG,
+ "no facility to parse DHCP code %u",
+ option);
+ break;
+ }
+
+ p += length;
+ }
+
+eexit:
+ /* We may have options overloaded, so go back and grab them */
+ if (parse_file) {
+ parse_file = false;
+ p = message->bootfile;
+ end = p + sizeof (message->bootfile);
+ in_overload = true;
+ goto parse_start;
+ } else if (parse_sname) {
+ parse_sname = false;
+ p = message->servername;
+ end = p + sizeof (message->servername);
+ memset (dhcp->servername, 0, sizeof (dhcp->servername));
+ in_overload = true;
+ goto parse_start;
+ }
+
+ /* Fill in any missing fields */
+ if (! dhcp->netmask.s_addr)
+ dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr);
+ if (! dhcp->broadcast.s_addr)
+ dhcp->broadcast.s_addr = dhcp->address.s_addr |
+ ~dhcp->netmask.s_addr;
+
+ /* If we have classess static routes then we discard
+ * static routes and routers according to RFC 3442 */
+ if (csr) {
+ dhcp->routes = csr;
+ free_route (mscsr);
+ free_route (routers);
+ free_route (routes);
+ } else if (mscsr) {
+ dhcp->routes = mscsr;
+ free_route (routers);
+ free_route (routes);
+ } else {
+ /* Ensure that we apply static routes before routers */
+ if (! routes)
+ routes = routers;
+ else if (routers)
+ STAILQ_CONCAT (routes, routers);
+ dhcp->routes = routes;
+ }
+
+ return (retval);
+}
diff --git a/src/customdhcpcd/dhcp.h b/src/customdhcpcd/dhcp.h
new file mode 100644
index 0000000..ef97b75
--- /dev/null
+++ b/src/customdhcpcd/dhcp.h
@@ -0,0 +1,215 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <stdint.h>
+
+#include "dhcpcd.h"
+#include "interface.h"
+
+/* Max MTU - defines dhcp option length */
+#define MTU_MAX 1500
+#define MTU_MIN 576
+
+/* UDP port numbers for DHCP */
+#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT 68
+
+#define MAGIC_COOKIE 0x63825363
+#define BROADCAST_FLAG 0x8000
+
+/* DHCP message OP code */
+#define DHCP_BOOTREQUEST 1
+#define DHCP_BOOTREPLY 2
+
+/* DHCP message type */
+#define DHCP_DISCOVER 1
+#define DHCP_OFFER 2
+#define DHCP_REQUEST 3
+#define DHCP_DECLINE 4
+#define DHCP_ACK 5
+#define DHCP_NAK 6
+#define DHCP_RELEASE 7
+#define DHCP_INFORM 8
+
+/* DHCP options */
+enum DHCP_OPTIONS
+{
+ DHCP_PAD = 0,
+ DHCP_NETMASK = 1,
+ DHCP_TIMEROFFSET = 2,
+ DHCP_ROUTERS = 3,
+ DHCP_TIMESERVER = 4,
+ DHCP_NAMESERVER = 5,
+ DHCP_DNSSERVER = 6,
+ DHCP_LOGSERVER = 7,
+ DHCP_COOKIESERVER = 8,
+ DHCP_HOSTNAME = 12,
+ DHCP_DNSDOMAIN = 15,
+ DHCP_ROOTPATH = 17,
+ DHCP_DEFAULTIPTTL = 23,
+ DHCP_MTU = 26,
+ DHCP_BROADCAST = 28,
+ DHCP_MASKDISCOVERY = 29,
+ DHCP_ROUTERDISCOVERY = 31,
+ DHCP_STATICROUTE = 33,
+ DHCP_NISDOMAIN = 40,
+ DHCP_NISSERVER = 41,
+ DHCP_NTPSERVER = 42,
+ DHCP_ADDRESS = 50,
+ DHCP_LEASETIME = 51,
+ DHCP_OPTIONSOVERLOADED = 52,
+ DHCP_MESSAGETYPE = 53,
+ DHCP_SERVERIDENTIFIER = 54,
+ DHCP_PARAMETERREQUESTLIST = 55,
+ DHCP_MESSAGE = 56,
+ DHCP_MAXMESSAGESIZE = 57,
+ DHCP_RENEWALTIME = 58,
+ DHCP_REBINDTIME = 59,
+ DHCP_CLASSID = 60,
+ DHCP_CLIENTID = 61,
+ DHCP_USERCLASS = 77, /* RFC 3004 */
+ DHCP_FQDN = 81,
+ DHCP_DNSSEARCH = 119, /* RFC 3397 */
+ DHCP_SIPSERVER = 120, /* RFC 3361 */
+ DHCP_CSR = 121, /* RFC 3442 */
+ DHCP_MSCSR = 249, /* MS code for RFC 3442 */
+ DHCP_END = 255
+};
+
+/* SetFQDNHostName values - lsnybble used in flags
+ * byte (see buildmsg.c), hsnybble to create order
+ * and to allow 0x00 to mean disable
+ */
+enum FQQN {
+ FQDN_DISABLE = 0x00,
+ FQDN_NONE = 0x18,
+ FQDN_PTR = 0x20,
+ FQDN_BOTH = 0x31
+};
+
+typedef struct fqdn_t
+{
+ uint8_t flags;
+ uint8_t r1;
+ uint8_t r2;
+ char *name;
+} fqdn_t;
+
+typedef struct dhcp_t
+{
+ char version[11];
+
+ struct in_addr serveraddress;
+ char serverhw[IF_NAMESIZE];
+ char servername[64];
+
+ struct in_addr address;
+ struct in_addr netmask;
+ struct in_addr broadcast;
+ unsigned short mtu;
+
+ uint32_t leasedfrom;
+ uint32_t leasetime;
+ uint32_t renewaltime;
+ uint32_t rebindtime;
+
+ struct route_head *routes;
+
+ char *hostname;
+ fqdn_t *fqdn;
+
+ struct address_head *dnsservers;
+ char *dnsdomain;
+ char *dnssearch;
+
+ struct address_head *ntpservers;
+
+ struct address_head *nisservers;
+ char *nisdomain;
+
+ char *sipservers;
+
+ char *message;
+ char *rootpath;
+
+ bool frominfo;
+} dhcp_t;
+
+/* Sizes for DHCP options */
+#define DHCP_CHADDR_LEN 16
+#define SERVERNAME_LEN 64
+#define BOOTFILE_LEN 128
+#define DHCP_UDP_LEN (20 + 8)
+#define DHCP_BASE_LEN (4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4)
+#define DHCP_RESERVE_LEN (4 + 4 + 4 + 4 + 2)
+#define DHCP_FIXED_LEN (DHCP_BASE_LEN + DHCP_CHADDR_LEN + \
+ + SERVERNAME_LEN + BOOTFILE_LEN)
+#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \
+ - DHCP_RESERVE_LEN)
+
+/* Some crappy DHCP servers require the BOOTP minimum length */
+#define BOOTP_MESSAGE_LENTH_MIN 300
+
+typedef struct dhcpmessage_t
+{
+ unsigned char op; /* message type */
+ unsigned char hwtype; /* hardware address type */
+ unsigned char hwlen; /* hardware address length */
+ unsigned char hwopcount; /* should be zero in client message */
+ uint32_t xid; /* transaction id */
+ uint16_t secs; /* elapsed time in sec. from boot */
+ uint16_t flags;
+ uint32_t ciaddr; /* (previously allocated) client IP */
+ uint32_t yiaddr; /* 'your' client IP address */
+ uint32_t siaddr; /* should be zero in client's messages */
+ uint32_t giaddr; /* should be zero in client's messages */
+ unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */
+ unsigned char servername[SERVERNAME_LEN]; /* server host name */
+ unsigned char bootfile[BOOTFILE_LEN]; /* boot file name */
+ uint32_t cookie;
+ unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */
+} dhcpmessage_t;
+
+struct udp_dhcp_packet
+{
+ struct ip ip;
+ struct udphdr udp;
+ dhcpmessage_t dhcp;
+};
+
+ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp,
+ uint32_t xid, char type, const options_t *options);
+void free_dhcp (dhcp_t *dhcp);
+int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message);
+#endif
diff --git a/src/customdhcpcd/dhcpcd.c b/src/customdhcpcd/dhcpcd.c
new file mode 100644
index 0000000..d0ad5e7
--- /dev/null
+++ b/src/customdhcpcd/dhcpcd.c
@@ -0,0 +1,671 @@
+ /* dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
+
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "client.h"
+#include "dhcpcd.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+#include "socket.h"
+#include "version.h"
+
+#include "logwriter.h"
+
+static int doversion = 0;
+static int dohelp = 0;
+#define EXTRA_OPTS
+static const struct option longopts[] = {
+ {"arp", no_argument, NULL, 'a'},
+ {"script", required_argument, NULL, 'c'},
+ {"debug", no_argument, NULL, 'd'},
+ {"hostname", optional_argument, NULL, 'h'},
+ {"classid", optional_argument, NULL, 'i'},
+ {"release", no_argument, NULL, 'k'},
+ {"leasetime", required_argument, NULL, 'l'},
+ {"metric", required_argument, NULL, 'm'},
+ {"renew", no_argument, NULL, 'n'},
+ {"persistent", no_argument, NULL, 'p'},
+ {"qtsocketaddress", required_argument, NULL, 'q'},
+ {"inform", optional_argument, NULL, 's'},
+ {"request", optional_argument, NULL, 'r'},
+ {"timeout", required_argument, NULL, 't'},
+ {"userclass", required_argument, NULL, 'u'},
+ {"exit", no_argument, NULL, 'x'},
+ {"lastlease", no_argument, NULL, 'E'},
+ {"fqdn", required_argument, NULL, 'F'},
+ {"nogateway", no_argument, NULL, 'G'},
+ {"sethostname", no_argument, NULL, 'H'},
+ {"clientid", optional_argument, NULL, 'I'},
+ {"noipv4ll", no_argument, NULL, 'L'},
+ {"nomtu", no_argument, NULL, 'M'},
+ {"nontp", no_argument, NULL, 'N'},
+ {"nodns", no_argument, NULL, 'R'},
+ {"msscr", no_argument, NULL, 'S'},
+ {"test", no_argument, NULL, 'T'},
+ {"nonis", no_argument, NULL, 'Y'},
+ {"help", no_argument, &dohelp, 1},
+ {"version", no_argument, &doversion, 1},
+#ifdef THERE_IS_NO_FORK
+ {"daemonised", no_argument, NULL, 'f'},
+ {"skiproutes", required_argument, NULL, 'g'},
+#endif
+ {NULL, 0, NULL, 0}
+};
+
+#ifdef THERE_IS_NO_FORK
+char dhcpcd[PATH_MAX];
+char **dhcpcd_argv = NULL;
+int dhcpcd_argc = 0;
+char *dhcpcd_skiproutes = NULL;
+#undef EXTRA_OPTS
+#define EXTRA_OPTS "fg:"
+#endif
+
+static int atoint (const char *s)
+{
+ char *t;
+ long n;
+
+ errno = 0;
+ n = strtol (s, &t, 0);
+ if ((errno != 0 && n == 0) || s == t ||
+ (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)))
+ {
+ logger (LOG_ERR, "`%s' out of range", s);
+ return (-1);
+ }
+
+ return ((int) n);
+}
+
+static pid_t read_pid (const char *pidfile)
+{
+ FILE *fp;
+ pid_t pid = 0;
+
+ if ((fp = fopen (pidfile, "r")) == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
+
+ fscanf (fp, "%d", &pid);
+ fclose (fp);
+
+
+ return (pid);
+}
+
+static void usage (void)
+{
+ printf ("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n"
+ " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n"
+ " [-t timeout] [-u userclass] [-F none | ptr | both]\n"
+ " [-I clientID] [-q qtsocketaddress] <interface>\n");
+}
+
+
+int main (int argc, char **argv)
+{
+ options_t *options;
+ int userclasses = 0;
+ int opt;
+ int option_index = 0;
+ char *prefix;
+ pid_t pid;
+ int debug = 0;
+ int i;
+ int pidfd = -1;
+ int sig = 0;
+ int retval = EXIT_FAILURE;
+
+ /* Close any un-needed fd's */
+ for (i = getdtablesize() - 1; i >= 3; --i)
+ close (i);
+
+ openlog (PACKAGE, LOG_PID, LOG_LOCAL0);
+
+ options = xzalloc (sizeof (*options));
+ options->script = (char *) DEFAULT_SCRIPT;
+ snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s",
+ PACKAGE, VERSION);
+
+ options->doarp = true;
+ options->dodns = true;
+ options->domtu = true;
+ options->donis = true;
+ options->dontp = true;
+ options->dogateway = true;
+ options->daemonise = true;
+ options->doinform = false;
+ options->doipv4ll = true;
+ options->doduid = true;
+ options->timeout = DEFAULT_TIMEOUT;
+ /* added by Niklas Goby, additional field, storing the socket address path for
+ * communicating with Qt "server"
+ * defined in dhcpcd.h */
+ strcpy(options->qtsocketaddress, DEFAULT_QTSOCKETADDRESS);
+
+ gethostname (options->hostname, sizeof (options->hostname));
+ if (strcmp (options->hostname, "(none)") == 0 ||
+ strcmp (options->hostname, "localhost") == 0)
+ memset (options->hostname, 0, sizeof (options->hostname));
+
+
+ /* Don't set any optional arguments here so we retain POSIX
+ * compatibility with getopt */
+ while ((opt = getopt_long(argc, argv, EXTRA_OPTS
+ "c:dh:i:kl:m:npq:r:s:t:u:xAEF:GHI:LMNRSTY",
+ longopts, &option_index)) != -1)
+ {
+ switch (opt) {
+ case 0:
+ if (longopts[option_index].flag)
+ break;
+ logger (LOG_ERR,
+ "option `%s' should set a flag",
+ longopts[option_index].name);
+ goto abort;
+ case 'c':
+ options->script = optarg;
+ break;
+ case 'd':
+ debug++;
+ switch (debug) {
+ case 1:
+ setloglevel (LOG_DEBUG);
+ break;
+ case 2:
+ options->daemonise = false;
+ break;
+ }
+ break;
+ #ifdef THERE_IS_NO_FORK
+ case 'f':
+ options->daemonised = true;
+ close_fds ();
+ break;
+ case 'g':
+ dhcpcd_skiproutes = xstrdup (optarg);
+ break;
+ #endif
+ case 'h':
+ if (! optarg)
+ *options->hostname = '\0';
+ else if (strlen (optarg) > MAXHOSTNAMELEN) {
+ logger (LOG_ERR,
+ "`%s' too long for HostName string, max is %d",
+ optarg, MAXHOSTNAMELEN);
+ goto abort;
+ } else
+ strlcpy (options->hostname, optarg,
+ sizeof (options->hostname));
+ break;
+ case 'i':
+ if (! optarg) {
+ *options->classid = '\0';
+ } else if (strlen (optarg) > CLASS_ID_MAX_LEN) {
+ logger (LOG_ERR,
+ "`%s' too long for ClassID string, max is %d",
+ optarg, CLASS_ID_MAX_LEN);
+ goto abort;
+ } else
+ strlcpy (options->classid, optarg,
+ sizeof (options->classid));
+ break;
+ case 'k':
+ sig = SIGHUP;
+ break;
+ case 'l':
+ if (*optarg == '-') {
+ logger (LOG_ERR,
+ "leasetime must be a positive value");
+ goto abort;
+ }
+ errno = 0;
+ options->leasetime = (uint32_t) strtol (optarg, NULL, 0);
+ if (errno == EINVAL || errno == ERANGE) {
+ logger (LOG_ERR, "`%s' out of range", optarg);
+ goto abort;
+ }
+ break;
+ case 'm':
+ options->metric = atoint (optarg);
+ if (options->metric < 0) {
+ logger (LOG_ERR,
+ "metric must be a positive value");
+ goto abort;
+ }
+ break;
+ case 'n':
+ sig = SIGALRM;
+ break;
+ case 'p':
+ options->persistent = true;
+ break;
+ case 'q':
+ if (strlen(optarg) > QTSOCKETADDRESSLENGTH) {
+ logger(LOG_ERR, "`%s' too long for an socket address path (max=%d)",
+ optarg, QTSOCKETADDRESSLENGTH);
+ goto abort;
+ }
+ strlcpy(options->qtsocketaddress, optarg, sizeof(options->qtsocketaddress));
+ break;
+ case 's':
+ options->doinform = true;
+ options->doarp = false;
+ if (! optarg || strlen (optarg) == 0) {
+ options->request_address.s_addr = 0;
+ break;
+ } else {
+ char *slash = strchr (optarg, '/');
+ if (slash) {
+ int cidr;
+ /* nullify the slash, so the -r option can read the
+ * address */
+ *slash++ = '\0';
+ if (sscanf (slash, "%d", &cidr) != 1 ||
+ inet_cidrtoaddr (cidr, &options->request_netmask) != 0) {
+ logger (LOG_ERR, "`%s' is not a valid CIDR", slash);
+ goto abort;
+ }
+ }
+ }
+ /* FALLTHROUGH */
+ case 'r':
+ if (! options->doinform)
+ options->dorequest = true;
+ if (strlen (optarg) > 0 &&
+ ! inet_aton (optarg, &options->request_address))
+ {
+ logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
+ goto abort;
+ }
+ break;
+ case 't':
+ options->timeout = atoint (optarg);
+ if (options->timeout < 0) {
+ logger (LOG_ERR, "timeout must be a positive value");
+ goto abort;
+ }
+ break;
+ case 'u':
+ {
+ int offset = 0;
+ for (i = 0; i < userclasses; i++)
+ offset += (int) options->userclass[offset] + 1;
+ if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
+ logger (LOG_ERR, "userclass overrun, max is %d",
+ USERCLASS_MAX_LEN);
+ goto abort;
+ }
+ userclasses++;
+ memcpy (options->userclass + offset + 1 , optarg, strlen (optarg));
+ options->userclass[offset] = strlen (optarg);
+ options->userclass_len += (strlen (optarg)) + 1;
+ }
+ break;
+ case 'x':
+ sig = SIGTERM;
+ break;
+ case 'A':
+ #ifndef ENABLE_ARP
+ logger (LOG_ERR,
+ "arp not compiled into dhcpcd");
+ goto abort;
+ #endif
+ options->doarp = false;
+ break;
+ case 'E':
+ #ifndef ENABLE_INFO
+ logger (LOG_ERR,
+ "info not compiled into dhcpcd");
+ goto abort;
+ #endif
+ options->dolastlease = true;
+ break;
+ case 'F':
+ if (strncmp (optarg, "none", strlen (optarg)) == 0)
+ options->fqdn = FQDN_NONE;
+ else if (strncmp (optarg, "ptr", strlen (optarg)) == 0)
+ options->fqdn = FQDN_PTR;
+ else if (strncmp (optarg, "both", strlen (optarg)) == 0)
+ options->fqdn = FQDN_BOTH;
+ else {
+ logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
+ goto abort;
+ }
+ break;
+ case 'G':
+ options->dogateway = false;
+ break;
+ case 'H':
+ options->dohostname++;
+ break;
+ case 'I':
+ if (optarg) {
+ if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
+ logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
+ optarg, CLIENT_ID_MAX_LEN);
+ goto abort;
+ }
+ if (strlcpy (options->clientid, optarg,
+ sizeof (options->clientid)) == 0)
+ /* empty string disabled duid */
+ options->doduid = false;
+
+ } else {
+ memset (options->clientid, 0, sizeof (options->clientid));
+ options->doduid = false;
+ }
+ break;
+ case 'L':
+ options->doipv4ll = false;
+ break;
+ case 'M':
+ options->domtu = false;
+ break;
+ case 'N':
+ options->dontp = false;
+ break;
+ case 'R':
+ options->dodns = false;
+ break;
+ case 'S':
+ options->domscsr++;
+ break;
+ case 'T':
+ #ifndef ENABLE_INFO
+ logger (LOG_ERR, "info support not compiled into dhcpcd");
+ goto abort;
+ #endif
+ options->test = true;
+ options->persistent = true;
+ break;
+ case 'Y':
+ options->donis = false;
+ break;
+ case '?':
+ usage ();
+ goto abort;
+ default:
+ usage ();
+ goto abort;
+ }
+ }
+ if (doversion) {
+ printf (""PACKAGE" "VERSION"\n");
+ printf ("Compile time options:"
+ #ifdef ENABLE_ARP
+ " ARP"
+ #endif
+ #ifdef ENABLE_DUID
+ " DUID"
+ #endif
+ #ifdef ENABLE_INFO
+ " INFO"
+ #endif
+ #ifdef ENABLE_INFO_COMPAT
+ " INFO_COMPAT"
+ #endif
+ #ifdef ENABLE_IPV4LL
+ " IPV4LL"
+ #endif
+ #ifdef ENABLE_NIS
+ " NIS"
+ #endif
+ #ifdef ENABLE_NTP
+ " NTP"
+ #endif
+ #ifdef SERVICE
+ " " SERVICE
+ #endif
+ #ifdef ENABLE_RESOLVCONF
+ " RESOLVCONF"
+ #endif
+ #ifdef THERE_IS_NO_FORK
+ " THERE_IS_NO_FORK"
+ #endif
+ "\n");
+ }
+
+ if (dohelp)
+ usage ();
+
+
+#ifdef THERE_IS_NO_FORK
+ dhcpcd_argv = argv;
+ dhcpcd_argc = argc;
+ if (! realpath (argv[0], dhcpcd)) {
+ logger (LOG_ERR, "unable to resolve the path `%s': %s",
+ argv[0], strerror (errno));
+ goto abort;
+ }
+#endif
+
+ /* initializations for the ipc connection to qt*/
+ setSocketName(options->qtsocketaddress);
+ if (initQtLoggerSocket() < 0) {
+ logger(LOG_ERR, "initialization Qt Logger failed: %s ", strerror (errno));
+ goto abort;
+ }
+
+
+ if (optind < argc) {
+ if (strlen(argv[optind]) > IF_NAMESIZE) {
+ logger(LOG_ERR, "`%s' too long for an interface name (max=%d)",
+ argv[optind], IF_NAMESIZE);
+ goto abort;
+ }
+ strlcpy(options->interface, argv[optind], sizeof(options->interface));
+ setInterfaceName(options->interface);
+ } else {
+ /* If only version was requested then exit now */
+ if (doversion || dohelp) {
+ retval = 0;
+ goto abort;
+ }
+
+ logger(LOG_ERR, "no interface specified");
+ setInterfaceName("no_if");
+ goto abort;
+ }
+
+ if (strchr(options->hostname, '.')) {
+ if (options->fqdn == FQDN_DISABLE)
+ options->fqdn = FQDN_BOTH;
+ } else
+ options->fqdn = FQDN_DISABLE;
+
+ if (options->request_address.s_addr == 0 && options->doinform) {
+ if ((options->request_address.s_addr = get_address(options->interface))
+ != 0)
+ options->keep_address = true;
+ }
+
+ if (IN_LINKLOCAL (ntohl (options->request_address.s_addr))) {
+ logger (LOG_ERR,
+ "you are not allowed to request a link local address");
+ logToQt(LOG_ERR, -1, "you are not allowed to request a link local address");
+ goto abort;
+ }
+
+ if (geteuid ()) {
+ logger (LOG_WARNING, PACKAGE " will not work correctly unless"
+ " run as root");
+ }
+
+ prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3));
+ snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface);
+ setlogprefix (prefix);
+ snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE,
+ options->interface);
+ free (prefix);
+
+ chdir ("/");
+ umask (022);
+
+ if (mkdir (INFODIR, S_IRUSR | S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
+ | S_IROTH | S_IXOTH) && errno != EEXIST)
+ {
+ logger (LOG_ERR,
+ "mkdir(\"%s\",0): %s\n", INFODIR, strerror (errno));
+ goto abort;
+ }
+
+ if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
+ | S_IROTH | S_IXOTH) && errno != EEXIST)
+ {
+ logger (LOG_ERR,
+ "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
+ goto abort;
+ }
+
+ if (options->test) {
+ if (options->dorequest || options->doinform) {
+ logger (LOG_ERR,
+ "cannot test with --inform or --request");
+ goto abort;
+ }
+
+ if (options->dolastlease) {
+ logger (LOG_ERR, "cannot test with --lastlease");
+ goto abort;
+ }
+
+ if (sig != 0) {
+ logger (LOG_ERR,
+ "cannot test with --release or --renew");
+ goto abort;
+ }
+ }
+
+ if (sig != 0) {
+ int killed = -1;
+ pid = read_pid (options->pidfile);
+ if (pid != 0)
+ logger (LOG_INFO, "sending signal %d to pid %d",
+ sig, pid);
+
+ if (! pid || (killed = kill (pid, sig)))
+ logger (sig == SIGALRM ? LOG_INFO : LOG_ERR,
+ ""PACKAGE" not running");
+
+ if (pid != 0 && (sig != SIGALRM || killed != 0))
+ unlink (options->pidfile);
+
+ if (killed == 0) {
+ retval = EXIT_SUCCESS;
+ goto abort;
+ }
+
+ if (sig != SIGALRM)
+ goto abort;
+ }
+
+ if (! options->test && ! options->daemonised) {
+ if ((pid = read_pid (options->pidfile)) > 0 &&
+ kill (pid, 0) == 0)
+ {
+ logger (LOG_ERR, ""PACKAGE
+ " already running on pid %d (%s)",
+ pid, options->pidfile);
+ goto abort;
+ }
+
+ pidfd = open (options->pidfile,
+ O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
+ if (pidfd == -1) {
+ logger (LOG_ERR, "open `%s': %s",
+ options->pidfile, strerror (errno));
+ goto abort;
+ }
+
+ /* Lock the file so that only one instance of dhcpcd runs
+ * on an interface */
+ if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) {
+ logger (LOG_ERR, "flock `%s': %s",
+ options->pidfile, strerror (errno));
+ goto abort;
+ }
+
+ /* dhcpcd.sh should not interhit this fd */
+ if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 ||
+ fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1)
+ logger (LOG_ERR, "fcntl: %s", strerror (errno));
+
+ writepid (pidfd, getpid ());
+ logger (LOG_INFO, PACKAGE " " VERSION " starting");
+ }
+
+ /* Seed random */
+ srandomdev ();
+
+ /* Massage our filters per platform */
+ setup_packet_filters ();
+
+ /* dhcp_run : defined in client.c */
+ if (dhcp_run (options, &pidfd) == 0)
+ retval = EXIT_SUCCESS;
+
+abort:
+ /* If we didn't daemonise then we need to punt the pidfile now */
+ if (pidfd > -1) {
+ close (pidfd);
+ unlink (options->pidfile);
+ }
+
+ free (options);
+
+#ifdef THERE_IS_NO_FORK
+ /* There may have been an error before the dhcp_run function
+ * clears this, so just do it here to be safe */
+ free (dhcpcd_skiproutes);
+#endif
+
+ logger (LOG_INFO, "exiting");
+ logToQt(LOG_INFO, DHCPCD_EXIT, "exiting due abort");
+ closeQtLoggerSocket();
+ exit (retval);
+ /* NOTREACHED */
+}
diff --git a/src/customdhcpcd/dhcpcd.h b/src/customdhcpcd/dhcpcd.h
new file mode 100644
index 0000000..c8df616
--- /dev/null
+++ b/src/customdhcpcd/dhcpcd.h
@@ -0,0 +1,108 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCPCD_H
+#define DHCPCD_H
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <limits.h>
+#include <stdbool.h>
+
+#include "common.h"
+
+#include "../../common/fbgui.h"
+
+#define DEFAULT_TIMEOUT 20
+#define DEFAULT_LEASETIME 3600 /* 1 hour */
+
+/* added by Niklas Goby, additional field, storing the socket address path for
+ * communicating with Qt "server" */
+
+
+#define QTSOCKETADDRESSLENGTH 255
+
+#define CLASS_ID_MAX_LEN 48
+#define CLIENT_ID_MAX_LEN 48
+#define USERCLASS_MAX_LEN 255
+
+#ifdef THERE_IS_NO_FORK
+extern char dhcpcd[PATH_MAX];
+extern char **dhcpcd_argv;
+extern int dhcpcd_argc;
+extern char *dhcpcd_skiproutes;
+#endif
+
+typedef struct options_t {
+ /* added by Niklas Goby, additional field, storing the socket address path for
+ * communicating with Qt "server" */
+ char qtsocketaddress[QTSOCKETADDRESSLENGTH];
+ /*----*/
+ char interface[IF_NAMESIZE];
+ char hostname[MAXHOSTNAMELEN];
+ int fqdn;
+ char classid[CLASS_ID_MAX_LEN];
+ char clientid[CLIENT_ID_MAX_LEN];
+ char userclass[USERCLASS_MAX_LEN];
+ size_t userclass_len;
+ uint32_t leasetime;
+ time_t timeout;
+ int metric;
+
+ bool doarp;
+ bool dodns;
+ bool dodomainname;
+ bool dogateway;
+ int dohostname;
+ bool domtu;
+ bool donis;
+ bool dontp;
+ bool dolastlease;
+ bool doinform;
+ bool dorequest;
+ bool doipv4ll;
+ bool doduid;
+ int domscsr;
+
+ struct in_addr request_address;
+ struct in_addr request_netmask;
+
+ bool persistent;
+ bool keep_address;
+ bool daemonise;
+ bool daemonised;
+ bool test;
+
+ char *script;
+ char pidfile[PATH_MAX];
+} options_t;
+
+int nd_main (char *ifname);
+
+#endif
diff --git a/src/customdhcpcd/dhcpcd.sh b/src/customdhcpcd/dhcpcd.sh
new file mode 100644
index 0000000..8c86aac
--- /dev/null
+++ b/src/customdhcpcd/dhcpcd.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# This is a sample /etc/dhcpcd.sh script.
+# /etc/dhcpcd.sh script is executed by dhcpcd daemon
+# any time it configures or shuts down interface.
+# The following parameters are passed to dhcpcd.exe script:
+# $1 = HostInfoFilePath, e.g "/var/lib/dhcpcd/dhcpcd-eth0.info"
+# $2 = "up" if interface has been configured with the same
+# IP address as before reboot;
+# $2 = "down" if interface has been shut down;
+# $2 = "new" if interface has been configured with new IP address;
+#
+# Sanity checks
+
+if [ $# -lt 2 ]; then
+ logger -s -p local0.err -t dhcpcd.sh "wrong usage"
+ exit 1
+fi
+
+hostinfo="$1"
+state="$2"
+
+# Reading HostInfo file for configuration parameters
+[ -e "${hostinfo}" ] && . "${hostinfo}"
+
+case "${state}" in
+ up)
+ logger -s -p local0.info -t dhcpcd.sh \
+ "interface ${INTERFACE} has been configured with old IP=${IPADDR}"
+ # Put your code here for when the interface has been brought up with an
+ # old IP address here
+ ;;
+
+ new)
+ logger -s -p local0.info -t dhcpcd.sh \
+ "interface ${INTERFACE} has been configured with new IP=${IPADDR}"
+ # Put your code here for when the interface has been brought up with a
+ # new IP address
+ ;;
+
+ down) logger -s -p local0.info -t dhcpcd.sh \
+ "interface ${INTERFACE} has been brought down"
+ # Put your code here for the when the interface has been shut down
+ ;;
+esac
+exit 0
diff --git a/src/customdhcpcd/discover.c b/src/customdhcpcd/discover.c
new file mode 100644
index 0000000..eae7b0a
--- /dev/null
+++ b/src/customdhcpcd/discover.c
@@ -0,0 +1,7 @@
+/*
+ * discover.c
+ *
+ * Created on: Jul 7, 2011
+ * Author: niklas
+ */
+
diff --git a/src/customdhcpcd/discover.h b/src/customdhcpcd/discover.h
new file mode 100644
index 0000000..1f4918d
--- /dev/null
+++ b/src/customdhcpcd/discover.h
@@ -0,0 +1,12 @@
+/*
+ * discover.h
+ *
+ * Created on: Jul 7, 2011
+ * Author: niklas
+ */
+
+#ifndef DISCOVER_H_
+#define DISCOVER_H_
+
+
+#endif /* DISCOVER_H_ */
diff --git a/src/customdhcpcd/duid.c b/src/customdhcpcd/duid.c
new file mode 100644
index 0000000..e4dd83b
--- /dev/null
+++ b/src/customdhcpcd/duid.c
@@ -0,0 +1,118 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "config.h"
+#include "common.h"
+#include "duid.h"
+#include "logger.h"
+
+#ifdef ENABLE_DUID
+
+#define THIRTY_YEARS_IN_SECONDS 946707779
+
+size_t get_duid (unsigned char *duid, const interface_t *iface)
+{
+ FILE *f;
+ uint16_t type = 0;
+ uint16_t hw = 0;
+ uint32_t ul;
+ time_t t;
+ int x = 0;
+ unsigned char *p = duid;
+ size_t len = 0;
+
+ if (! iface)
+ return (0);
+
+ /* If we already have a DUID then use it as it's never supposed
+ * to change once we have one even if the interfaces do */
+ if ((f = fopen (DUIDFILE, "r"))) {
+ char *line = get_line (f);
+ if (line) {
+ len = hwaddr_aton (NULL, line);
+ if (len && len <= DUID_LEN)
+ hwaddr_aton (duid, line);
+ free (line);
+ }
+ fclose (f);
+ if (len)
+ return (len);
+ } else {
+ if (errno != ENOENT) {
+ logger (LOG_ERR, "fopen `%s': %s",
+ DUIDFILE, strerror (errno));
+ return (0);
+ }
+ }
+
+ /* No file? OK, lets make one based on our interface */
+ type = htons (1); /* DUI-D-LLT */
+ memcpy (p, &type, 2);
+ p += 2;
+
+ hw = htons (iface->family);
+ memcpy (p, &hw, 2);
+ p += 2;
+
+ /* time returns seconds from jan 1 1970, but DUID-LLT is
+ * seconds from jan 1 2000 modulo 2^32 */
+ t = time (NULL) - THIRTY_YEARS_IN_SECONDS;
+ ul = htonl (t & 0xffffffff);
+ memcpy (p, &ul, 4);
+ p += 4;
+
+ /* Finally, add the MAC address of the interface */
+ memcpy (p, iface->hwaddr, iface->hwlen);
+ p += iface->hwlen;
+
+ len = p - duid;
+
+ if (! (f = fopen (DUIDFILE, "w")))
+ logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno));
+ else {
+ x = fprintf (f, "%s\n", hwaddr_ntoa (duid, len));
+ fclose (f);
+ }
+
+ /* Failed to write the duid? scrub it, we cannot use it */
+ if (x < 1) {
+ len = 0;
+ unlink (DUIDFILE);
+ }
+
+ return (len);
+}
+#endif
diff --git a/src/customdhcpcd/duid.h b/src/customdhcpcd/duid.h
new file mode 100644
index 0000000..1492990
--- /dev/null
+++ b/src/customdhcpcd/duid.h
@@ -0,0 +1,42 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DUID_H
+#define DUID_H
+
+#include "config.h"
+
+#ifdef ENABLE_DUID
+#ifndef DUID_LEN
+# define DUID_LEN 128 + 2
+#endif
+
+#include "interface.h"
+
+size_t get_duid (unsigned char *duid, const interface_t *iface);
+#endif
+#endif
diff --git a/src/customdhcpcd/info.c b/src/customdhcpcd/info.c
new file mode 100644
index 0000000..8369b43
--- /dev/null
+++ b/src/customdhcpcd/info.c
@@ -0,0 +1,472 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+#include "info.h"
+
+#ifdef ENABLE_INFO
+
+/* Create a malloced string of cstr, changing ' to '\''
+ * so the contents work in a shell */
+static char *cleanmetas (const char *cstr)
+{
+ const char *p = cstr;
+ char *new;
+ char *n;
+ size_t len;
+
+ if (cstr == NULL || (len = strlen (cstr)) == 0)
+ return (xstrdup (""));
+
+ n = new = xmalloc (sizeof (char) * len + 2);
+ do
+ if (*p == '\'') {
+ size_t pos = n - new;
+ len += 4;
+ new = xrealloc (new, sizeof (char) * len + 1);
+ n = new + pos;
+ *n++ = '\'';
+ *n++ = '\\';
+ *n++ = '\'';
+ *n++ = '\'';
+ } else
+ *n++ = *p;
+ while (*p++);
+
+ /* Terminate the sucker */
+ *n = '\0';
+
+ return (new);
+}
+
+
+static void print_addresses (FILE *f, const struct address_head *addresses)
+{
+ const address_t *addr;
+
+ STAILQ_FOREACH (addr, addresses, entries) {
+ fprintf (f, "%s", inet_ntoa (addr->address));
+ if (STAILQ_NEXT (addr, entries))
+ fprintf (f, " ");
+ }
+}
+
+static void print_clean (FILE *f, const char *name, const char *value)
+{
+ char *clean;
+
+ if (! value)
+ return;
+
+ clean = cleanmetas (value);
+ fprintf (f, "%s='%s'\n", name, clean);
+ free (clean);
+}
+
+bool write_info(const interface_t *iface, const dhcp_t *dhcp,
+ const options_t *options, bool overwrite)
+{
+ FILE *f;
+ route_t *route;
+ struct stat sb;
+
+ if (options->test)
+ f = stdout;
+ else {
+ if (! overwrite && stat (iface->infofile, &sb) == 0)
+ return (true);
+
+ logger (LOG_DEBUG, "writing %s", iface->infofile);
+ if ((f = fopen (iface->infofile, "w")) == NULL) {
+ logger (LOG_ERR, "fopen `%s': %s",
+ iface->infofile, strerror (errno));
+ return (false);
+ }
+ }
+
+ if (dhcp->address.s_addr) {
+ struct in_addr n;
+ n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
+ fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address));
+ fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask));
+ fprintf (f, "NETWORK='%s'\n", inet_ntoa (n));
+ fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast));
+ }
+ if (dhcp->mtu > 0)
+ fprintf (f, "MTU='%d'\n", dhcp->mtu);
+
+ if (dhcp->routes) {
+ bool doneone = false;
+ fprintf (f, "ROUTES='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr != 0) {
+ if (doneone)
+ fprintf (f, " ");
+ fprintf (f, "%s", inet_ntoa (route->destination));
+ fprintf (f, ",%s", inet_ntoa (route->netmask));
+ fprintf (f, ",%s", inet_ntoa (route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf (f, "'\n");
+
+ doneone = false;
+ fprintf (f, "GATEWAYS='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr == 0) {
+ if (doneone)
+ fprintf (f, " ");
+ fprintf (f, "%s", inet_ntoa (route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf (f, "'\n");
+ }
+
+ print_clean (f, "HOSTNAME", dhcp->hostname);
+ print_clean (f, "DNSDOMAIN", dhcp->dnsdomain);
+ print_clean (f, "DNSSEARCH", dhcp->dnssearch);
+
+ if (dhcp->dnsservers) {
+ fprintf (f, "DNSSERVERS='");
+ print_addresses (f, dhcp->dnsservers);
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->fqdn) {
+ fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags);
+ fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1);
+ fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2);
+ print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name);
+ }
+
+ if (dhcp->ntpservers) {
+ fprintf (f, "NTPSERVERS='");
+ print_addresses (f, dhcp->ntpservers);
+ fprintf (f, "'\n");
+ }
+
+ print_clean (f, "NISDOMAIN", dhcp->nisdomain);
+ if (dhcp->nisservers) {
+ fprintf (f, "NISSERVERS='");
+ print_addresses (f, dhcp->nisservers);
+ fprintf (f, "'\n");
+ }
+
+ print_clean (f, "ROOTPATH", dhcp->rootpath);
+ print_clean (f, "SIPSERVERS", dhcp->sipservers);
+
+ if (dhcp->serveraddress.s_addr)
+ fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress));
+ if (dhcp->servername[0])
+ print_clean (f, "DHCPSNAME", dhcp->servername);
+
+ if (! options->doinform && dhcp->address.s_addr) {
+ if (! options->test)
+ fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom);
+ fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime);
+ fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime);
+ fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime);
+ }
+ print_clean (f, "INTERFACE", iface->name);
+ print_clean (f, "CLASSID", options->classid);
+ if (iface->clientid_len > 0) {
+ fprintf (f, "CLIENTID='%s'\n",
+ hwaddr_ntoa (iface->clientid, iface->clientid_len));
+ }
+ fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr,
+ iface->hwlen));
+
+#ifdef ENABLE_INFO_COMPAT
+ /* Support the old .info settings if we need to */
+ fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n");
+ if (dhcp->dnsservers) {
+ address_t *addr;
+
+ fprintf (f, "DNS='");
+ STAILQ_FOREACH (addr, dhcp->dnsservers, entries) {
+ fprintf (f, "%s", inet_ntoa (addr->address));
+ if (STAILQ_NEXT (addr, entries))
+ fprintf (f, ",");
+ }
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->routes) {
+ bool doneone = false;
+ fprintf (f, "GATEWAY='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr == 0) {
+ if (doneone)
+ fprintf (f, ",");
+ fprintf (f, "%s", inet_ntoa (route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf (f, "'\n");
+ }
+#endif
+
+ if (! options->test)
+ fclose (f);
+ return (true);
+}
+
+static bool parse_address (struct in_addr *addr,
+ const char *value, const char *var)
+{
+ if (inet_aton (value, addr) == 0) {
+ logger (LOG_ERR, "%s `%s': %s", var, value,
+ strerror (errno));
+ return (false);
+ }
+ return (true);
+}
+
+static bool parse_uint (unsigned int *i,
+ const char *value, const char *var)
+{
+ if (sscanf (value, "%u", i) != 1) {
+ logger (LOG_ERR, "%s `%s': not a valid number",
+ var, value);
+ return (false);
+ }
+ return (true);
+}
+
+static bool parse_ushort (unsigned short *s,
+ const char *value, const char *var)
+{
+ if (sscanf (value, "%hu", s) != 1) {
+ logger (LOG_ERR, "%s `%s': not a valid number",
+ var, value);
+ return (false);
+ }
+ return (true);
+}
+
+static struct address_head *parse_addresses (char *value, const char *var)
+{
+ char *token;
+ char *p = value;
+ struct address_head *head = NULL;
+
+ while ((token = strsep (&p, " "))) {
+ address_t *a = xzalloc (sizeof (*a));
+
+ if (inet_aton (token, &a->address) == 0) {
+ logger (LOG_ERR, "%s: invalid address `%s'", var, token);
+ free_address (head);
+ free (a);
+ return (NULL);
+ }
+
+ if (! head) {
+ head = xmalloc (sizeof (*head));
+ STAILQ_INIT (head);
+ }
+ STAILQ_INSERT_TAIL (head, a, entries);
+ }
+
+ return (head);
+}
+
+bool read_info (const interface_t *iface, dhcp_t *dhcp)
+{
+ FILE *fp;
+ char *line;
+ char *var;
+ char *value;
+ char *p;
+ struct stat sb;
+
+ if (stat (iface->infofile, &sb) != 0) {
+ logger (LOG_ERR, "lease information file `%s' does not exist",
+ iface->infofile);
+ return (false);
+ }
+
+ if (! (fp = fopen (iface->infofile, "r"))) {
+ logger (LOG_ERR, "fopen `%s': %s",
+ iface->infofile, strerror (errno));
+ return (false);
+ }
+
+ dhcp->frominfo = true;
+
+ while ((line = get_line (fp))) {
+ var = line;
+
+ /* Strip leading spaces/tabs */
+ while ((*var == ' ') || (*var == '\t'))
+ var++;
+
+ /* Trim trailing \n */
+ p = var + strlen (var) - 1;
+ if (*p == '\n')
+ *p = 0;
+
+ /* Skip comments */
+ if (*var == '#')
+ goto next;
+
+ /* If we don't have an equals sign then skip it */
+ if (! (p = strchr (var, '=')))
+ goto next;
+
+ /* Terminate the = so we have two strings */
+ *p = 0;
+
+ value = p + 1;
+ /* Strip leading and trailing quotes if present */
+ if (*value == '\'' || *value == '"')
+ value++;
+ p = value + strlen (value) - 1;
+ if (*p == '\'' || *p == '"')
+ *p = 0;
+
+ /* Don't process null vars or values */
+ if (! *var || ! *value)
+ goto next;
+
+ if (strcmp (var, "IPADDR") == 0)
+ parse_address (&dhcp->address, value, "IPADDR");
+ else if (strcmp (var, "NETMASK") == 0)
+ parse_address (&dhcp->netmask, value, "NETMASK");
+ else if (strcmp (var, "BROADCAST") == 0)
+ parse_address (&dhcp->broadcast, value, "BROADCAST");
+ else if (strcmp (var, "MTU") == 0)
+ parse_ushort (&dhcp->mtu, value, "MTU");
+ else if (strcmp (var, "ROUTES") == 0) {
+ p = value;
+ while ((value = strsep (&p, " "))) {
+ char *pp = value;
+ char *dest = strsep (&pp, ",");
+ char *net = strsep (&pp, ",");
+ char *gate = strsep (&pp, ",");
+ route_t *route;
+
+ if (! dest || ! net || ! gate) {
+ logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route",
+ dest, net, gate);
+ goto next;
+ }
+
+ /* See if we can create a route */
+ route = xzalloc (sizeof (*route));
+ if (inet_aton (dest, &route->destination) == 0) {
+ logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address",
+ dest);
+ free (route);
+ goto next;
+ }
+ if (inet_aton (dest, &route->netmask) == 0) {
+ logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address",
+ net);
+ free (route);
+ goto next;
+ }
+ if (inet_aton (dest, &route->gateway) == 0) {
+ logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address",
+ gate);
+ free (route);
+ goto next;
+ }
+
+ /* OK, now add our route */
+ if (! dhcp->routes) {
+ dhcp->routes = xmalloc (sizeof (*dhcp->routes));
+ STAILQ_INIT (dhcp->routes);
+ }
+ STAILQ_INSERT_TAIL (dhcp->routes, route, entries);
+ }
+ } else if (strcmp (var, "GATEWAYS") == 0) {
+ p = value;
+ while ((value = strsep (&p, " "))) {
+ route_t *route = xzalloc (sizeof (*route));
+ if (parse_address (&route->gateway, value, "GATEWAYS")) {
+ if (! dhcp->routes) {
+ dhcp->routes = xmalloc (sizeof (*dhcp->routes));
+ STAILQ_INIT (dhcp->routes);
+ }
+ STAILQ_INSERT_TAIL (dhcp->routes, route, entries);
+ } else
+ free (route);
+ }
+ } else if (strcmp (var, "HOSTNAME") == 0)
+ dhcp->hostname = xstrdup (value);
+ else if (strcmp (var, "DNSDOMAIN") == 0)
+ dhcp->dnsdomain = xstrdup (value);
+ else if (strcmp (var, "DNSSEARCH") == 0)
+ dhcp->dnssearch = xstrdup (value);
+ else if (strcmp (var, "DNSSERVERS") == 0)
+ dhcp->dnsservers = parse_addresses (value, "DNSSERVERS");
+ else if (strcmp (var, "NTPSERVERS") == 0)
+ dhcp->ntpservers = parse_addresses (value, "NTPSERVERS");
+ else if (strcmp (var, "NISDOMAIN") == 0)
+ dhcp->nisdomain = xstrdup (value);
+ else if (strcmp (var, "NISSERVERS") == 0)
+ dhcp->nisservers = parse_addresses (value, "NISSERVERS");
+ else if (strcmp (var, "ROOTPATH") == 0)
+ dhcp->rootpath = xstrdup (value);
+ else if (strcmp (var, "DHCPSID") == 0)
+ parse_address (&dhcp->serveraddress, value, "DHCPSID");
+ else if (strcmp (var, "DHCPSNAME") == 0)
+ strlcpy (dhcp->servername, value, sizeof (dhcp->servername));
+ else if (strcmp (var, "LEASEDFROM") == 0)
+ parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM");
+ else if (strcmp (var, "LEASETIME") == 0)
+ parse_uint (&dhcp->leasetime, value, "LEASETIME");
+ else if (strcmp (var, "RENEWALTIME") == 0)
+ parse_uint (&dhcp->renewaltime, value, "RENEWALTIME");
+ else if (strcmp (var, "REBINDTIME") == 0)
+ parse_uint (&dhcp->rebindtime, value, "REBINDTIME");
+
+next:
+ free (line);
+ }
+
+ fclose (fp);
+ return (true);
+}
+
+#endif
+
diff --git a/src/customdhcpcd/info.h b/src/customdhcpcd/info.h
new file mode 100644
index 0000000..22966db
--- /dev/null
+++ b/src/customdhcpcd/info.h
@@ -0,0 +1,42 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef INFO_H
+#define INFO_H
+
+#include "dhcpcd.h"
+#include "interface.h"
+#include "dhcp.h"
+
+#ifdef ENABLE_INFO
+bool write_info (const interface_t *iface, const dhcp_t *dhcp,
+ const options_t *options, bool overwrite);
+
+bool read_info (const interface_t *iface, dhcp_t *dhcp);
+#endif
+
+#endif
diff --git a/src/customdhcpcd/interface.c b/src/customdhcpcd/interface.c
new file mode 100644
index 0000000..d2ff8d6
--- /dev/null
+++ b/src/customdhcpcd/interface.c
@@ -0,0 +1,1060 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#include <arpa/inet.h>
+
+/* Netlink suff */
+#ifdef __linux__
+#include <asm/types.h> /* Needed for 2.4 kernels */
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+#else
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+
+void free_address (struct address_head *addresses)
+{
+ address_t *p;
+ address_t *n;
+
+ if (! addresses)
+ return;
+
+ p = STAILQ_FIRST (addresses);
+ while (p) {
+ n = STAILQ_NEXT (p, entries);
+ free (p);
+ p = n;
+ }
+ free (addresses);
+}
+
+void free_route (struct route_head *routes)
+{
+ route_t *p;
+ route_t *n;
+
+ if (! routes)
+ return;
+
+ p = STAILQ_FIRST (routes);
+ while (p) {
+ n = STAILQ_NEXT (p, entries);
+ free (p);
+ p = n;
+ }
+ free (routes);
+}
+
+int inet_ntocidr (struct in_addr address)
+{
+ int cidr = 0;
+ uint32_t mask = htonl (address.s_addr);
+
+ while (mask) {
+ cidr++;
+ mask <<= 1;
+ }
+
+ return (cidr);
+}
+
+int inet_cidrtoaddr (int cidr, struct in_addr *addr) {
+ int ocets;
+
+ if (cidr < 0 || cidr > 32) {
+ errno = EINVAL;
+ return (-1);
+ }
+ ocets = (cidr + 7) / 8;
+
+ memset (addr, 0, sizeof (*addr));
+ if (ocets > 0) {
+ memset (&addr->s_addr, 255, (size_t) ocets - 1);
+ memset ((unsigned char *) &addr->s_addr + (ocets - 1),
+ (256 - (1 << (32 - cidr) % 8)), 1);
+ }
+
+ return (0);
+}
+
+uint32_t get_netmask (uint32_t addr)
+{
+ uint32_t dst;
+
+ if (addr == 0)
+ return (0);
+
+ dst = htonl (addr);
+ if (IN_CLASSA (dst))
+ return (ntohl (IN_CLASSA_NET));
+ if (IN_CLASSB (dst))
+ return (ntohl (IN_CLASSB_NET));
+ if (IN_CLASSC (dst))
+ return (ntohl (IN_CLASSC_NET));
+
+ return (0);
+}
+
+char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen)
+{
+ static char buffer[(HWADDR_LEN * 3) + 1];
+ char *p = buffer;
+ size_t i;
+
+ for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
+ if (i > 0)
+ *p ++= ':';
+ p += snprintf (p, 3, "%.2x", hwaddr[i]);
+ }
+
+ *p ++= '\0';
+
+ return (buffer);
+}
+
+size_t hwaddr_aton (unsigned char *buffer, const char *addr)
+{
+ char c[3];
+ const char *p = addr;
+ unsigned char *bp = buffer;
+ size_t len = 0;
+
+ c[2] = '\0';
+ while (*p) {
+ c[0] = *p++;
+ c[1] = *p++;
+ /* Ensure that next data is EOL or a seperator with data */
+ if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
+ errno = EINVAL;
+ return (0);
+ }
+ /* Ensure that digits are hex */
+ if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) {
+ errno = EINVAL;
+ return (0);
+ }
+ p++;
+ if (bp)
+ *bp++ = (unsigned char) strtol (c, NULL, 16);
+ else
+ len++;
+ }
+
+ if (bp)
+ return (bp - buffer);
+ return (len);
+}
+
+static int _do_interface (const char *ifname,
+ _unused unsigned char *hwaddr, _unused size_t *hwlen,
+ struct in_addr *addr,
+ bool flush, bool get)
+{
+ int s;
+ struct ifconf ifc;
+ int retval = 0;
+ int len = 10 * sizeof (struct ifreq);
+ int lastlen = 0;
+ char *p;
+
+ if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ /* Not all implementations return the needed buffer size for
+ * SIOGIFCONF so we loop like so for all until it works */
+ memset (&ifc, 0, sizeof (ifc));
+ for (;;) {
+ ifc.ifc_len = len;
+ ifc.ifc_buf = xmalloc ((size_t) len);
+ if (ioctl (s, SIOCGIFCONF, &ifc) == -1) {
+ if (errno != EINVAL || lastlen != 0) {
+ logger (LOG_ERR, "ioctl SIOCGIFCONF: %s",
+ strerror (errno));
+ close (s);
+ free (ifc.ifc_buf);
+ return -1;
+ }
+ } else {
+ if (ifc.ifc_len == lastlen)
+ break;
+ lastlen = ifc.ifc_len;
+ }
+
+ free (ifc.ifc_buf);
+ ifc.ifc_buf = NULL;
+ len *= 2;
+ }
+
+ for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) {
+ union {
+ char *buffer;
+ struct ifreq *ifr;
+ } ifreqs;
+ struct sockaddr_in address;
+ struct ifreq *ifr;
+
+ /* Cast the ifc buffer to an ifreq cleanly */
+ ifreqs.buffer = p;
+ ifr = ifreqs.ifr;
+
+#ifdef __linux__
+ p += sizeof (*ifr);
+#else
+ p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len;
+#endif
+
+ if (strcmp (ifname, ifr->ifr_name) != 0)
+ continue;
+
+#ifdef AF_LINK
+ if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) {
+ struct sockaddr_dl sdl;
+
+ memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl));
+ *hwlen = sdl.sdl_alen;
+ memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen,
+ (size_t) sdl.sdl_alen);
+ retval = 1;
+ break;
+ }
+#endif
+
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ memcpy (&address, &ifr->ifr_addr, sizeof (address));
+ if (flush) {
+ struct sockaddr_in netmask;
+
+ if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) {
+ logger (LOG_ERR,
+ "ioctl SIOCGIFNETMASK: %s",
+ strerror (errno));
+ continue;
+ }
+ memcpy (&netmask, &ifr->ifr_addr,
+ sizeof (netmask));
+
+ if (del_address (ifname,
+ address.sin_addr,
+ netmask.sin_addr) == -1)
+ retval = -1;
+ } else if (get) {
+ addr->s_addr = address.sin_addr.s_addr;
+ retval = 1;
+ break;
+ } else if (address.sin_addr.s_addr == addr->s_addr) {
+ retval = 1;
+ break;
+ }
+ }
+
+ }
+
+ close (s);
+ free (ifc.ifc_buf);
+ return retval;
+}
+
+interface_t *read_interface (const char *ifname, _unused int metric)
+{
+ int s;
+ struct ifreq ifr;
+ interface_t *iface = NULL;
+ unsigned char *hwaddr = NULL;
+ size_t hwlen = 0;
+ sa_family_t family = 0;
+ unsigned short mtu;
+#ifdef __linux__
+ char *p;
+#endif
+
+ if (! ifname)
+ return NULL;
+
+ memset (&ifr, 0, sizeof (ifr));
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+
+ if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return NULL;
+ }
+
+#ifdef __linux__
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) {
+ logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno));
+ goto exit;
+ }
+
+ switch (ifr.ifr_hwaddr.sa_family) {
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE802:
+ hwlen = ETHER_ADDR_LEN;
+ break;
+ case ARPHRD_IEEE1394:
+ hwlen = EUI64_ADDR_LEN;
+ case ARPHRD_INFINIBAND:
+ hwlen = INFINIBAND_ADDR_LEN;
+ break;
+ default:
+ logger (LOG_ERR,
+ "interface is not Ethernet, FireWire, " \
+ "InfiniBand or Token Ring");
+ goto exit;
+ }
+
+ hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN);
+ memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen);
+ family = ifr.ifr_hwaddr.sa_family;
+#else
+ ifr.ifr_metric = metric;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) {
+ logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno));
+ goto exit;
+ }
+
+ hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN);
+ if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) {
+ logger (LOG_ERR, "could not find interface %s", ifname);
+ goto exit;
+ }
+
+ family = ARPHRD_ETHER;
+#endif
+
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl (s, SIOCGIFMTU, &ifr) == -1) {
+ logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
+ goto exit;
+ }
+
+ if (ifr.ifr_mtu < MTU_MIN) {
+ logger (LOG_DEBUG, "MTU of %d is too low, setting to %d",
+ ifr.ifr_mtu, MTU_MIN);
+ ifr.ifr_mtu = MTU_MIN;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl (s, SIOCSIFMTU, &ifr) == -1) {
+ logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s",
+ strerror (errno));
+ goto exit;
+ }
+ }
+ mtu = ifr.ifr_mtu;
+
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+#ifdef __linux__
+ /* We can only bring the real interface up */
+ if ((p = strchr (ifr.ifr_name, ':')))
+ *p = '\0';
+#endif
+ if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) {
+ logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
+ goto exit;
+ }
+
+ if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) {
+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+ if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) {
+ logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s",
+ strerror (errno));
+ goto exit;
+ }
+ }
+
+ iface = xzalloc (sizeof (*iface));
+ strlcpy (iface->name, ifname, IF_NAMESIZE);
+#ifdef ENABLE_INFO
+ snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname);
+#endif
+ memcpy (&iface->hwaddr, hwaddr, hwlen);
+ iface->hwlen = hwlen;
+
+ iface->family = family;
+ iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK));
+ iface->mtu = iface->previous_mtu = mtu;
+
+ logger (LOG_INFO, "hardware address = %s",
+ hwaddr_ntoa (iface->hwaddr, iface->hwlen));
+
+ /* 0 is a valid fd, so init to -1 */
+ iface->fd = -1;
+#ifdef __linux__
+ iface->listen_fd = -1;
+#endif
+
+exit:
+ close (s);
+ free (hwaddr);
+ return iface;
+}
+
+int get_mtu (const char *ifname)
+{
+ struct ifreq ifr;
+ int r;
+ int s;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return (-1);
+ }
+
+ memset (&ifr, 0, sizeof (ifr));
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ r = ioctl (s, SIOCGIFMTU, &ifr);
+ close (s);
+
+ if (r == -1) {
+ logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
+ return (-1);
+ }
+
+ return (ifr.ifr_mtu);
+}
+
+int set_mtu (const char *ifname, short int mtu)
+{
+ struct ifreq ifr;
+ int r;
+ int s;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return (-1);
+ }
+
+ memset (&ifr, 0, sizeof (ifr));
+ logger (LOG_DEBUG, "setting MTU to %d", mtu);
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ r = ioctl (s, SIOCSIFMTU, &ifr);
+ close (s);
+
+ if (r == -1)
+ logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno));
+
+ return (r == 0 ? 0 : -1);
+}
+
+static void log_route (struct in_addr destination,
+ struct in_addr netmask,
+ struct in_addr gateway,
+ _unused int metric,
+ int change, int del)
+{
+ char *dstd = xstrdup (inet_ntoa (destination));
+
+#ifdef __linux__
+#define METRIC " metric %d"
+#else
+#define METRIC ""
+#endif
+
+ if (gateway.s_addr == destination.s_addr ||
+ gateway.s_addr == INADDR_ANY)
+ logger (LOG_INFO, "%s route to %s/%d" METRIC,
+ change ? "changing" : del ? "removing" : "adding",
+ dstd, inet_ntocidr (netmask)
+#ifdef __linux__
+ , metric
+#endif
+ );
+ else if (destination.s_addr == INADDR_ANY)
+ logger (LOG_INFO, "%s default route via %s" METRIC,
+ change ? "changing" : del ? "removing" : "adding",
+ inet_ntoa (gateway)
+
+#ifdef __linux__
+ , metric
+#endif
+ );
+ else
+ logger (LOG_INFO, "%s route to %s/%d via %s" METRIC,
+ change ? "changing" : del ? "removing" : "adding",
+ dstd, inet_ntocidr (netmask), inet_ntoa (gateway)
+#ifdef __linux__
+ , metric
+#endif
+ );
+
+ free (dstd);
+}
+
+#if defined(BSD) || defined(__FreeBSD_kernel__)
+
+/* Darwin doesn't define this for some very odd reason */
+#ifndef SA_SIZE
+# define SA_SIZE(sa) \
+ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
+ sizeof(long) : \
+ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
+#endif
+
+static int do_address (const char *ifname, struct in_addr address,
+ struct in_addr netmask, struct in_addr broadcast,
+ int del)
+{
+ int s;
+ struct ifaliasreq ifa;
+
+ if (! ifname)
+ return -1;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset (&ifa, 0, sizeof (ifa));
+ strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name));
+
+#define ADDADDR(_var, _addr) { \
+ union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \
+ _s.sa = &_var; \
+ _s.sin->sin_family = AF_INET; \
+ _s.sin->sin_len = sizeof (*_s.sin); \
+ memcpy (&_s.sin->sin_addr, &_addr, sizeof (_s.sin->sin_addr)); \
+}
+
+ ADDADDR (ifa.ifra_addr, address);
+ ADDADDR (ifa.ifra_mask, netmask);
+if (! del)
+ ADDADDR (ifa.ifra_broadaddr, broadcast);
+
+#undef ADDADDR
+
+ if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) {
+ logger (LOG_ERR, "ioctl %s: %s",
+ del ? "SIOCDIFADDR" : "SIOCAIFADDR",
+ strerror (errno));
+ close (s);
+ return -1;
+ }
+
+close (s);
+return 0;
+}
+
+static int do_route (const char *ifname,
+ struct in_addr destination,
+ struct in_addr netmask,
+ struct in_addr gateway,
+ int metric,
+ int change, int del)
+{
+ int s;
+ static int seq;
+ union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_dl sdl;
+ struct sockaddr_storage ss;
+ } su;
+ struct rtm
+ {
+ struct rt_msghdr hdr;
+ char buffer[sizeof (su) * 3];
+ } rtm;
+ char *bp = rtm.buffer;
+ size_t l;
+
+ if (! ifname)
+ return -1;
+
+ log_route (destination, netmask, gateway, metric, change, del);
+
+ if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset (&rtm, 0, sizeof (rtm));
+
+ rtm.hdr.rtm_version = RTM_VERSION;
+ rtm.hdr.rtm_seq = ++seq;
+ rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD;
+ rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
+
+ /* This order is important */
+ rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+
+#define ADDADDR(_addr) \
+ memset (&su, 0, sizeof (su)); \
+ su.sin.sin_family = AF_INET; \
+ su.sin.sin_len = sizeof (su.sin); \
+ memcpy (&su.sin.sin_addr, &_addr, sizeof (su.sin.sin_addr)); \
+ l = SA_SIZE (&(su.sa)); \
+ memcpy (bp, &(su), l); \
+ bp += l;
+
+ ADDADDR (destination);
+
+ if (netmask.s_addr == INADDR_BROADCAST ||
+ gateway.s_addr == INADDR_ANY)
+ {
+ /* Make us a link layer socket */
+ unsigned char *hwaddr;
+ size_t hwlen = 0;
+
+ if (netmask.s_addr == INADDR_BROADCAST)
+ rtm.hdr.rtm_flags |= RTF_HOST;
+
+ hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN);
+ _do_interface (ifname, hwaddr, &hwlen, NULL, false, false);
+ memset (&su, 0, sizeof (su));
+ su.sdl.sdl_len = sizeof (su.sdl);
+ su.sdl.sdl_family = AF_LINK;
+ su.sdl.sdl_nlen = strlen (ifname);
+ memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen);
+ su.sdl.sdl_alen = hwlen;
+ memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen,
+ hwaddr, (size_t) su.sdl.sdl_alen);
+
+ l = SA_SIZE (&(su.sa));
+ memcpy (bp, &su, l);
+ bp += l;
+ free (hwaddr);
+ } else {
+ rtm.hdr.rtm_flags |= RTF_GATEWAY;
+ ADDADDR (gateway);
+ }
+
+ ADDADDR (netmask);
+#undef ADDADDR
+
+ rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
+ if (write (s, &rtm, l) == -1) {
+ /* Don't report error about routes already existing */
+ if (errno != EEXIST)
+ logger (LOG_ERR, "write: %s", strerror (errno));
+ close (s);
+ return -1;
+ }
+
+ close (s);
+ return 0;
+}
+
+#elif __linux__
+/* This netlink stuff is overly compex IMO.
+ * The BSD implementation is much cleaner and a lot less code.
+ * send_netlink handles the actual transmission so we can work out
+ * if there was an error or not. */
+#define BUFFERLEN 256
+int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg)
+{
+ int s;
+ pid_t mypid = getpid ();
+ struct sockaddr_nl nl;
+ struct iovec iov;
+ struct msghdr msg;
+ static unsigned int seq;
+ char *buffer;
+ ssize_t bytes;
+ union
+ {
+ char *buffer;
+ struct nlmsghdr *nlm;
+ } h;
+
+ if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset (&nl, 0, sizeof (nl));
+ nl.nl_family = AF_NETLINK;
+ if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) {
+ logger (LOG_ERR, "bind: %s", strerror (errno));
+ close (s);
+ return -1;
+ }
+
+ memset (&iov, 0, sizeof (iov));
+ iov.iov_base = hdr;
+ iov.iov_len = hdr->nlmsg_len;
+
+ memset (&msg, 0, sizeof (msg));
+ msg.msg_name = &nl;
+ msg.msg_namelen = sizeof (nl);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ /* Request a reply */
+ hdr->nlmsg_flags |= NLM_F_ACK;
+ hdr->nlmsg_seq = ++seq;
+
+ if (sendmsg (s, &msg, 0) == -1) {
+ logger (LOG_ERR, "write: %s", strerror (errno));
+ close (s);
+ return -1;
+ }
+
+ buffer = xzalloc (sizeof (char) * BUFFERLEN);
+ iov.iov_base = buffer;
+
+ for (;;) {
+ iov.iov_len = BUFFERLEN;
+ bytes = recvmsg (s, &msg, 0);
+
+ if (bytes == -1) {
+ if (errno != EINTR)
+ logger (LOG_ERR, "recvmsg: %s",
+ strerror (errno));
+ continue;
+ }
+
+ if (bytes == 0) {
+ logger (LOG_ERR, "netlink: EOF");
+ goto eexit;
+ }
+
+ if (msg.msg_namelen != sizeof (nl)) {
+ logger (LOG_ERR,
+ "netlink: sender address length mismatch");
+ goto eexit;
+ }
+
+ for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) {
+ int len = h.nlm->nlmsg_len;
+ int l = len - sizeof (*h.nlm);
+ struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm);
+
+ if (l < 0 || len > bytes) {
+ if (msg.msg_flags & MSG_TRUNC)
+ logger (LOG_ERR, "netlink: truncated message");
+ else
+ logger (LOG_ERR, "netlink: malformed message");
+ goto eexit;
+ }
+
+ /* Ensure it's our message */
+ if (nl.nl_pid != 0 ||
+ (pid_t) h.nlm->nlmsg_pid != mypid ||
+ h.nlm->nlmsg_seq != seq)
+ {
+ /* Next Message */
+ bytes -= NLMSG_ALIGN (len);
+ h.buffer += NLMSG_ALIGN (len);
+ continue;
+ }
+
+ /* We get an NLMSG_ERROR back with a code of zero for success */
+ if (h.nlm->nlmsg_type != NLMSG_ERROR) {
+ logger (LOG_ERR, "netlink: unexpected reply %d",
+ h.nlm->nlmsg_type);
+ goto eexit;
+ }
+
+ if ((unsigned) l < sizeof (*err)) {
+ logger (LOG_ERR, "netlink: error truncated");
+ goto eexit;
+ }
+
+ if (err->error == 0) {
+ int retval = 0;
+
+ close (s);
+ if (callback) {
+ if ((retval = callback (hdr, arg)) == -1)
+ logger (LOG_ERR, "netlink: callback failed");
+ }
+ free (buffer);
+ return (retval);
+ }
+
+ errno = -err->error;
+ /* Don't report on something already existing */
+ if (errno != EEXIST)
+ logger (LOG_ERR, "netlink: %s",
+ strerror (errno));
+ goto eexit;
+ }
+ }
+
+eexit:
+ close (s);
+ free (buffer);
+ return -1;
+}
+
+#define NLMSG_TAIL(nmsg) \
+ ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len)))
+
+static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
+ const void *data, int alen)
+{
+ int len = RTA_LENGTH(alen);
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) {
+ logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n",
+ maxlen);
+ return -1;
+ }
+
+ rta = NLMSG_TAIL (n);
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy (RTA_DATA (rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
+
+ return 0;
+}
+
+static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type,
+ uint32_t data)
+{
+ int len = RTA_LENGTH (sizeof (data));
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) {
+ logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n",
+ maxlen);
+ return -1;
+ }
+
+ rta = NLMSG_TAIL (n);
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy (RTA_DATA (rta), &data, sizeof (data));
+ n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+ return 0;
+}
+
+struct nlma
+{
+ struct nlmsghdr hdr;
+ struct ifaddrmsg ifa;
+ char buffer[64];
+};
+
+struct nlmr
+{
+ struct nlmsghdr hdr;
+ struct rtmsg rt;
+ char buffer[256];
+};
+
+static int do_address(const char *ifname,
+ struct in_addr address, struct in_addr netmask,
+ struct in_addr broadcast, int del)
+{
+ struct nlma *nlm;
+ int retval;
+
+ if (!ifname)
+ return -1;
+
+ nlm = xzalloc (sizeof (*nlm));
+ nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
+ nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
+ if (! del)
+ nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+ nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR;
+ if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) {
+ logger (LOG_ERR, "if_nametoindex: no index for interface `%s'",
+ ifname);
+ free (nlm);
+ return -1;
+ }
+ nlm->ifa.ifa_family = AF_INET;
+
+ nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask);
+
+ /* This creates the aliased interface */
+ add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL,
+ ifname, strlen (ifname) + 1);
+
+ add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL,
+ &address.s_addr, sizeof (address.s_addr));
+ if (! del)
+ add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST,
+ &broadcast.s_addr, sizeof (broadcast.s_addr));
+
+ retval = send_netlink (&nlm->hdr, NULL, NULL);
+ free (nlm);
+ return retval;
+}
+
+static int do_route (const char *ifname,
+ struct in_addr destination,
+ struct in_addr netmask,
+ struct in_addr gateway,
+ int metric, int change, int del)
+{
+ struct nlmr *nlm;
+ unsigned int ifindex;
+ int retval;
+
+ if (! ifname)
+ return -1;
+
+ log_route (destination, netmask, gateway, metric, change, del);
+
+ if (! (ifindex = if_nametoindex (ifname))) {
+ logger (LOG_ERR, "if_nametoindex: no index for interface `%s'",
+ ifname);
+ return -1;
+ }
+
+ nlm = xzalloc (sizeof (*nlm));
+ nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+ if (change)
+ nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
+ else if (! del)
+ nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
+ nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
+ nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE;
+ nlm->rt.rtm_family = AF_INET;
+ nlm->rt.rtm_table = RT_TABLE_MAIN;
+
+ if (del)
+ nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
+ else {
+ nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+ nlm->rt.rtm_protocol = RTPROT_BOOT;
+ if (netmask.s_addr == INADDR_BROADCAST ||
+ gateway.s_addr == INADDR_ANY)
+ nlm->rt.rtm_scope = RT_SCOPE_LINK;
+ else
+ nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
+ nlm->rt.rtm_type = RTN_UNICAST;
+ }
+
+ nlm->rt.rtm_dst_len = inet_ntocidr (netmask);
+ add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST,
+ &destination.s_addr, sizeof (destination.s_addr));
+ if (netmask.s_addr != INADDR_BROADCAST &&
+ destination.s_addr != gateway.s_addr)
+ add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY,
+ &gateway.s_addr, sizeof (gateway.s_addr));
+
+ add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex);
+ add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric);
+
+ retval = send_netlink (&nlm->hdr, NULL, NULL);
+ free (nlm);
+ return retval;
+}
+
+#else
+ #error "Platform not supported!"
+ #error "We currently support BPF and Linux sockets."
+ #error "Other platforms may work using BPF. If yours does, please let me know"
+ #error "so I can add it to our list."
+#endif
+
+int add_address (const char *ifname, struct in_addr address,
+ struct in_addr netmask, struct in_addr broadcast)
+{
+ logger (LOG_INFO, "adding IP address %s/%d",
+ inet_ntoa (address), inet_ntocidr (netmask));
+
+ return (do_address (ifname, address, netmask, broadcast, 0));
+}
+
+int del_address (const char *ifname,
+ struct in_addr address, struct in_addr netmask)
+{
+ struct in_addr t;
+
+ logger (LOG_INFO, "removing IP address %s/%d",
+ inet_ntoa (address), inet_ntocidr (netmask));
+
+ memset (&t, 0, sizeof (t));
+ return (do_address (ifname, address, netmask, t, 1));
+}
+
+int add_route (const char *ifname, struct in_addr destination,
+ struct in_addr netmask, struct in_addr gateway, int metric)
+{
+ return (do_route (ifname, destination, netmask, gateway, metric, 0, 0));
+}
+
+int change_route (const char *ifname, struct in_addr destination,
+ struct in_addr netmask, struct in_addr gateway, int metric)
+{
+ return (do_route (ifname, destination, netmask, gateway, metric, 1, 0));
+}
+
+int del_route (const char *ifname, struct in_addr destination,
+ struct in_addr netmask, struct in_addr gateway, int metric)
+{
+ return (do_route (ifname, destination, netmask, gateway, metric, 0, 1));
+}
+
+
+int flush_addresses (const char *ifname)
+{
+ return (_do_interface (ifname, NULL, NULL, NULL, true, false));
+}
+
+in_addr_t get_address (const char *ifname)
+{
+ struct in_addr address;
+ if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0)
+ return (address.s_addr);
+ return (0);
+}
+
+int has_address (const char *ifname, struct in_addr address)
+{
+ return (_do_interface (ifname, NULL, NULL, &address, false, false));
+}
diff --git a/src/customdhcpcd/interface.h b/src/customdhcpcd/interface.h
new file mode 100644
index 0000000..8215d48
--- /dev/null
+++ b/src/customdhcpcd/interface.h
@@ -0,0 +1,173 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <limits.h>
+#include <stdbool.h>
+
+#include "config.h"
+
+#ifdef __linux__
+# include <linux/netlink.h>
+#endif
+
+#ifdef ENABLE_DUID
+#ifndef DUID_LEN
+# define DUID_LEN 128 + 2
+#endif
+#endif
+
+#define EUI64_ADDR_LEN 8
+#define INFINIBAND_ADDR_LEN 20
+
+/* Linux 2.4 doesn't define this */
+#ifndef ARPHRD_IEEE1394
+# define ARPHRD_IEEE1394 24
+#endif
+
+/* The BSD's don't define this yet */
+#ifndef ARPHRD_INFINIBAND
+# define ARPHRD_INFINIBAND 32
+#endif
+
+#define HWADDR_LEN 20
+
+/* Work out if we have a private address or not
+ * 10/8
+ * 172.16/12
+ * 192.168/16
+ */
+#ifndef IN_PRIVATE
+# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \
+ ((addr & 0xfff00000) == 0xac100000) || \
+ ((addr & IN_CLASSB_NET) == 0xc0a80000))
+#endif
+
+#define LINKLOCAL_ADDR 0xa9fe0000
+#define LINKLOCAL_MASK 0xffff0000
+#define LINKLOCAL_BRDC 0xa9feffff
+
+#ifndef IN_LINKLOCAL
+# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
+#endif
+
+#ifndef STAILQ_ENTRY
+# error "your sys/queue.h is too old and lacks STAILQ"
+#endif
+
+#define NSTAILQ_FOREACH(var, head, field) \
+ if (head) STAILQ_FOREACH (var, head, field)
+
+typedef struct route_t
+{
+ struct in_addr destination;
+ struct in_addr netmask;
+ struct in_addr gateway;
+ STAILQ_ENTRY (route_t) entries;
+} route_t;
+STAILQ_HEAD (route_head, route_t);
+
+typedef struct address_t
+{
+ struct in_addr address;
+ STAILQ_ENTRY (address_t) entries;
+} address_t;
+STAILQ_HEAD (address_head, address_t);
+
+typedef struct interface_t
+{
+ char name[IF_NAMESIZE];
+ sa_family_t family;
+ unsigned char hwaddr[HWADDR_LEN];
+ size_t hwlen;
+ bool arpable;
+ unsigned short mtu;
+
+ int fd;
+ size_t buffer_length;
+
+#ifdef __linux__
+ int listen_fd;
+ int socket_protocol;
+#endif
+
+ char infofile[PATH_MAX];
+
+ unsigned short previous_mtu;
+ struct in_addr previous_address;
+ struct in_addr previous_netmask;
+ struct route_head *previous_routes;
+
+ time_t start_uptime;
+
+ unsigned char *clientid;
+ size_t clientid_len;
+} interface_t;
+
+void free_address (struct address_head *addresses);
+void free_route (struct route_head *routes);
+uint32_t get_netmask (uint32_t addr);
+char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen);
+size_t hwaddr_aton (unsigned char *hwaddr, const char *addr);
+
+interface_t *read_interface (const char *ifname, int metric);
+int get_mtu (const char *ifname);
+int set_mtu (const char *ifname, short int mtu);
+
+int add_address (const char *ifname, struct in_addr address,
+ struct in_addr netmask, struct in_addr broadcast);
+int del_address (const char *ifname, struct in_addr address,
+ struct in_addr netmask);
+
+int flush_addresses (const char *ifname);
+in_addr_t get_address (const char *ifname);
+int has_address (const char *ifname, struct in_addr address);
+
+int add_route (const char *ifname, struct in_addr destination,
+ struct in_addr netmask, struct in_addr gateway, int metric);
+int change_route (const char *ifname, struct in_addr destination,
+ struct in_addr netmask, struct in_addr gateway, int metric);
+int del_route (const char *ifname, struct in_addr destination,
+ struct in_addr netmask, struct in_addr gateway, int metric);
+
+int inet_ntocidr (struct in_addr address);
+int inet_cidrtoaddr (int cidr, struct in_addr *addr);
+
+#ifdef __linux__
+typedef int (*netlink_callback) (struct nlmsghdr *hdr, void *arg);
+int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg);
+#endif
+#endif
diff --git a/src/customdhcpcd/ipv4ll.c b/src/customdhcpcd/ipv4ll.c
new file mode 100644
index 0000000..9742b9a
--- /dev/null
+++ b/src/customdhcpcd/ipv4ll.c
@@ -0,0 +1,70 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "arp.h"
+#include "ipv4ll.h"
+
+#ifdef ENABLE_IPV4LL
+
+#ifndef ENABLE_ARP
+ # error IPV4LL requires ARP
+#endif
+
+#define IPV4LL_LEASETIME 20
+
+int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) {
+ struct in_addr addr;
+
+ for (;;) {
+ addr.s_addr = htonl (LINKLOCAL_ADDR |
+ (((uint32_t) abs ((int) random ())
+ % 0xFD00) + 0x0100));
+ errno = 0;
+ if (! arp_claim (iface, addr))
+ break;
+ /* Our ARP may have been interrupted */
+ if (errno)
+ return (-1);
+ }
+
+ dhcp->address.s_addr = addr.s_addr;
+ dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK);
+ dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC);
+
+ /* Finally configure some DHCP like lease times */
+ dhcp->leasetime = IPV4LL_LEASETIME;
+ dhcp->renewaltime = (dhcp->leasetime * 0.5);
+ dhcp->rebindtime = (dhcp->leasetime * 0.875);
+
+ return (0);
+}
+
+#endif
diff --git a/src/customdhcpcd/ipv4ll.h b/src/customdhcpcd/ipv4ll.h
new file mode 100644
index 0000000..4fa8943
--- /dev/null
+++ b/src/customdhcpcd/ipv4ll.h
@@ -0,0 +1,39 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef IPV4LL_H
+#define IPV4LL_H
+
+#ifdef ENABLE_IPV4LL
+
+#include "dhcp.h"
+#include "interface.h"
+
+int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp);
+
+#endif
+#endif
diff --git a/src/customdhcpcd/logger.c b/src/customdhcpcd/logger.c
new file mode 100644
index 0000000..2c8431d
--- /dev/null
+++ b/src/customdhcpcd/logger.c
@@ -0,0 +1,154 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define SYSLOG_NAMES
+
+#define COM_CH "/var/tmp/com.socket"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "logger.h"
+#include "logwriter.h"
+
+static int loglevel = LOG_WARNING;
+static char logprefix[12] = { 0 };
+
+int logtolevel(const char *priority) {
+ CODE *c;
+
+ if (isdigit ((int) *priority))
+ return (atoi(priority));
+
+ for (c = prioritynames; c->c_name; c++)
+ if (!strcasecmp(priority, c->c_name))
+ return (c->c_val);
+
+ return (-1);
+}
+
+static const char *leveltolog(int level) {
+ CODE *c;
+
+ for (c = prioritynames; c->c_name; c++)
+ if (c->c_val == level)
+ return (c->c_name);
+
+ return (NULL);
+}
+
+void setloglevel(int level) {
+ loglevel = level;
+}
+
+void setlogprefix(const char *prefix) {
+ snprintf(logprefix, sizeof(logprefix), "%s", prefix);
+}
+
+void logger(int level, const char *fmt, ...) {
+ va_list p;
+ //va_list p2;
+// FILE *f = stderr;
+ FILE *f;
+ FILE *f2;
+ char* path = "/tmp/cdhcpcd.log";
+ char* msgpath = "/tmp/cdhcpcd-msg.log";
+ int size = 512;
+ char *msg = (char *) malloc (size);
+
+
+ f = fopen(path,"a");
+ f2 = fopen(msgpath,"a");
+ va_start (p, fmt);
+ //va_copy (p2, p);
+
+
+ vsnprintf (msg, size, fmt, p);
+ strcat(msg,"\n");
+ logToQt(level, DHCPCD_LOG, msg);
+
+ fprintf(f2, "%s, %s", leveltolog(level), logprefix);
+ fprintf(f2, "%s", msg);
+ fputc('\n', f2);
+
+ fprintf(f, "%s, %s", leveltolog(level), logprefix);
+ vfprintf(f, fmt, p);
+ fputc('\n', f);
+
+ /* stdout, stderr may be re-directed to some kind of buffer.
+ * So we always flush to ensure it's written. */
+ fflush(f);
+
+// //logLoggerToQt(level, fmt, p);
+// if (level <= LOG_ERR || level <= loglevel) {
+//
+// /* new function by Niklas Goby
+// * send the log message also to our Qt programm.
+// * implemented in logwriter.c
+// * */
+// //logLoggerToQt(level, fmt, p);
+//
+// if (level == LOG_DEBUG || level == LOG_INFO)
+// f = stdout;
+// fprintf(f, "%s, %s", leveltolog(level), logprefix);
+// vfprintf(f, fmt, p);
+// fputc('\n', f);
+//
+// /* stdout, stderr may be re-directed to some kind of buffer.
+// * So we always flush to ensure it's written. */
+// fflush(f);
+// }
+// if (level < LOG_DEBUG || level <= loglevel) {
+// size_t len = strlen(logprefix);
+// size_t fmt2len = strlen(fmt) + len + 1;
+// char *fmt2 = malloc(sizeof(char) * fmt2len);
+// char *pf = fmt2;
+// if (fmt2) {
+// memcpy(pf, logprefix, len);
+// pf += len;
+// strlcpy(pf, fmt, fmt2len - len);
+// vsyslog(level, fmt2, p2);
+// free(fmt2);
+// } else {
+// vsyslog(level, fmt, p2);
+// syslog(LOG_ERR, "logger: memory exhausted");
+// exit(EXIT_FAILURE);
+// }
+// }
+
+ //va_end (p2);
+ va_end (p);
+}
+
diff --git a/src/customdhcpcd/logger.h b/src/customdhcpcd/logger.h
new file mode 100644
index 0000000..70e2ed5
--- /dev/null
+++ b/src/customdhcpcd/logger.h
@@ -0,0 +1,48 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LOGGER_H
+#define LOGGER_H
+
+#if defined(__GNUC__)
+# define _PRINTF_LIKE(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two)))
+#else
+# define _PRINTF_LIKE(_one, _two)
+#endif
+
+#include <syslog.h>
+
+
+
+int logtolevel (const char *priority);
+void setloglevel (int level);
+void setlogprefix (const char *prefix);
+void logger (int level, const char *fmt, ...) _PRINTF_LIKE (2, 3);
+
+
+
+#endif
diff --git a/src/customdhcpcd/logwriter.c b/src/customdhcpcd/logwriter.c
new file mode 100644
index 0000000..6230d4c
--- /dev/null
+++ b/src/customdhcpcd/logwriter.c
@@ -0,0 +1,260 @@
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "dhcp.h"
+#include "dhcpcd.h"
+#include "errno.h"
+#include "info.h"
+#include "logger.h"
+#include "logwriter.h"
+
+#include "../../common/fbgui.h" // for constants
+/*sockets for the logger and the qt-reader */
+int sockfd, ns;
+int retval = -1;
+char socketName[QTSOCKETADDRESSLENGTH];
+char interfaceName[IF_NAMESIZE];
+
+void setSocketName(const char * sn) {
+ snprintf(socketName, sizeof(socketName), "%s", sn);
+}
+
+void setInterfaceName(const char * in) {
+ snprintf(interfaceName, sizeof(interfaceName), "%s", in);
+}
+
+int initQtLoggerSocket() {
+ /**
+ * new code. seems to be right.
+ */
+
+ struct sockaddr_un serv_addr;
+ fprintf(stdout, "start init \n");
+ sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ fprintf(stdout, "ERROR opening socket \n");
+ retval = sockfd;
+ return sockfd;
+ }
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, socketName);
+
+ retval = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
+ if (retval < 0)
+ fprintf(stdout, "ERROR connecting \n");
+ fprintf(stdout, "init Qt Logger Socket done \n");
+ return retval;
+}
+
+void closeQtLoggerSocket() {
+ close(sockfd);
+}
+
+void sendToQt(log_msg * msg) {
+ int n = -1;
+ int t;
+ int ret;
+ const char *tpl = "%s;%d;%d;%s\n";
+ char outbuf[DHCP_MESSAGE_SIZE];
+ char ack[ACK_SIZE];
+ /*
+ size_t outbuf_size = sizeof(char) * 4 + // ";" *3 + newline
+ sizeof(int) * 2 + // status, substatus
+ sizeof(msg->device) + // devicename
+ sizeof(msg->msg); // msg
+ outbuf = malloc(outbuf_size);
+ memset(outbuf, 0, outbuf_size);
+ snprintf(outbuf, sizeof(char) * 3 + sizeof(int) * 2 + sizeof(msg->device)
+ + sizeof(msg->msg), tpl, msg->device, msg->status, msg->substatus,
+ msg->msg);
+ */
+ memset(outbuf, '\0', DHCP_MESSAGE_SIZE);
+ ret = snprintf(outbuf, DHCP_MESSAGE_SIZE, tpl, msg->device, msg->status,
+ msg->substatus, msg->msg);
+ if (ret < 1) {
+ log ger(LOG_INFO, "[fbgui] ERROR filling message buffer");
+ //syslog(LOG_INFO, "[fbgui] ERROR filling message buffer");
+ return;
+ }
+ if (outbuf != NULL) {
+ n = send(sockfd, outbuf, DHCP_MESSAGE_SIZE, 0);
+ }
+ syslog(LOG_INFO, "[fbgui] INFO writing to socket: [%d:%d] %s (%s)",
+ msg->status, msg->substatus, msg->msg, msg->device);
+
+ if (n <= 0) {
+ logger(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)",
+ msg->status, msg->substatus, msg->msg, msg->device);
+ //syslog(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)",
+ // msg->status, msg->substatus, msg->msg, msg->device);
+ }
+ /*
+ memset(ack, 0, ACK_SIZE);
+ if ((t = recv(sockfd, ack, ACK_SIZE, 0)) > 0) {
+ syslog(LOG_ERR, "[fbgui] recv ack echo> %s", ack);
+ printf("received: %s\n", ack);
+ } else {
+ if (t < 0)
+ syslog(LOG_ERR, "[fbgui] ERROR receiving from socket");
+ else
+ syslog(LOG_ERR, "[fbgui] ERROR Server closed");
+ }
+ */
+}
+
+
+
+void logToQt(int status, int substatus, const char * msg) {
+ if (retval >= 0) {
+ log_msg lm;
+ lm.status = status;
+ lm.substatus = substatus;
+ snprintf(lm.msg, sizeof(lm.msg), "%s", msg);
+ snprintf(lm.device, sizeof(lm.device), "%s", interfaceName);
+ sendToQt(&lm);
+ }
+}
+
+
+
+void logSendToQt(int type) {
+ switch (type) {
+ case DHCP_DISCOVER:
+ logToQt(LOG_INFO, DHCP_DISCOVER, "send discover");
+ break;
+ case DHCP_OFFER:
+ logToQt(LOG_INFO, DHCP_OFFER, "send offer");
+ break;
+ case DHCP_REQUEST:
+ logToQt(LOG_INFO, DHCP_REQUEST, "send request");
+ break;
+ case DHCP_DECLINE:
+ logToQt(LOG_INFO, DHCP_DECLINE, "send decline");
+ break;
+ case DHCP_ACK:
+ logToQt(LOG_INFO, DHCP_ACK, "send ack");
+ break;
+ case DHCP_NAK:
+ logToQt(LOG_INFO, DHCP_NAK, "send nak");
+ break;
+ case DHCP_RELEASE:
+ logToQt(LOG_INFO, DHCP_RELEASE, "send release");
+ break;
+ case DHCP_INFORM:
+ logToQt(LOG_INFO, DHCP_INFORM, "send inform");
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+static void print_addresses (FILE *f, const struct address_head *addresses)
+{
+ const address_t *addr;
+
+ STAILQ_FOREACH (addr, addresses, entries) {
+ fprintf (f, "%s", inet_ntoa (addr->address));
+ if (STAILQ_NEXT (addr, entries))
+ fprintf (f, " ");
+ }
+}
+
+
+
+void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp) {
+ /*void logGatewayToFile(const interface_t iface, const dhcp_t *dhcp,
+ const options_t options)*/
+ //char path[QTSOCKETADDRESSLENGTH];
+
+ /*
+ strcpy(path, DEFAULT_GATEWAY_INFO_LOCATION);
+ strcat(path, iface.name);
+ strcpy(iface.infofile, path);
+ options.test = false;
+ syslog(LOG_INFO, "[fbgui] try to open file: %s", iface.infofile);
+ write_info(&iface, dhcp, &options, true);
+ */
+ FILE *f;
+ route_t *route;
+ char path[QTSOCKETADDRESSLENGTH];
+
+ strcpy(path, DEFAULT_INTERFACE_CONF_LOCATION);
+ strcat(path, iface->name);
+
+ syslog(LOG_INFO, "[fbgui] try to open file: %s", path);
+
+ logger(LOG_DEBUG, "writing %s", iface->infofile);
+ if ((f = fopen(path, "w")) == NULL) {
+ logger(LOG_ERR, "fopen `%s': %s", path, strerror(errno));
+ //TODO: exit/return ..
+ return;
+ }
+
+ if (dhcp->address.s_addr) {
+ struct in_addr n;
+ n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
+ fprintf(f, "IPADDR='%s'\n", inet_ntoa(dhcp->address));
+ fprintf(f, "NETMASK='%s'\n", inet_ntoa(dhcp->netmask));
+ fprintf(f, "NETWORK='%s'\n", inet_ntoa(n));
+ fprintf(f, "BROADCAST='%s'\n", inet_ntoa(dhcp->broadcast));
+ }
+
+ if (dhcp->routes) {
+ bool doneone = false;
+ fprintf(f, "ROUTES='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr != 0) {
+ if (doneone)
+ fprintf(f, " ");
+ fprintf(f, "%s", inet_ntoa(route->destination));
+ fprintf(f, ",%s", inet_ntoa(route->netmask));
+ fprintf(f, ",%s", inet_ntoa(route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf(f, "'\n");
+
+ doneone = false;
+ fprintf(f, "GATEWAYS='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr == 0) {
+ if (doneone)
+ fprintf(f, " ");
+ fprintf(f, "%s", inet_ntoa(route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf(f, "'\n");
+ }
+
+ fprintf(f, "HOSTNAME='%s", dhcp->hostname);
+ fprintf(f, "'\n");
+ fprintf(f, "DNSSEARCH='%s", dhcp->dnssearch);
+ fprintf(f, "'\n");
+
+ if (dhcp->dnsservers) {
+ fprintf(f, "DNSSERVERS='");
+ print_addresses(f, dhcp->dnsservers);
+ fprintf(f, "'\n");
+ }
+ fprintf(f, "INTERFACE='%s", iface->name);
+ fprintf(f, "'\n");
+ if (iface->clientid_len > 0) {
+ fprintf(f, "CLIENTID='%s'\n", hwaddr_ntoa(iface->clientid,
+ iface->clientid_len));
+ }
+ fprintf(f, "DHCPCHADDR='%s'\n", hwaddr_ntoa(iface->hwaddr, iface->hwlen));
+ fclose(f);
+}
diff --git a/src/customdhcpcd/logwriter.h b/src/customdhcpcd/logwriter.h
new file mode 100644
index 0000000..43f35fa
--- /dev/null
+++ b/src/customdhcpcd/logwriter.h
@@ -0,0 +1,40 @@
+/*
+ * logwriter.h
+ *
+ * Created on: Jul 7, 2011
+ * Author: niklas
+ */
+
+#ifndef LOGWRITER_H_
+#define LOGWRITER_H_
+
+#include <arpa/inet.h>
+#include "dhcp.h"
+#include "interface.h"
+#include "dhcpcd.h"
+
+#define LOG_MSG_SIZE 1024
+
+typedef struct _log_msg log_msg;
+struct _log_msg {
+ int status;
+ int substatus;
+ char device[IF_NAMESIZE];
+ char msg[LOG_MSG_SIZE];
+};
+
+/**
+ * new functions for communicating with Qt
+ */
+void setSocketName(const char * sn);
+void setInterfaceName(const char * in);
+int initQtLoggerSocket ();
+void closeQtLoggerSocket ();
+void sendToQt ();
+void logToQt(int status, int substatus, const char * msg);
+void logSendToQt(int type);
+void logLoggerToQt(int level, const char *fmt, ...);
+//void logToQt(char * status, char * substatus, char * msg);
+void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp);
+
+#endif /* LOGWRITER_H_ */
diff --git a/src/customdhcpcd/signal.c b/src/customdhcpcd/signal.c
new file mode 100644
index 0000000..9055c9f
--- /dev/null
+++ b/src/customdhcpcd/signal.c
@@ -0,0 +1,183 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "logger.h"
+#include "signal.h"
+
+static int signal_pipe[2];
+static int signals[5];
+
+static const int handle_sigs[] = {
+ SIGHUP,
+ SIGALRM,
+ SIGTERM,
+ SIGINT
+};
+
+static void signal_handler (int sig)
+{
+ unsigned int i = 0;
+ int serrno = errno;
+
+ /* Add a signal to our stack */
+ while (signals[i])
+ i++;
+ if (i > sizeof (signals) / sizeof (signals[0]))
+ logger (LOG_ERR, "signal buffer overrun");
+ else
+ signals[i] = sig;
+
+ if (write (signal_pipe[1], &sig, sizeof (sig)) == -1)
+ logger (LOG_ERR, "Could not send signal: %s", strerror (errno));
+
+ /* Restore errno */
+ errno = serrno;
+}
+
+int signal_fd (void)
+{
+ return (signal_pipe[0]);
+}
+
+/* Check if we have a signal or not */
+int signal_exists (const struct pollfd *fd)
+{
+ if (signals[0] || (fd && fd->revents & POLLIN))
+ return (0);
+ return (-1);
+}
+
+/* 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 signal_read (struct pollfd *fd)
+{
+ int sig = -1;
+
+ /* Pop a signal off the our stack */
+ if (signals[0]) {
+ unsigned int i = 0;
+ sig = signals[0];
+ while (i < (sizeof (signals) / sizeof (signals[0])) - 1) {
+ signals[i] = signals[i + 1];
+ if (! signals[++i])
+ break;
+ }
+ }
+
+ if (fd && fd->revents & POLLIN) {
+ char buf[16];
+ size_t bytes;
+
+ memset (buf, 0, sizeof (buf));
+ bytes = read (signal_pipe[0], buf, sizeof (buf));
+
+ if (bytes >= sizeof (sig))
+ memcpy (&sig, buf, sizeof (sig));
+
+ /* We need to clear us from rset if nothing left in the buffer
+ * in case we are called many times */
+ if (bytes == sizeof (sig))
+ fd->revents = 0;
+ }
+
+ return (sig);
+}
+
+/* Call this before doing anything else. Sets up the socket pair
+ * and installs the signal handler */
+int signal_init (void)
+{
+ struct sigaction sa;
+
+ if (pipe (signal_pipe) == -1) {
+ logger (LOG_ERR, "pipe: %s", strerror (errno));
+ return (-1);
+ }
+
+ /* Stop any scripts from inheriting us */
+ close_on_exec (signal_pipe[0]);
+ close_on_exec (signal_pipe[1]);
+
+ /* Ignore child signals and don't make zombies.
+ * Because we do this, we don't need to be in signal_setup */
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT;
+ if (sigaction (SIGCHLD, &sa, NULL) == -1) {
+ logger (LOG_ERR, "sigaction: %s", strerror (errno));
+ return (-1);
+ }
+
+ memset (signals, 0, sizeof (signals));
+ return (0);
+}
+
+int signal_setup (void)
+{
+ unsigned int i;
+ struct sigaction sa;
+
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_handler = signal_handler;
+ sigemptyset (&sa.sa_mask);
+
+ for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++)
+ if (sigaction (handle_sigs[i], &sa, NULL) == -1) {
+ logger (LOG_ERR, "sigaction: %s", strerror (errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int signal_reset (void)
+{
+ struct sigaction sa;
+ unsigned int i;
+
+ memset (&sa, 0, sizeof (sa));
+ sa.sa_handler = SIG_DFL;
+ sigemptyset (&sa.sa_mask);
+
+ for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++)
+ if (sigaction (handle_sigs[i], &sa, NULL) == -1) {
+ logger (LOG_ERR, "sigaction: %s", strerror (errno));
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/src/customdhcpcd/signal.h b/src/customdhcpcd/signal.h
new file mode 100644
index 0000000..63a5906
--- /dev/null
+++ b/src/customdhcpcd/signal.h
@@ -0,0 +1,40 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SIGNAL_H
+#define SIGNAL_H
+
+#include <poll.h>
+
+int signal_init (void);
+int signal_setup (void);
+int signal_reset (void);
+int signal_fd (void);
+int signal_exists (const struct pollfd *fd);
+int signal_read (struct pollfd *fd);
+
+#endif
diff --git a/src/customdhcpcd/socket.c b/src/customdhcpcd/socket.c
new file mode 100644
index 0000000..58ad6c5
--- /dev/null
+++ b/src/customdhcpcd/socket.c
@@ -0,0 +1,647 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#define __FAVOR_BSD /* Nasty hack so we can use BSD semantics for UDP */
+#include <netinet/udp.h>
+#undef __FAVOR_BSD
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(BSD) || defined(__FreeBSD_kernel__)
+# include <net/bpf.h>
+#elif __linux__
+# include <linux/filter.h>
+# include <netpacket/packet.h>
+# define bpf_insn sock_filter
+#endif
+
+#include "config.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+#include "socket.h"
+
+/* A suitably large buffer for all transactions.
+ * BPF buffer size is set by the kernel, so no define. */
+#ifdef __linux__
+# define BUFFER_LENGTH 4096
+#endif
+
+/* Broadcast address for IPoIB */
+static const uint8_t ipv4_bcast_addr[] = {
+ 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+/* Credit where credit is due :)
+ * The below BPF filter is taken from ISC DHCP */
+static struct bpf_insn dhcp_bpf_filter [] = {
+ /* Make sure this is an IP packet... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
+
+ /* Make sure it's a UDP packet... */
+ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
+
+ /* Make sure this isn't a fragment... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
+
+ /* Get the IP header length... */
+ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
+
+ /* Make sure it's to the right port... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT (BPF_RET + BPF_K, ~0U),
+
+ /* Otherwise, drop it. */
+ BPF_STMT (BPF_RET + BPF_K, 0),
+};
+
+static struct bpf_insn arp_bpf_filter [] = {
+ /* Make sure this is an ARP packet... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3),
+
+ /* Make sure this is an ARP REPLY... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1),
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT (BPF_RET + BPF_K, ~0U),
+
+ /* Otherwise, drop it. */
+ BPF_STMT (BPF_RET + BPF_K, 0),
+};
+
+void setup_packet_filters (void)
+{
+#ifdef __linux__
+ /* We need to massage the filters for Linux cooked packets */
+ dhcp_bpf_filter[1].jf = 0; /* skip the IP packet type check */
+ dhcp_bpf_filter[2].k -= ETH_HLEN;
+ dhcp_bpf_filter[4].k -= ETH_HLEN;
+ dhcp_bpf_filter[6].k -= ETH_HLEN;
+ dhcp_bpf_filter[7].k -= ETH_HLEN;
+
+ arp_bpf_filter[1].jf = 0; /* skip the IP packet type check */
+ arp_bpf_filter[2].k -= ETH_HLEN;
+#endif
+}
+
+static uint16_t checksum (unsigned char *addr, uint16_t len)
+{
+ uint32_t sum = 0;
+ union
+ {
+ unsigned char *addr;
+ uint16_t *i;
+ } p;
+ uint16_t nleft = len;
+
+ p.addr = addr;
+ while (nleft > 1) {
+ sum += *p.i++;
+ nleft -= 2;
+ }
+
+ if (nleft == 1) {
+ uint8_t a = 0;
+ memcpy (&a, p.i, 1);
+ sum += ntohs (a) << 8;
+ }
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return ~sum;
+}
+
+void make_dhcp_packet(struct udp_dhcp_packet *packet,
+ const unsigned char *data, size_t length,
+ struct in_addr source, struct in_addr dest)
+{
+ struct ip *ip = &packet->ip;
+ struct udphdr *udp = &packet->udp;
+
+ /* OK, this is important :)
+ * We copy the data to our packet and then create a small part of the
+ * ip structure and an invalid ip_len (basically udp length).
+ * We then fill the udp structure and put the checksum
+ * of the whole packet into the udp checksum.
+ * Finally we complete the ip structure and ip checksum.
+ * If we don't do the ordering like so then the udp checksum will be
+ * broken, so find another way of doing it! */
+
+ memcpy (&packet->dhcp, data, length);
+
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_src.s_addr = source.s_addr;
+ if (dest.s_addr == 0)
+ ip->ip_dst.s_addr = INADDR_BROADCAST;
+ else
+ ip->ip_dst.s_addr = dest.s_addr;
+
+ udp->uh_sport = htons (DHCP_CLIENT_PORT);
+ udp->uh_dport = htons (DHCP_SERVER_PORT);
+ udp->uh_ulen = htons (sizeof (*udp) + length);
+ ip->ip_len = udp->uh_ulen;
+ udp->uh_sum = checksum ((unsigned char *) packet, sizeof (*packet));
+
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = 5;
+ ip->ip_id = 0;
+ ip->ip_tos = IPTOS_LOWDELAY;
+ ip->ip_len = htons (sizeof (*ip) + sizeof (*udp) + length);
+ ip->ip_id = 0;
+ ip->ip_off = htons (IP_DF); /* Don't fragment */
+ ip->ip_ttl = IPDEFTTL;
+
+ ip->ip_sum = checksum ((unsigned char *) ip, sizeof (*ip));
+}
+
+static int valid_dhcp_packet (unsigned char *data)
+{
+ union
+ {
+ unsigned char *data;
+ struct udp_dhcp_packet *packet;
+ } d;
+ uint16_t bytes;
+ uint16_t ipsum;
+ uint16_t iplen;
+ uint16_t udpsum;
+ struct in_addr source;
+ struct in_addr dest;
+ int retval = 0;
+
+ d.data = data;
+ bytes = ntohs (d.packet->ip.ip_len);
+ ipsum = d.packet->ip.ip_sum;
+ iplen = d.packet->ip.ip_len;
+ udpsum = d.packet->udp.uh_sum;
+
+ d.data = data;
+ d.packet->ip.ip_sum = 0;
+ if (ipsum != checksum ((unsigned char *) &d.packet->ip,
+ sizeof (d.packet->ip)))
+ {
+ logger (LOG_DEBUG, "bad IP header checksum, ignoring");
+ retval = -1;
+ goto eexit;
+ }
+
+ memcpy (&source, &d.packet->ip.ip_src, sizeof (d.packet->ip.ip_src));
+ memcpy (&dest, &d.packet->ip.ip_dst, sizeof (d.packet->ip.ip_dst));
+ memset (&d.packet->ip, 0, sizeof (d.packet->ip));
+ d.packet->udp.uh_sum = 0;
+
+ d.packet->ip.ip_p = IPPROTO_UDP;
+ memcpy (&d.packet->ip.ip_src, &source, sizeof (d.packet->ip.ip_src));
+ memcpy (&d.packet->ip.ip_dst, &dest, sizeof (d.packet->ip.ip_dst));
+ d.packet->ip.ip_len = d.packet->udp.uh_ulen;
+ if (udpsum && udpsum != checksum (d.data, bytes)) {
+ logger (LOG_ERR, "bad UDP checksum, ignoring");
+ retval = -1;
+ }
+
+eexit:
+ d.packet->ip.ip_sum = ipsum;
+ d.packet->ip.ip_len = iplen;
+ d.packet->udp.uh_sum = udpsum;
+
+ return retval;
+}
+
+#if defined(BSD) || defined(__FreeBSD_kernel__)
+int open_socket (interface_t *iface, int protocol)
+{
+ int n = 0;
+ int fd = -1;
+ char *device;
+ int flags;
+ struct ifreq ifr;
+ int buf = 0;
+ struct bpf_program pf;
+
+ device = xmalloc (sizeof (char) * PATH_MAX);
+ do {
+ snprintf (device, PATH_MAX, "/dev/bpf%d", n++);
+ fd = open (device, O_RDWR);
+ } while (fd == -1 && errno == EBUSY);
+ free (device);
+
+ if (fd == -1) {
+ logger (LOG_ERR, "unable to open a BPF device");
+ return -1;
+ }
+
+ close_on_exec (fd);
+
+ memset (&ifr, 0, sizeof (ifr));
+ strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name));
+ if (ioctl (fd, BIOCSETIF, &ifr) == -1) {
+ logger (LOG_ERR,
+ "cannot attach interface `%s' to bpf device `%s': %s",
+ iface->name, device, strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ /* Get the required BPF buffer length from the kernel. */
+ if (ioctl (fd, BIOCGBLEN, &buf) == -1) {
+ logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+ iface->buffer_length = buf;
+
+ flags = 1;
+ if (ioctl (fd, BIOCIMMEDIATE, &flags) == -1) {
+ logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ /* Install the DHCP filter */
+ if (protocol == ETHERTYPE_ARP) {
+ pf.bf_insns = arp_bpf_filter;
+ pf.bf_len = sizeof (arp_bpf_filter)
+ / sizeof (arp_bpf_filter[0]);
+ } else {
+ pf.bf_insns = dhcp_bpf_filter;
+ pf.bf_len = sizeof (dhcp_bpf_filter)
+ / sizeof (dhcp_bpf_filter[0]);
+ }
+ if (ioctl (fd, BIOCSETF, &pf) == -1) {
+ logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ if (iface->fd > -1)
+ close (iface->fd);
+ iface->fd = fd;
+
+ return fd;
+}
+
+ssize_t send_packet (const interface_t *iface, int type,
+ const unsigned char *data, size_t len)
+{
+ ssize_t retval = -1;
+ struct iovec iov[2];
+
+ if (iface->family == ARPHRD_ETHER) {
+ struct ether_header hw;
+ memset (&hw, 0, sizeof (hw));
+ memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
+ hw.ether_type = htons (type);
+
+ iov[0].iov_base = &hw;
+ iov[0].iov_len = sizeof (hw);
+ } else {
+ logger (LOG_ERR, "unsupported interace type %d", iface->family);
+ return -1;
+ }
+ iov[1].iov_base = (unsigned char *) data;
+ iov[1].iov_len = len;
+
+ if ((retval = writev(iface->fd, iov, 2)) == -1)
+ logger (LOG_ERR, "writev: %s", strerror (errno));
+
+ return retval;
+}
+
+/* BPF requires that we read the entire buffer.
+ * So we pass the buffer in the API so we can loop on >1 dhcp packet. */
+ssize_t get_packet (const interface_t *iface, unsigned char *data,
+ unsigned char *buffer,
+ size_t *buffer_len, size_t *buffer_pos)
+{
+ union
+ {
+ unsigned char *buffer;
+ struct bpf_hdr *packet;
+ } bpf;
+
+ bpf.buffer = buffer;
+
+ if (*buffer_pos < 1) {
+ memset (bpf.buffer, 0, iface->buffer_length);
+ *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length);
+ *buffer_pos = 0;
+ if (*buffer_len < 1) {
+ struct timespec ts;
+ logger (LOG_ERR, "read: %s", strerror (errno));
+ ts.tv_sec = 3;
+ ts.tv_nsec = 0;
+ nanosleep (&ts, NULL);
+ return (-1);
+ }
+ } else
+ bpf.buffer += *buffer_pos;
+
+ while (bpf.packet) {
+ size_t len = 0;
+ union
+ {
+ unsigned char *buffer;
+ struct ether_header *hw;
+ } hdr;
+ unsigned char *payload;
+ bool have_data = false;
+
+ /* Ensure that the entire packet is in our buffer */
+ if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen
+ > (unsigned) *buffer_len)
+ break;
+
+ hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen;
+ payload = hdr.buffer + sizeof (*hdr.hw);
+
+ /* If it's an ARP reply, then just send it back */
+ if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) {
+ len = bpf.packet->bh_caplen -
+ sizeof (*hdr.hw);
+ memcpy (data, payload, len);
+ have_data = true;
+ } else {
+ if (valid_dhcp_packet (payload) >= 0) {
+ union
+ {
+ unsigned char *buffer;
+ struct udp_dhcp_packet *packet;
+ } pay;
+ pay.buffer = payload;
+ len = ntohs (pay.packet->ip.ip_len) -
+ sizeof (pay.packet->ip) -
+ sizeof (pay.packet->udp);
+ memcpy (data, &pay.packet->dhcp, len);
+ have_data = true;
+ }
+ }
+
+ /* Update the buffer_pos pointer */
+ bpf.buffer += BPF_WORDALIGN (bpf.packet->bh_hdrlen +
+ bpf.packet->bh_caplen);
+ if ((unsigned) (bpf.buffer - buffer) < *buffer_len)
+ *buffer_pos = bpf.buffer - buffer;
+ else
+ *buffer_pos = 0;
+
+ if (have_data)
+ return len;
+
+ if (*buffer_pos == 0)
+ break;
+ }
+
+ /* No valid packets left, so return */
+ *buffer_pos = 0;
+ return -1;
+}
+
+#elif __linux__
+
+int open_socket (interface_t *iface, int protocol)
+{
+ int fd;
+ union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_ll sll;
+ struct sockaddr_storage ss;
+ } su;
+ struct sock_fprog pf;
+ struct ifreq ifr;
+ int n = 1;
+
+ /* We need to bind to a port, otherwise Linux generate ICMP messages
+ * that cannot contect the port when we have an address.
+ * We don't actually use this fd at all, instead using our packet
+ * filter socket. */
+ if (iface->listen_fd == -1 && protocol == ETHERTYPE_IP) {
+ if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ } else {
+ memset (&su, 0, sizeof (su));
+ su.sin.sin_family = AF_INET;
+ su.sin.sin_port = htons (DHCP_CLIENT_PORT);
+ if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
+ &n, sizeof (n)) == -1)
+ logger (LOG_ERR, "SO_REUSEADDR: %s",
+ strerror (errno));
+ if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
+ &n, sizeof (n)) == -1)
+ logger (LOG_ERR, "SO_RCVBUF: %s",
+ strerror (errno));
+ memset (&ifr, 0, sizeof (ifr));
+ strncpy (ifr.ifr_name, iface->name,
+ sizeof (ifr.ifr_name));
+ if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE,
+ &ifr, sizeof (ifr)) == -1)
+ logger (LOG_ERR, "SO_SOBINDTODEVICE: %s",
+ strerror (errno));
+ if (bind (fd, &su.sa, sizeof (su)) == -1) {
+ logger (LOG_ERR, "bind: %s", strerror (errno));
+ close (fd);
+ } else {
+ iface->listen_fd = fd;
+ close_on_exec (fd);
+ }
+ }
+ }
+
+ if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return (-1);
+ }
+ close_on_exec (fd);
+
+ memset (&su, 0, sizeof (su));
+ su.sll.sll_family = PF_PACKET;
+ su.sll.sll_protocol = htons (protocol);
+ if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) {
+ logger (LOG_ERR,
+ "if_nametoindex: no index for interface `%s'",
+ iface->name);
+ close (fd);
+ return (-1);
+ }
+
+ /* Install the DHCP filter */
+ memset (&pf, 0, sizeof (pf));
+ if (protocol == ETHERTYPE_ARP) {
+ pf.filter = arp_bpf_filter;
+ pf.len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]);
+ } else {
+ pf.filter = dhcp_bpf_filter;
+ pf.len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]);
+ }
+ if (setsockopt (fd, SOL_SOCKET, SO_ATTACH_FILTER,
+ &pf, sizeof (pf)) != 0)
+ {
+ logger (LOG_ERR, "SO_ATTACH_FILTER: %s", strerror (errno));
+ close (fd);
+ return (-1);
+ }
+
+ if (bind (fd, &su.sa, sizeof (su)) == -1) {
+ logger (LOG_ERR, "bind: %s", strerror (errno));
+ close (fd);
+ return (-1);
+ }
+
+ if (iface->fd > -1)
+ close (iface->fd);
+ iface->fd = fd;
+ iface->socket_protocol = protocol;
+ iface->buffer_length = BUFFER_LENGTH;
+
+ return (fd);
+}
+
+ssize_t send_packet (const interface_t *iface, int type,
+ const unsigned char *data, size_t len)
+{
+ union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_ll sll;
+ struct sockaddr_storage ss;
+ } su;
+ ssize_t retval;
+
+ if (! iface)
+ return (-1);
+
+ memset (&su, 0, sizeof (su));
+ su.sll.sll_family = AF_PACKET;
+ su.sll.sll_protocol = htons (type);
+
+ if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) {
+ logger (LOG_ERR, "if_nametoindex: no index for interface `%s'",
+ iface->name);
+ return (-1);
+ }
+
+ su.sll.sll_hatype = htons (iface->family);
+ su.sll.sll_halen = iface->hwlen;
+ if (iface->family == ARPHRD_INFINIBAND)
+ memcpy (&su.sll.sll_addr,
+ &ipv4_bcast_addr, sizeof (ipv4_bcast_addr));
+ else
+ memset (&su.sll.sll_addr, 0xff, iface->hwlen);
+
+ if ((retval = sendto (iface->fd, data, len, 0, &su.sa,
+ sizeof (su))) == -1)
+
+ logger (LOG_ERR, "sendto: %s", strerror (errno));
+ return (retval);
+}
+
+/* Linux has no need for the buffer as we can read as much as we want.
+ * We only have the buffer listed to keep the same API. */
+ssize_t get_packet (const interface_t *iface, unsigned char *data,
+ unsigned char *buffer,
+ size_t *buffer_len, size_t *buffer_pos)
+{
+ ssize_t bytes;
+ union
+ {
+ unsigned char *buffer;
+ struct udp_dhcp_packet *packet;
+ } pay;
+
+ /* We don't use the given buffer, but we need to rewind the position */
+ *buffer_pos = 0;
+
+ memset (buffer, 0, iface->buffer_length);
+ bytes = read (iface->fd, buffer, iface->buffer_length);
+
+ if (bytes == -1) {
+ struct timespec ts;
+ logger (LOG_ERR, "read: %s", strerror (errno));
+ ts.tv_sec = 3;
+ ts.tv_nsec = 0;
+ nanosleep (&ts, NULL);
+ return (-1);
+ }
+
+ *buffer_len = bytes;
+ /* If it's an ARP reply, then just send it back */
+ if (iface->socket_protocol == ETHERTYPE_ARP) {
+ memcpy (data, buffer, bytes);
+ return (bytes);
+ }
+
+ if ((unsigned) bytes < (sizeof (pay.packet->ip) +
+ sizeof (pay.packet->udp)))
+ {
+ logger (LOG_DEBUG, "message too short, ignoring");
+ return (-1);
+ }
+
+ pay.buffer = buffer;
+ if (bytes < ntohs (pay.packet->ip.ip_len)) {
+ logger (LOG_DEBUG, "truncated packet, ignoring");
+ return (-1);
+ }
+
+ if (valid_dhcp_packet (buffer) == -1)
+ return (-1);
+
+ bytes = ntohs (pay.packet->ip.ip_len) -
+ (sizeof (pay.packet->ip) + sizeof (pay.packet->udp));
+ memcpy (data, &pay.packet->dhcp, bytes);
+ return (bytes);
+}
+
+#else
+ #error "Platform not supported!"
+ #error "We currently support BPF and Linux sockets."
+ #error "Other platforms may work using BPF. If yours does, please let me know"
+ #error "so I can add it to our list."
+#endif
diff --git a/src/customdhcpcd/socket.h b/src/customdhcpcd/socket.h
new file mode 100644
index 0000000..bdf26d0
--- /dev/null
+++ b/src/customdhcpcd/socket.h
@@ -0,0 +1,46 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include <stdbool.h>
+
+#include "dhcp.h"
+#include "interface.h"
+
+void setup_packet_filters (void);
+void make_dhcp_packet(struct udp_dhcp_packet *packet,
+ const unsigned char *data, size_t length,
+ struct in_addr source, struct in_addr dest);
+
+int open_socket (interface_t *iface, int protocol);
+ssize_t send_packet (const interface_t *iface, int type,
+ const unsigned char *data, size_t len);
+ssize_t get_packet (const interface_t *iface, unsigned char *data,
+ unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos);
+#endif
diff --git a/src/customdhcpcd/version.h b/src/customdhcpcd/version.h
new file mode 100644
index 0000000..9cf5fa4
--- /dev/null
+++ b/src/customdhcpcd/version.h
@@ -0,0 +1 @@
+#define VERSION "3.2.3"
diff --git a/src/downloadmanager.cpp b/src/fbgui/downloadmanager.cpp
index 653bc7b..653bc7b 100644
--- a/src/downloadmanager.cpp
+++ b/src/fbgui/downloadmanager.cpp
diff --git a/src/downloadmanager.h b/src/fbgui/downloadmanager.h
index 62df4bc..62df4bc 100644
--- a/src/downloadmanager.h
+++ b/src/fbgui/downloadmanager.h
diff --git a/src/fbgui.cpp b/src/fbgui/fbgui.cpp
index 22a2ac6..22a2ac6 100644
--- a/src/fbgui.cpp
+++ b/src/fbgui/fbgui.cpp
diff --git a/src/fbgui.h b/src/fbgui/fbgui.h
index ee42469..ee42469 100644
--- a/src/fbgui.h
+++ b/src/fbgui/fbgui.h
diff --git a/src/fbgui.pro b/src/fbgui/fbgui.pro
index 701402b..701402b 100644
--- a/src/fbgui.pro
+++ b/src/fbgui/fbgui.pro
diff --git a/src/fbgui.qrc b/src/fbgui/fbgui.qrc
index a5333c5..a5333c5 100644
--- a/src/fbgui.qrc
+++ b/src/fbgui/fbgui.qrc
diff --git a/src/html/background.png b/src/fbgui/html/background.png
index 7e374f9..7e374f9 100644
--- a/src/html/background.png
+++ b/src/fbgui/html/background.png
Binary files differ
diff --git a/src/html/continueBoot.html b/src/fbgui/html/continueBoot.html
index 89020b7..89020b7 100644
--- a/src/html/continueBoot.html
+++ b/src/fbgui/html/continueBoot.html
diff --git a/src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
index 954e22d..954e22d 100644
--- a/src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
+++ b/src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png b/src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
index 64ece57..64ece57 100644
--- a/src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
+++ b/src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_flat_10_000000_40x100.png b/src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png
index abdc010..abdc010 100644
--- a/src/html/css/images/ui-bg_flat_10_000000_40x100.png
+++ b/src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png b/src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png
index 9b383f4..9b383f4 100644
--- a/src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png
+++ b/src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png b/src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png
index a23baad..a23baad 100644
--- a/src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png
+++ b/src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_glass_65_ffffff_1x400.png b/src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png
index 42ccba2..42ccba2 100644
--- a/src/html/css/images/ui-bg_glass_65_ffffff_1x400.png
+++ b/src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
index 39d5824..39d5824 100644
--- a/src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
+++ b/src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
index f127367..f127367 100644
--- a/src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
+++ b/src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
Binary files differ
diff --git a/src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
index 359397a..359397a 100644
--- a/src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
+++ b/src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
Binary files differ
diff --git a/src/html/css/images/ui-icons_222222_256x240.png b/src/fbgui/html/css/images/ui-icons_222222_256x240.png
index b273ff1..b273ff1 100644
--- a/src/html/css/images/ui-icons_222222_256x240.png
+++ b/src/fbgui/html/css/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/src/html/css/images/ui-icons_228ef1_256x240.png b/src/fbgui/html/css/images/ui-icons_228ef1_256x240.png
index a641a37..a641a37 100644
--- a/src/html/css/images/ui-icons_228ef1_256x240.png
+++ b/src/fbgui/html/css/images/ui-icons_228ef1_256x240.png
Binary files differ
diff --git a/src/html/css/images/ui-icons_ef8c08_256x240.png b/src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png
index 85e63e9..85e63e9 100644
--- a/src/html/css/images/ui-icons_ef8c08_256x240.png
+++ b/src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png
Binary files differ
diff --git a/src/html/css/images/ui-icons_ffd27a_256x240.png b/src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png
index e117eff..e117eff 100644
--- a/src/html/css/images/ui-icons_ffd27a_256x240.png
+++ b/src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png
Binary files differ
diff --git a/src/html/css/images/ui-icons_ffffff_256x240.png b/src/fbgui/html/css/images/ui-icons_ffffff_256x240.png
index 42f8f99..42f8f99 100644
--- a/src/html/css/images/ui-icons_ffffff_256x240.png
+++ b/src/fbgui/html/css/images/ui-icons_ffffff_256x240.png
Binary files differ
diff --git a/src/html/css/jquery-ui-1.8.16.css b/src/fbgui/html/css/jquery-ui-1.8.16.css
index 5547c7b..5547c7b 100644
--- a/src/html/css/jquery-ui-1.8.16.css
+++ b/src/fbgui/html/css/jquery-ui-1.8.16.css
diff --git a/src/html/images/loading.gif b/src/fbgui/html/images/loading.gif
index cbe59fb..cbe59fb 100644
--- a/src/html/images/loading.gif
+++ b/src/fbgui/html/images/loading.gif
Binary files differ
diff --git a/src/html/js/jquery-1.6.4.min.js b/src/fbgui/html/js/jquery-1.6.4.min.js
index 628ed9b..628ed9b 100644
--- a/src/html/js/jquery-1.6.4.min.js
+++ b/src/fbgui/html/js/jquery-1.6.4.min.js
diff --git a/src/html/js/jquery-ui-1.8.16.min.js b/src/fbgui/html/js/jquery-ui-1.8.16.min.js
index 14c9064..14c9064 100644
--- a/src/html/js/jquery-ui-1.8.16.min.js
+++ b/src/fbgui/html/js/jquery-ui-1.8.16.min.js
diff --git a/src/html/js/networkDiscovery.js b/src/fbgui/html/js/networkDiscovery.js
index 2aaea11..2aaea11 100644
--- a/src/html/js/networkDiscovery.js
+++ b/src/fbgui/html/js/networkDiscovery.js
diff --git a/src/html/loadsystem.css b/src/fbgui/html/loadsystem.css
index 6a6e64f..6a6e64f 100644
--- a/src/html/loadsystem.css
+++ b/src/fbgui/html/loadsystem.css
diff --git a/src/html/loadsystem.html b/src/fbgui/html/loadsystem.html
index 838423e..838423e 100644
--- a/src/html/loadsystem.html
+++ b/src/fbgui/html/loadsystem.html
diff --git a/src/html/networkdiscovery.css b/src/fbgui/html/networkdiscovery.css
index cf4121d..cf4121d 100644
--- a/src/html/networkdiscovery.css
+++ b/src/fbgui/html/networkdiscovery.css
diff --git a/src/html/networkdiscovery.html b/src/fbgui/html/networkdiscovery.html
index a1e62ac..a1e62ac 100644
--- a/src/html/networkdiscovery.html
+++ b/src/fbgui/html/networkdiscovery.html
diff --git a/src/html/networkdiscovery_debug.html b/src/fbgui/html/networkdiscovery_debug.html
index 06c1fe7..06c1fe7 100644
--- a/src/html/networkdiscovery_debug.html
+++ b/src/fbgui/html/networkdiscovery_debug.html
diff --git a/src/html/networkdiscovery_userchoice.html b/src/fbgui/html/networkdiscovery_userchoice.html
index 3625fe0..3625fe0 100644
--- a/src/html/networkdiscovery_userchoice.html
+++ b/src/fbgui/html/networkdiscovery_userchoice.html
diff --git a/src/html/networkdiscovery_userchoice_debug.html b/src/fbgui/html/networkdiscovery_userchoice_debug.html
index 88da8b4..88da8b4 100644
--- a/src/html/networkdiscovery_userchoice_debug.html
+++ b/src/fbgui/html/networkdiscovery_userchoice_debug.html
diff --git a/src/html/old.png b/src/fbgui/html/old.png
index 84dd7b3..84dd7b3 100644
--- a/src/html/old.png
+++ b/src/fbgui/html/old.png
Binary files differ
diff --git a/src/html/preload-debug.html b/src/fbgui/html/preload-debug.html
index 29d7391..29d7391 100644
--- a/src/html/preload-debug.html
+++ b/src/fbgui/html/preload-debug.html
diff --git a/src/html/preload.css b/src/fbgui/html/preload.css
index e1eff68..e1eff68 100644
--- a/src/html/preload.css
+++ b/src/fbgui/html/preload.css
diff --git a/src/html/preload.html b/src/fbgui/html/preload.html
index bc0abd9..bc0abd9 100644
--- a/src/html/preload.html
+++ b/src/fbgui/html/preload.html
diff --git a/src/interfaceconfiguration.cpp b/src/fbgui/interfaceconfiguration.cpp
index 3d09e52..3d09e52 100644
--- a/src/interfaceconfiguration.cpp
+++ b/src/fbgui/interfaceconfiguration.cpp
diff --git a/src/interfaceconfiguration.h b/src/fbgui/interfaceconfiguration.h
index 475f689..475f689 100644
--- a/src/interfaceconfiguration.h
+++ b/src/fbgui/interfaceconfiguration.h
diff --git a/src/javascriptinterface.cpp b/src/fbgui/javascriptinterface.cpp
index b45a2f9..b45a2f9 100644
--- a/src/javascriptinterface.cpp
+++ b/src/fbgui/javascriptinterface.cpp
diff --git a/src/javascriptinterface.h b/src/fbgui/javascriptinterface.h
index cf2ec5b..cf2ec5b 100644
--- a/src/javascriptinterface.h
+++ b/src/fbgui/javascriptinterface.h
diff --git a/src/loggerengine.cpp b/src/fbgui/loggerengine.cpp
index 8a0991d..8a0991d 100644
--- a/src/loggerengine.cpp
+++ b/src/fbgui/loggerengine.cpp
diff --git a/src/loggerengine.h b/src/fbgui/loggerengine.h
index 1dfae4e..1dfae4e 100644
--- a/src/loggerengine.h
+++ b/src/fbgui/loggerengine.h
diff --git a/src/main.cpp b/src/fbgui/main.cpp
index a187d01..a187d01 100644
--- a/src/main.cpp
+++ b/src/fbgui/main.cpp
diff --git a/src/ndgui.cpp b/src/fbgui/ndgui.cpp
index 3034051..3034051 100644
--- a/src/ndgui.cpp
+++ b/src/fbgui/ndgui.cpp
diff --git a/src/ndgui.h b/src/fbgui/ndgui.h
index 41a7bbf..41a7bbf 100644
--- a/src/ndgui.h
+++ b/src/fbgui/ndgui.h
diff --git a/src/networkdiscovery.cpp b/src/fbgui/networkdiscovery.cpp
index 132429c..132429c 100644
--- a/src/networkdiscovery.cpp
+++ b/src/fbgui/networkdiscovery.cpp
diff --git a/src/networkdiscovery.h b/src/fbgui/networkdiscovery.h
index c422b18..c422b18 100644
--- a/src/networkdiscovery.h
+++ b/src/fbgui/networkdiscovery.h
diff --git a/src/networkmanager.cpp b/src/fbgui/networkmanager.cpp
index 2dc774f..2dc774f 100644
--- a/src/networkmanager.cpp
+++ b/src/fbgui/networkmanager.cpp
diff --git a/src/networkmanager.h b/src/fbgui/networkmanager.h
index fbb8993..fbb8993 100644
--- a/src/networkmanager.h
+++ b/src/fbgui/networkmanager.h
diff --git a/src/sysinfo.cpp b/src/fbgui/sysinfo.cpp
index 7d6ac92..7d6ac92 100644
--- a/src/sysinfo.cpp
+++ b/src/fbgui/sysinfo.cpp
diff --git a/src/sysinfo.h b/src/fbgui/sysinfo.h
index c860cca..c860cca 100644
--- a/src/sysinfo.h
+++ b/src/fbgui/sysinfo.h