summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/isc-dhcp/client/dhclient.c212
-rw-r--r--contrib/isc-dhcp/includes/dhcpd.h15
2 files changed, 189 insertions, 38 deletions
diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c
index 820205f..f1bd5c4 100644
--- a/contrib/isc-dhcp/client/dhclient.c
+++ b/contrib/isc-dhcp/client/dhclient.c
@@ -257,8 +257,11 @@ int main (argc, argv, envp)
log_fatal ("%s: interface name too long (max %ld)",
argv [i], (long)strlen (argv [i]));
strlcpy (tmp -> name, argv [i], IFNAMSIZ);
+#ifdef __FreeBSD__
set_ieee80211 (tmp);
- tmp -> linkstatus = interface_active (tmp);
+#endif
+ tmp -> forcediscover = 0;
+ tmp -> linkstate = 0;
if (interfaces) {
interface_reference (&tmp -> next,
interfaces, MDL);
@@ -412,7 +415,15 @@ int main (argc, argv, envp)
INTERFACE_AUTOMATIC)) !=
INTERFACE_REQUESTED))
continue;
+#ifdef __FreeBSD__
set_ieee80211 (ip);
+#endif
+ ip -> forcediscover = 0;
+ if (ip -> client -> config -> media != NULL)
+ ip -> havemedia = 1;
+ else
+ ip -> havemedia = 0;
+
script_init (ip -> client,
"PREINIT", (struct string_list *)0);
if (ip -> client -> alias)
@@ -909,6 +920,15 @@ void bind_lease (client)
/* 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);
@@ -923,6 +943,10 @@ void bind_lease (client)
piaddr (client -> active -> address),
(long)(client -> active -> renewal - cur_time));
client -> state = S_BOUND;
+#ifdef ENABLE_POLLING_MODE
+ client -> interface -> linkstate = HAVELINK;
+ client -> interface -> forcediscover = 0;
+#endif /* ifdef ENABLE_POLLING_MODE */
reinitialize_interfaces ();
go_daemon ();
if (client -> config -> do_forward_update) {
@@ -1385,9 +1409,6 @@ void send_discover (cpp)
int interval;
int increase = 1;
- if (interface_active (client -> interface) == 0)
- return;
-
/* Figure out how long it's been since we started transmitting. */
interval = cur_time - client -> first_sending;
@@ -1427,6 +1448,9 @@ void send_discover (cpp)
}
}
+ if (interface_active (client -> interface) == NOLINK)
+ return;
+
/* If we're supposed to increase the interval, do so. If it's
currently zero (i.e., we haven't sent any packets yet), set
it to one; otherwise, add to it a random number between
@@ -1493,7 +1517,7 @@ void state_panic (cpp)
struct client_lease *loop;
struct client_lease *lp;
- if (interface_active (client -> interface) == 0)
+ if (interface_active (client -> interface) == NOLINK)
return;
loop = lp = client -> active;
@@ -1535,6 +1559,11 @@ void state_panic (cpp)
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;
@@ -2809,7 +2838,7 @@ void client_location_changed ()
break;
}
client -> state = S_INIT;
- if (interface_active (ip))
+ if (interface_active (ip) == HAVELINK)
state_reboot (client);
}
}
@@ -2971,7 +3000,7 @@ isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
client -> state = S_INIT;
/* Set up a timeout to start the initialization
process. */
- if (interface_active (ip)) {
+ if (interface_active (ip) == HAVELINK) {
add_timeout (cur_time + random () % 5,
state_reboot, client, 0, 0);
}
@@ -3038,7 +3067,7 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
break;
case server_awaken:
- if (interface_active (ip))
+ if (interface_active (ip) == HAVELINK)
state_reboot (client);
break;
}
@@ -3199,38 +3228,69 @@ interface_active(struct interface_info *ip) {
* Interface doesn't support SIOCGIFMEDIA, presume okay
*/
close (sock);
- return (1);
+ return (HAVELINK);
}
close (sock);
if (ifmr.ifm_count == 0) {
/*
- * this is unexpected (to me), but we'll just assume
- * that this means interface does not support SIOCGIFMEDIA
+ * Assume that this means interface
+ * does not support SIOCGIFMEDIA
*/
log_fatal ("%s: no media types?", ifname);
- return (1);
+ 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 (1);
+ (ifmr.ifm_status & IFM_ACTIVE)) {
+ if (ip -> havemedia &&
+ ip -> client -> state != S_BOUND)
+ ip -> forcediscover = 1;
+ return (HAVELINK);
+ }
} else {
- if (ifmr.ifm_status & IFM_ACTIVE)
- return (1);
+ /*
+ * Media settings can also be possible for normal
+ * devices.
+ */
+ if (ifmr.ifm_status & IFM_ACTIVE) {
+ if (ip -> havemedia &&
+ ip -> client -> state != S_BOUND)
+ ip -> forcediscover = 1;
+ return (HAVELINK);
+ }
}
}
- return (0);
+ /*
+ * 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)
+ return (HAVELINK);
+
+ /*
+ * We really have no link.
+ */
+ return (NOLINK);
#else /* ifdef __FreeBSD__ */
- return (1);
+ /*
+ * Always return a successful link if the OS
+ * is not supported.
+ */
+ return (HAVELINK);
#endif /* Other OSs */
}
#ifdef __FreeBSD__
+void
set_ieee80211 (struct interface_info *ip) {
struct ieee80211req ireq;
@@ -3267,6 +3327,13 @@ set_ieee80211 (struct interface_info *ip) {
#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_link (cpp)
void *cpp;
@@ -3278,50 +3345,123 @@ void state_link (cpp)
printf ("Polling interface status\n");
#endif
for (ip = interfaces; ip; ip = ip -> next) {
- if (ip -> linkstatus == 0 || doinitcheck == 0) {
- if (interface_active (ip)) {
+
+#ifdef DEBUG
+ 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
+
+ /*
+ * 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 (interface_active (ip) == HAVELINK) {
#ifdef DEBUG
- printf ("%s: Found Link on interface\n", ip -> name);
+ 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_reboot. But of
+ * course we can not be sure that we really got link,
+ * we just assume it.
+ */
for (client = ip -> client;
client; client = client -> next) {
- add_timeout (cur_time + random () % 5,
- state_reboot, client, 0, 0);
+ cancel_timeout (state_init, client);
+ cancel_timeout (state_reboot, client);
+ cancel_timeout (state_selecting, client);
+ add_timeout (cur_time + random () % 5,
+ state_reboot, client, 0, 0);
}
- ip -> linkstatus = 1;
+ ip -> linkstate = HAVELINK;
} else {
#ifdef DEBUG
printf ("%s: No Link on interface\n", ip -> name);
#endif
for (client = ip -> client;
client; client = client -> next) {
- cancel_timeout (state_init, client);
- cancel_timeout (send_discover, client);
- cancel_timeout (send_request, client);
/*
- * XXX without this, dhclient does
+ * Without this add_timout(), dhclient does
* not poll on a interface if there
* is no cable plugged in at startup
- * time
+ * 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,
+ add_timeout (cur_time + (polling_interval + 1),
state_link, client, 0, 0);
}
}
- ip -> linkstatus = 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);
+ }
}
- } else {
- if (interface_active (ip) == 0) {
+ }
+
+ /*
+ * The last status of the interface tells us
+ * the we previously had link.
+ */
+ if (ip -> linkstate == HAVELINK && doinitcheck) {
+ if (interface_active (ip) == 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
- ip -> linkstatus = 0;
+ /*
+ * 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. */
}
}
- if (doinitcheck)
- go_daemon ();
doinitcheck = 1;
}
#endif /* ifdef ENABLE_POLLING_MODE */
diff --git a/contrib/isc-dhcp/includes/dhcpd.h b/contrib/isc-dhcp/includes/dhcpd.h
index d647f12..e62e93b 100644
--- a/contrib/isc-dhcp/includes/dhcpd.h
+++ b/contrib/isc-dhcp/includes/dhcpd.h
@@ -101,6 +101,9 @@ typedef struct hash_table class_hash_t;
(((x) >> OPTION_HASH_EXP) & \
(OPTION_HASH_PTWO - 1))) % OPTION_HASH_SIZE;
+#define NOLINK 0
+#define HAVELINK 1
+
enum dhcp_shutdown_state {
shutdown_listeners,
shutdown_omapi_connections,
@@ -780,8 +783,10 @@ struct interface_info {
unsigned remote_id_len; /* Length of Remote ID. */
char name [IFNAMSIZ]; /* Its name... */
- int linkstatus; /* Link status */
- int ieee80211; /* True if media is ieee80211 */
+ int ieee80211; /* True if media is ieee802.11 */
+ int havemedia; /* True if we have a media table */
+ int linkstate; /* True if we have link */
+ int forcediscover; /* True if a discover is needed */
int index; /* Its index. */
int rfdesc; /* Its read file descriptor. */
int wfdesc; /* Its write file descriptor, if
@@ -1859,6 +1864,7 @@ void send_decline PROTO ((void *));
void state_reboot PROTO ((void *));
#ifdef ENABLE_POLLING_MODE
void state_link PROTO (());
+void state_background PROTO ((void *));
#endif
void state_init PROTO ((void *));
void state_selecting PROTO ((void *));
@@ -1867,6 +1873,11 @@ void state_bound PROTO ((void *));
void state_stop PROTO ((void *));
void state_panic PROTO ((void *));
+#ifdef __FreeBSD__
+void set_ieee80211 PROTO ((struct interface_info *));
+#endif
+int interface_active PROTO ((struct interface_info *));
+
void bind_lease PROTO ((struct client_state *));
void make_client_options PROTO ((struct client_state *,
OpenPOWER on IntegriCloud