summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c')
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c
new file mode 100644
index 0000000000..d7fb37970d
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/async.c
@@ -0,0 +1,296 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dhcpmsg.h>
+#include <libinetutil.h>
+
+#include "async.h"
+#include "util.h"
+#include "agent.h"
+#include "interface.h"
+#include "script_handler.h"
+
+static void async_timeout(iu_tq_t *, void *);
+
+/*
+ * async_pending(): checks to see if an async command is pending. if a stale
+ * async command is found, cancellation is attempted.
+ *
+ * input: struct ifslist *: the interface to check for an async command on
+ * output: boolean_t: B_TRUE if async command is pending, B_FALSE if not
+ */
+
+boolean_t
+async_pending(struct ifslist *ifsp)
+{
+ if (!(ifsp->if_dflags & DHCP_IF_BUSY))
+ return (B_FALSE);
+
+ /*
+ * if the command was not started by the user (i.e., was
+ * started internal to the agent), then it will timeout in
+ * async_timeout() -- don't shoot it here.
+ */
+
+ if (!ifsp->if_async.as_user)
+ return (B_TRUE);
+
+ if (ifsp->if_script_pid != -1)
+ return (B_TRUE);
+
+ /*
+ * user command -- see if they went away. if they went away,
+ * either a timeout was already sent to them or they
+ * control-c'd out.
+ */
+
+ if (ipc_action_pending(ifsp))
+ return (B_TRUE);
+
+ /*
+ * it appears they went away. try to cancel their pending
+ * command. if we can't cancel it, we leave their command
+ * pending and it's just gonna have to complete its business
+ * in any case, cancel the ipc_action timer, since we know
+ * they've gone away.
+ */
+
+ dhcpmsg(MSG_DEBUG, "async_pending: async command left, attempting "
+ "cancellation");
+
+ ipc_action_cancel_timer(ifsp);
+ return (async_cancel(ifsp) ? B_FALSE : B_TRUE);
+}
+
+/*
+ * async_start(): starts an asynchronous command on an interface
+ *
+ * input: struct ifslist *: the interface to start the async command on
+ * dhcp_ipc_type_t: the command to start
+ * boolean_t: B_TRUE if the command was started by a user
+ * output: int: 1 on success, 0 on failure
+ */
+
+int
+async_start(struct ifslist *ifsp, dhcp_ipc_type_t cmd, boolean_t user)
+{
+ iu_timer_id_t tid;
+
+ if (async_pending(ifsp))
+ return (0);
+
+ tid = iu_schedule_timer(tq, DHCP_ASYNC_WAIT, async_timeout, ifsp);
+ if (tid == -1)
+ return (0);
+
+ hold_ifs(ifsp);
+
+ ifsp->if_async.as_tid = tid;
+ ifsp->if_async.as_cmd = cmd;
+ ifsp->if_async.as_user = user;
+ ifsp->if_dflags |= DHCP_IF_BUSY;
+
+ return (1);
+}
+
+
+/*
+ * async_finish(): completes an asynchronous command
+ *
+ * input: struct ifslist *: the interface with the pending async command
+ * output: void
+ * note: should only be used when the command has no residual state to
+ * clean up
+ */
+
+void
+async_finish(struct ifslist *ifsp)
+{
+ /*
+ * be defensive here. the script may still be running if
+ * the asynchronous action times out before it is killed by the
+ * script helper process.
+ */
+
+ if (ifsp->if_script_pid != -1)
+ script_stop(ifsp);
+
+ /*
+ * in case async_timeout() has already called async_cancel(),
+ * and to be idempotent, check the DHCP_IF_BUSY flag
+ */
+
+ if (!(ifsp->if_dflags & DHCP_IF_BUSY))
+ return;
+
+ if (ifsp->if_async.as_tid == -1) {
+ ifsp->if_dflags &= ~DHCP_IF_BUSY;
+ return;
+ }
+
+ if (iu_cancel_timer(tq, ifsp->if_async.as_tid, NULL) == 1) {
+ ifsp->if_dflags &= ~DHCP_IF_BUSY;
+ ifsp->if_async.as_tid = -1;
+ (void) release_ifs(ifsp);
+ return;
+ }
+
+ /*
+ * if we can't cancel this timer, we'll just leave the
+ * interface busy and when the timeout finally fires, we'll
+ * mark it free, which will just cause a minor nuisance.
+ */
+
+ dhcpmsg(MSG_WARNING, "async_finish: cannot cancel async timer");
+}
+
+/*
+ * async_cancel(): cancels a pending asynchronous command
+ *
+ * input: struct ifslist *: the interface with the pending async command
+ * output: int: 1 if cancellation was successful, 0 on failure
+ */
+
+int
+async_cancel(struct ifslist *ifsp)
+{
+ boolean_t do_reset = B_FALSE;
+
+ /*
+ * we decide how to cancel the command depending on our
+ * current state, since commands such as EXTEND may in fact
+ * cause us to enter back into SELECTING (if a NAK results
+ * from the EXTEND).
+ */
+
+ switch (ifsp->if_state) {
+
+ case BOUND:
+ case INFORMATION:
+ break;
+
+ case RENEWING: /* FALLTHRU */
+ case REBINDING: /* FALLTHRU */
+ case INFORM_SENT:
+
+ /*
+ * these states imply that we've sent a packet and we're
+ * awaiting an ACK or NAK. just cancel the wait.
+ */
+
+ if (unregister_acknak(ifsp) == 0)
+ return (0);
+
+ break;
+
+ case INIT: /* FALLTHRU */
+ case SELECTING: /* FALLTHRU */
+ case REQUESTING: /* FALLTHRU */
+ case INIT_REBOOT:
+
+ /*
+ * these states imply we're still trying to get a lease.
+ * just return to a clean slate (INIT) -- but not until
+ * after we've finished the asynchronous command!
+ */
+
+ do_reset = B_TRUE;
+ break;
+
+ default:
+ dhcpmsg(MSG_WARNING, "async_cancel: cancellation in unexpected "
+ "state %d", ifsp->if_state);
+ return (0);
+ }
+
+ async_finish(ifsp);
+ dhcpmsg(MSG_DEBUG, "async_cancel: asynchronous command (%d) aborted",
+ ifsp->if_async.as_cmd);
+ if (do_reset)
+ reset_ifs(ifsp);
+
+ return (1);
+}
+
+/*
+ * async_timeout(): expires stale asynchronous commands
+ *
+ * input: iu_tq_t *: the timer queue on which the timeout went off
+ * void *: the interface with the pending async command
+ * output: void
+ */
+
+static void
+async_timeout(iu_tq_t *tq, void *arg)
+{
+ struct ifslist *ifsp = (struct ifslist *)arg;
+
+ if (check_ifs(ifsp) == 0) {
+ (void) release_ifs(ifsp);
+ return;
+ }
+
+ /* we've expired now */
+ ifsp->if_async.as_tid = -1;
+
+ /*
+ * if the command was generated internally to the agent, try
+ * to cancel it immediately. otherwise, if the user has gone
+ * away, we cancel it in async_pending(). otherwise, we let
+ * it live.
+ */
+
+ if (!ifsp->if_async.as_user) {
+ (void) async_cancel(ifsp);
+ return;
+ }
+
+ if (async_pending(ifsp)) {
+
+ ifsp->if_async.as_tid = iu_schedule_timer(tq, DHCP_ASYNC_WAIT,
+ async_timeout, ifsp);
+
+ if (ifsp->if_async.as_tid != -1) {
+ hold_ifs(ifsp);
+ dhcpmsg(MSG_DEBUG, "async_timeout: asynchronous "
+ "command %d still pending", ifsp->if_async.as_cmd);
+ return;
+ }
+
+ /*
+ * what can we do but cancel it? we can't get called
+ * back again and otherwise we'll end up in the
+ * twilight zone with the interface permanently busy
+ */
+
+ ipc_action_finish(ifsp, DHCP_IPC_E_INT);
+ (void) async_cancel(ifsp);
+ }
+}