async.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* 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 <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
*/
{
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.
*/
return (B_TRUE);
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.
*/
"cancellation");
}
/*
* 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
{
if (async_pending(ifsp))
return (0);
if (tid == -1)
return (0);
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
{
/*
* be defensive here. the script may still be running if
* the asynchronous action times out before it is killed by the
* script helper process.
*/
/*
* in case async_timeout() has already called async_cancel(),
* and to be idempotent, check the DHCP_IF_BUSY flag
*/
return;
return;
}
(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.
*/
}
/*
* 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
{
/*
* 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).
*/
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!
*/
break;
default:
return (0);
}
if (do_reset)
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
{
(void) release_ifs(ifsp);
return;
}
/* we've expired now */
/*
* 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.
*/
(void) async_cancel(ifsp);
return;
}
if (async_pending(ifsp)) {
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
*/
(void) async_cancel(ifsp);
}
}