1
0
mirror of https://git.FreeBSD.org/ports.git synced 2024-12-05 01:55:52 +00:00
freebsd-ports/net/isc-dhcp40-server/files/patch-client::dhclient.c
Sergey Matveychuk a1dec1380f - Update net/isc-dhcp3-* to 3.0.4
* fixes to the failover protocol
  * manpage updates
  * DDNS fixes
  * commandline parsing fixes
- Remove USE_REINPLACE

PR:		ports/96916
Submitted by:	maintainer
2006-05-07 20:34:01 +00:00

546 lines
14 KiB
C

--- client/dhclient.c.orig Thu Apr 27 23:38:29 2006
+++ client/dhclient.c Sat May 6 17:34:55 2006
@@ -38,6 +38,13 @@
#include "dhcpd.h"
#include "version.h"
+#if __FreeBSD_version > 502010
+#include <sys/ioctl.h>
+#include <net/if_media.h>
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211.h>
+#endif
+
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
@@ -72,8 +79,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));
@@ -174,6 +184,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 ();
@@ -187,6 +200,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;
@@ -215,7 +241,16 @@
if (strlen(argv[i]) >= sizeof(tmp->name))
log_fatal("%s: interface name too long (is %ld)",
argv [i], (long)strlen(argv[i]));
- strcpy(tmp->name, argv[i]);
+ strlcpy (tmp -> name, argv [i], IFNAMSIZ);
+#if __FreeBSD_version > 502010
+ 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);
@@ -375,6 +410,16 @@
INTERFACE_AUTOMATIC)) !=
INTERFACE_REQUESTED))
continue;
+#if __FreeBSD_version > 502010
+ 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)
@@ -417,8 +462,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
}
}
}
@@ -476,9 +526,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]");
}
@@ -879,6 +929,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);
@@ -893,6 +952,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) {
@@ -1357,6 +1422,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);
@@ -1682,6 +1770,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),
@@ -1703,6 +1803,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);
}
@@ -2600,6 +2710,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);
@@ -2786,8 +2903,10 @@
case S_STOPPED:
break;
}
+#ifndef ENABLE_POLLING_MODE
client -> state = S_INIT;
state_reboot (client);
+#endif
}
}
}
@@ -3015,7 +3134,9 @@
break;
case server_awaken:
+#ifndef ENABLE_POLLING_MODE
state_reboot (client);
+#endif
break;
}
}
@@ -3153,3 +3274,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) {
+#if __FreeBSD_version > 502010
+ 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);
+}
+
+#if __FreeBSD_version > 502010
+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_version */
+
+#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 */