aboutsummaryrefslogtreecommitdiff
path: root/net/isc-dhcp40-server/files/extra-patch-client::dhclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/isc-dhcp40-server/files/extra-patch-client::dhclient.c')
-rw-r--r--net/isc-dhcp40-server/files/extra-patch-client::dhclient.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/net/isc-dhcp40-server/files/extra-patch-client::dhclient.c b/net/isc-dhcp40-server/files/extra-patch-client::dhclient.c
new file mode 100644
index 000000000000..6ad84bfa9e13
--- /dev/null
+++ b/net/isc-dhcp40-server/files/extra-patch-client::dhclient.c
@@ -0,0 +1,545 @@
+--- client/dhclient.c.orig Sat Apr 26 23:51:39 2003
++++ client/dhclient.c Wed Mar 3 16:21:02 2004
+@@ -47,6 +47,13 @@
+ #include "dhcpd.h"
+ #include "version.h"
+
++#ifdef __FreeBSD__
++#include <sys/ioctl.h>
++#include <net/if_media.h>
++#include <net80211/ieee80211_ioctl.h>
++#include <net80211/ieee80211.h>
++#endif
++
+ TIME cur_time;
+ TIME default_lease_time = 43200; /* 12 hours... */
+ TIME max_lease_time = 86400; /* 24 hours... */
+@@ -82,8 +89,11 @@
+ struct string_list *client_env=NULL;
+ int client_env_count=0;
+ int onetry=0;
+-int quiet=0;
++int quiet=1;
+ int nowait=0;
++#ifdef ENABLE_POLLING_MODE
++int polling_interval = 5;
++#endif
+
+ static void usage PROTO ((void));
+
+@@ -184,6 +194,9 @@
+ } else if (!strcmp (argv [i], "-q")) {
+ quiet = 1;
+ quiet_interface_discovery = 1;
++ } else if (!strcmp (argv [i], "-v")) {
++ quiet = 0;
++ quiet_interface_discovery = 0;
+ } else if (!strcmp (argv [i], "-s")) {
+ if (++i == argc)
+ usage ();
+@@ -197,6 +210,19 @@
+ } else if (!strcmp (argv [i], "-n")) {
+ /* do not start up any interfaces */
+ interfaces_requested = 1;
++#ifdef ENABLE_POLLING_MODE
++ } else if (!strcmp (argv [i], "-i")) {
++ if (++i == argc)
++ usage ();
++ polling_interval = (int)strtol (argv [i],
++ (char **)NULL, 10);
++ if (polling_interval <= 0) {
++ log_info ("Incorrect polling interval %d",
++ polling_interval);
++ log_info ("Using a default of 5 seconds");
++ polling_interval = 5;
++ }
++#endif
+ } else if (!strcmp (argv [i], "-w")) {
+ /* do not exit if there are no broadcast interfaces. */
+ persist = 1;
+@@ -225,7 +251,16 @@
+ if (strlen (argv [i]) > sizeof tmp -> name)
+ log_fatal ("%s: interface name too long (max %ld)",
+ argv [i], (long)strlen (argv [i]));
+- strcpy (tmp -> name, argv [i]);
++ strlcpy (tmp -> name, argv [i], IFNAMSIZ);
++#ifdef __FreeBSD__
++ set_ieee80211 (tmp);
++#endif
++ /* Init some interface vars, enable polling */
++#ifdef ENABLE_POLLING_MODE
++ tmp -> forcediscover = 0;
++ tmp -> linkstate = HAVELINK;
++ tmp -> polling = 1;
++#endif /* ifdef ENABLE_POLLING_MODE */
+ if (interfaces) {
+ interface_reference (&tmp -> next,
+ interfaces, MDL);
+@@ -385,6 +420,16 @@
+ INTERFACE_AUTOMATIC)) !=
+ INTERFACE_REQUESTED))
+ continue;
++#ifdef __FreeBSD__
++ set_ieee80211 (ip);
++#endif
++#ifdef ENABLE_POLLING_MODE
++ ip -> forcediscover = 0;
++ if (ip -> client -> config -> media != NULL)
++ ip -> havemedia = 1;
++ else
++ ip -> havemedia = 0;
++#endif
+ script_init (ip -> client,
+ "PREINIT", (struct string_list *)0);
+ if (ip -> client -> alias)
+@@ -427,8 +472,13 @@
+ client -> state = S_INIT;
+ /* Set up a timeout to start the initialization
+ process. */
++#ifdef ENABLE_POLLING_MODE
++ add_timeout (cur_time + random () % 5 + 2,
++ state_polling, client, 0, 0);
++#else
+ add_timeout (cur_time + random () % 5,
+ state_reboot, client, 0, 0);
++#endif
+ }
+ }
+ }
+@@ -486,9 +536,9 @@
+ log_info (arr);
+ log_info (url);
+
+- log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s",
+- "[-s server]");
+- log_error (" [-cf config-file] [-lf lease-file]%s",
++ log_error ("Usage: dhclient [-1Ddqrv] [-i polling-interval] %s",
++ "[-nw] [-p <port>] [-s server]");
++ log_error (" [-cf config-file] [-lf lease-file] %s",
+ "[-pf pid-file] [-e VAR=val]");
+ log_fatal (" [-sf script-file] [interface]");
+ }
+@@ -876,6 +926,15 @@
+ /* Write out the new lease. */
+ write_client_lease (client, client -> new, 0, 0);
+
++ /*
++ * It's now possible that state_reboot can be called
++ * after a interface link went down and is up again.
++ * To prevent tons of equal leases saved on disk, we rewrite
++ * them.
++ */
++ read_client_leases ();
++ rewrite_client_leases ();
++
+ /* Replace the old active lease with the new one. */
+ if (client -> active)
+ destroy_client_lease (client -> active);
+@@ -890,6 +949,12 @@
+ piaddr (client -> active -> address),
+ (long)(client -> active -> renewal - cur_time));
+ client -> state = S_BOUND;
++#ifdef ENABLE_POLLING_MODE
++ /* Init some interface vars, enable polling */
++ client -> interface -> linkstate = HAVELINK;
++ client -> interface -> forcediscover = 0;
++ client -> interface -> polling = 1;
++#endif /* ifdef ENABLE_POLLING_MODE */
+ reinitialize_interfaces ();
+ go_daemon ();
+ if (client -> config -> do_forward_update) {
+@@ -1352,6 +1417,11 @@
+ int interval;
+ int increase = 1;
+
++#ifdef ENABLE_POLLING_MODE
++ /* Disable polling for this interface */
++ client -> interface -> polling = 0;
++#endif
++
+ /* Figure out how long it's been since we started transmitting. */
+ interval = cur_time - client -> first_sending;
+
+@@ -1457,6 +1527,9 @@
+ struct client_lease *loop;
+ struct client_lease *lp;
+
++ if (client -> interface -> linkstate == NOLINK)
++ return;
++
+ loop = lp = client -> active;
+
+ log_info ("No DHCPOFFERS received.");
+@@ -1489,6 +1562,10 @@
+ log_info ("bound: renewal in %ld %s.",
+ (long)(client -> active -> renewal -
+ cur_time), "seconds");
++#ifdef ENABLE_POLLING_MODE
++ /* Enable polling for this interface */
++ client -> interface -> polling = 1;
++#endif
+ add_timeout (client -> active -> renewal,
+ state_bound, client, 0, 0);
+ } else {
+@@ -1496,6 +1573,11 @@
+ log_info ("bound: immediate renewal.");
+ state_bound (client);
+ }
++ /*
++ * Set the link status back to nolink, even
++ * if we have media settings.
++ */
++ client -> interface -> linkstate = NOLINK;
+ reinitialize_interfaces ();
+ go_daemon ();
+ return;
+@@ -1541,6 +1623,12 @@
+ }
+
+ log_info ("No working leases in persistent database - sleeping.");
++
++#ifdef ENABLE_POLLING_MODE
++ /* Enable polling for this interface */
++ client -> interface -> polling = 1;
++#endif
++
+ script_init (client, "FAIL", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_", client -> alias);
+@@ -1681,6 +1769,18 @@
+ client -> packet.secs = htons (65535);
+ }
+
++ /*
++ * Only try the first ten seconds to renew a lease from a
++ * given dhcp-server adress. After that, fall back to use
++ * state_reboot with INADDR_BROADCAST.
++ */
++ if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
++ (client -> state == S_RENEWING || client -> state == S_REBINDING)) {
++ if (client -> active && client -> active -> expiry > cur_time &&
++ interval >= 10)
++ goto cancel;
++ }
++
+ log_info ("DHCPREQUEST on %s to %s port %d",
+ client -> name ? client -> name : client -> interface -> name,
+ inet_ntoa (destination.sin_addr),
+@@ -1702,6 +1802,16 @@
+ from, &destination,
+ (struct hardware *)0);
+
++ /*
++ * If sendto() for a direct request fails, fall back to use
++ * state_reboot with INADDR_BROADCAST.
++ */
++ if (result == -1 && destination.sin_addr.s_addr != INADDR_BROADCAST &&
++ (client -> state == S_RENEWING || client -> state == S_REBINDING)) {
++ if (client -> active && client -> active -> expiry > cur_time)
++ goto cancel;
++ }
++
+ add_timeout (cur_time + client -> interval,
+ send_request, client, 0, 0);
+ }
+@@ -2597,6 +2707,13 @@
+ wstatus = 0;
+ }
+ } else {
++ if ((i = open(_PATH_DEVNULL, O_RDWR)) != -1) {
++ dup2(i, STDIN_FILENO);
++ dup2(i, STDOUT_FILENO);
++ dup2(i, STDERR_FILENO);
++ if (i > STDERR_FILENO)
++ close(i);
++ }
+ execve (scriptName, argv, envp);
+ log_error ("execve (%s, ...): %m", scriptName);
+ exit (0);
+@@ -2783,8 +2900,10 @@
+ case S_STOPPED:
+ break;
+ }
++#ifndef ENABLE_POLLING_MODE
+ client -> state = S_INIT;
+ state_reboot (client);
++#endif
+ }
+ }
+ }
+@@ -3010,7 +3129,9 @@
+ break;
+
+ case server_awaken:
++#ifndef ENABLE_POLLING_MODE
+ state_reboot (client);
++#endif
+ break;
+ }
+ }
+@@ -3147,3 +3268,265 @@
+ data_string_forget (&ddns_dhcid, MDL);
+ return rcode;
+ }
++
++/* Check to see if there's a wire plugged in */
++int
++interface_active(struct interface_info *ip) {
++#ifdef __FreeBSD__
++ struct ifmediareq ifmr;
++ int *media_list, i;
++ char *ifname;
++ int sock;
++
++ ifname = ip -> name;
++
++ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
++ log_fatal ("Can't create interface_active socket");
++
++ (void) memset (&ifmr, 0, sizeof (ifmr));
++ (void) strncpy (ifmr.ifm_name, ifname, sizeof (ifmr.ifm_name));
++
++ if (ioctl (sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
++ /*
++ * Interface doesn't support SIOCGIFMEDIA, presume okay
++ */
++ close (sock);
++ return (HAVELINK);
++ }
++ close (sock);
++
++ if (ifmr.ifm_count == 0) {
++ /*
++ * Assume that this means interface
++ * does not support SIOCGIFMEDIA
++ */
++ log_fatal ("%s: no media types?", ifname);
++ return (HAVELINK);
++ }
++
++ if (ifmr.ifm_status & IFM_AVALID) {
++ if (ip -> ieee80211) {
++ /*
++ * Wavelan devices need to be checked if they are
++ * associated.
++ */
++ if ((IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211) &&
++ (ifmr.ifm_status & IFM_ACTIVE)) {
++ return (HAVELINK);
++ }
++ } else {
++ if (ifmr.ifm_status & IFM_ACTIVE) {
++ return (HAVELINK);
++ }
++ }
++ /*
++ * We really have no link.
++ */
++ return (NOLINK);
++ }
++ /*
++ * IFM_AVALID is not set. We cannot check
++ * the link state. Assume HAVELINK.
++ */
++
++#endif /* Other OSs */
++ /*
++ * Always return a successful link if the OS
++ * is not supported.
++ */
++ return (HAVELINK);
++}
++
++#ifdef __FreeBSD__
++void
++set_ieee80211 (struct interface_info *ip) {
++
++ struct ieee80211req ireq;
++ u_int8_t data[32];
++ int associated = 0;
++ int *media_list, i;
++ char *ifname;
++ int sock;
++
++ ifname = ip -> name;
++
++ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
++ log_fatal ("Can't create interface_active socket");
++
++ (void) memset (&ireq, 0, sizeof (ireq));
++ (void) strncpy (ireq.i_name, ifname, sizeof (ireq.i_name));
++ ireq.i_data = &data;
++ ireq.i_type = IEEE80211_IOC_SSID;
++ ireq.i_val = -1;
++ /*
++ * If we can't get the SSID,
++ * this isn't an 802.11 device.
++ */
++ if (ioctl (sock, SIOCG80211, &ireq) < 0)
++ ip -> ieee80211 = 0;
++ else {
++#ifdef DEBUG
++ printf ("Device %s has 802.11\n", ifname);
++#endif
++ ip -> ieee80211 = 1;
++ }
++ close (sock);
++ }
++#endif /* __FreeBSD__ */
++
++#ifdef ENABLE_POLLING_MODE
++/* Go to background after some time */
++void state_background (cpp)
++ void *cpp;
++{
++ go_daemon ();
++}
++
++/* Check the state of the NICs if we have link */
++void state_polling (cpp)
++ void *cpp;
++{
++ static int doinitcheck = 0;
++ struct interface_info *ip;
++ struct client_state *client;
++ int result;
++
++ for (ip = interfaces; ip; ip = ip -> next) {
++ if (! ip -> polling)
++ continue;
++#ifdef DEBUG
++ printf ("%s: Polling interface state\n", ip -> name);
++ for (client = ip -> client;
++ client; client = client -> next) {
++ printf ("%s: client state of %d\n", ip -> name, ip -> client -> state);
++ printf ("%s: link = %d\n", ip -> name, ip -> linkstate);
++ }
++#endif
++
++ result = interface_active (ip);
++ /*
++ * If dhclient.conf contains media settings, we cannot
++ * abort if the interface is not set to active mode.
++ */
++ if (ip -> havemedia && ip -> client -> state != S_BOUND) {
++ if (result == HAVELINK)
++ ip -> forcediscover = 1;
++ result = HAVELINK;
++ }
++
++ /*
++ * The last status of the interface tells us
++ * the we've got no link ...
++ */
++ if (ip -> linkstate == NOLINK || ! doinitcheck) {
++ /*
++ * ... but we have now link. Let's send
++ * requests.
++ */
++ if (result == HAVELINK) {
++#ifdef DEBUG
++ if (ip -> havemedia)
++ printf ("%s: Trying media settings on interface\n",
++ ip -> name);
++ else
++ printf ("%s: Found Link on interface\n", ip -> name);
++#endif
++ /*
++ * Set the interface to state_bound. We assume that we have
++ * a working link. If we cannot reach the server directly,
++ * INADDR_BROADCAST is used.
++ */
++ for (client = ip -> client;
++ client; client = client -> next) {
++ cancel_timeout (state_init, client);
++ cancel_timeout (state_reboot, client);
++ cancel_timeout (state_selecting, client);
++ if (client -> active) {
++ add_timeout (cur_time + random () % 5,
++ state_bound, client, 0, 0);
++ } else {
++ add_timeout (cur_time + random () % 5,
++ state_reboot, client, 0, 0);
++ }
++ }
++ ip -> linkstate = HAVELINK;
++ } else {
++#ifdef DEBUG
++ printf ("%s: No link on interface\n", ip -> name);
++#endif
++ for (client = ip -> client;
++ client; client = client -> next) {
++ /*
++ * Without this add_timout(), dhclient does
++ * not poll on a interface if there
++ * is no cable plugged in at startup
++ * time. Because we add one additional second
++ * to the time of a normal timeout, we always
++ * skip and block a running one. This prevents
++ * that polling is done twice at the same time.
++ */
++ if (client -> state == S_INIT) {
++ add_timeout (cur_time + (polling_interval + 1),
++ state_polling, client, 0, 0);
++ }
++ }
++ ip -> linkstate = NOLINK;
++ /*
++ * Automatically go into the background after
++ * some time. Do this only if there are no
++ * media options available for a interface.
++ */
++ if (! ip -> havemedia && ! doinitcheck) {
++ add_timeout (cur_time + (polling_interval * 2),
++ state_background, client, 0, 0);
++ }
++ }
++ }
++
++ /*
++ * The last status of the interface tells us
++ * the we previously had link.
++ */
++ if (ip -> linkstate == HAVELINK && doinitcheck) {
++ if (result == NOLINK) {
++ /*
++ * We lost link on the interface, or it isn't
++ * associated anymore.
++ */
++#ifdef DEBUG
++ printf ("%s: Lost Link on interface\n", ip -> name);
++#endif
++ /*
++ * After we lost link, cycle again through the
++ * different media settings if available. Else
++ * set NOLINK.
++ */
++ if (ip -> havemedia)
++ ip -> forcediscover = 1;
++ else
++ ip -> linkstate = NOLINK;
++ }
++ /*
++ * If we happen to have a real link, but no
++ * active lease, force the interface into
++ * state_reboot. Do the same if media settings
++ * are available.
++ */
++ if (ip -> forcediscover) {
++ for (client = ip -> client;
++ client; client = client -> next) {
++ if (client -> state != S_REBOOTING &&
++ client -> state != S_SELECTING) {
++ add_timeout (cur_time + random () % 5,
++ state_reboot, client, 0, 0);
++ }
++ }
++ ip -> forcediscover = 0;
++ ip -> linkstate = HAVELINK;
++ }
++ /* We still have link, do nothing. */
++ }
++ }
++ doinitcheck = 1;
++}
++#endif /* ifdef ENABLE_POLLING_MODE */