10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*3431Scarlsonj * Common Development and Distribution License (the "License").
6*3431Scarlsonj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*3431Scarlsonj * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
28*3431Scarlsonj #include <stdlib.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <dhcpmsg.h>
31*3431Scarlsonj #include <dhcpagent_ipc.h>
320Sstevel@tonic-gate
33*3431Scarlsonj #include "agent.h"
34*3431Scarlsonj #include "states.h"
350Sstevel@tonic-gate #include "interface.h"
360Sstevel@tonic-gate #include "ipc_action.h"
370Sstevel@tonic-gate #include "util.h"
380Sstevel@tonic-gate
390Sstevel@tonic-gate static iu_tq_callback_t ipc_action_timeout;
400Sstevel@tonic-gate
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate * ipc_action_init(): initializes the ipc_action structure
430Sstevel@tonic-gate *
44*3431Scarlsonj * input: ipc_action_t *: the structure to initialize
450Sstevel@tonic-gate * output: void
460Sstevel@tonic-gate */
470Sstevel@tonic-gate
480Sstevel@tonic-gate void
ipc_action_init(ipc_action_t * ia)49*3431Scarlsonj ipc_action_init(ipc_action_t *ia)
500Sstevel@tonic-gate {
51*3431Scarlsonj ia->ia_cmd = 0;
52*3431Scarlsonj ia->ia_fd = -1;
53*3431Scarlsonj ia->ia_tid = -1;
54*3431Scarlsonj ia->ia_eid = -1;
55*3431Scarlsonj ia->ia_request = NULL;
560Sstevel@tonic-gate }
570Sstevel@tonic-gate
580Sstevel@tonic-gate /*
59*3431Scarlsonj * ipc_action_start(): starts an ipc_action request on a DHCP state machine
600Sstevel@tonic-gate *
61*3431Scarlsonj * input: dhcp_smach_t *: the state machine to start the action on
62*3431Scarlsonj * ipc_action_t *: request structure
63*3431Scarlsonj * output: B_TRUE if the request is started successfully, B_FALSE otherwise
64*3431Scarlsonj * original request is still valid on failure, consumed otherwise.
650Sstevel@tonic-gate */
660Sstevel@tonic-gate
670Sstevel@tonic-gate boolean_t
ipc_action_start(dhcp_smach_t * dsmp,ipc_action_t * iareq)68*3431Scarlsonj ipc_action_start(dhcp_smach_t *dsmp, ipc_action_t *iareq)
690Sstevel@tonic-gate {
70*3431Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia;
710Sstevel@tonic-gate
72*3431Scarlsonj if (ia->ia_fd != -1 || ia->ia_tid != -1 || iareq->ia_fd == -1) {
73*3431Scarlsonj dhcpmsg(MSG_CRIT, "ipc_action_start: attempted restart on %s",
74*3431Scarlsonj dsmp->dsm_name);
75*3431Scarlsonj return (B_FALSE);
76*3431Scarlsonj }
770Sstevel@tonic-gate
78*3431Scarlsonj if (!async_cancel(dsmp)) {
79*3431Scarlsonj dhcpmsg(MSG_WARNING, "ipc_action_start: unable to cancel "
80*3431Scarlsonj "action on %s", dsmp->dsm_name);
81*3431Scarlsonj return (B_FALSE);
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
84*3431Scarlsonj if (iareq->ia_request->timeout == DHCP_IPC_WAIT_DEFAULT)
85*3431Scarlsonj iareq->ia_request->timeout = DHCP_IPC_DEFAULT_WAIT;
86*3431Scarlsonj
87*3431Scarlsonj if (iareq->ia_request->timeout == DHCP_IPC_WAIT_FOREVER) {
88*3431Scarlsonj iareq->ia_tid = -1;
89*3431Scarlsonj } else {
90*3431Scarlsonj iareq->ia_tid = iu_schedule_timer(tq,
91*3431Scarlsonj iareq->ia_request->timeout, ipc_action_timeout, dsmp);
92*3431Scarlsonj
93*3431Scarlsonj if (iareq->ia_tid == -1) {
94*3431Scarlsonj dhcpmsg(MSG_ERROR, "ipc_action_start: failed to set "
95*3431Scarlsonj "timer for %s on %s",
96*3431Scarlsonj dhcp_ipc_type_to_string(iareq->ia_cmd),
97*3431Scarlsonj dsmp->dsm_name);
98*3431Scarlsonj return (B_FALSE);
99*3431Scarlsonj }
100*3431Scarlsonj
101*3431Scarlsonj hold_smach(dsmp);
102*3431Scarlsonj }
103*3431Scarlsonj
104*3431Scarlsonj *ia = *iareq;
105*3431Scarlsonj
106*3431Scarlsonj /* We've taken ownership, so the input request is now invalid */
107*3431Scarlsonj ipc_action_init(iareq);
108*3431Scarlsonj
109*3431Scarlsonj dhcpmsg(MSG_DEBUG, "ipc_action_start: started %s (command %d) on %s",
110*3431Scarlsonj dhcp_ipc_type_to_string(ia->ia_cmd), ia->ia_cmd, dsmp->dsm_name);
111*3431Scarlsonj
112*3431Scarlsonj dsmp->dsm_dflags |= DHCP_IF_BUSY;
113*3431Scarlsonj
114*3431Scarlsonj /* This cannot fail due to the async_cancel above */
115*3431Scarlsonj (void) async_start(dsmp, ia->ia_cmd, B_TRUE);
116*3431Scarlsonj
117*3431Scarlsonj return (B_TRUE);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate * ipc_action_finish(): completes an ipc_action request on an interface
1220Sstevel@tonic-gate *
123*3431Scarlsonj * input: dhcp_smach_t *: the state machine to complete the action on
1240Sstevel@tonic-gate * int: the reason why the action finished (nonzero on error)
1250Sstevel@tonic-gate * output: void
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate void
ipc_action_finish(dhcp_smach_t * dsmp,int reason)129*3431Scarlsonj ipc_action_finish(dhcp_smach_t *dsmp, int reason)
1300Sstevel@tonic-gate {
131*3431Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia;
132*3431Scarlsonj
133*3431Scarlsonj dsmp->dsm_dflags &= ~DHCP_IF_BUSY;
134*3431Scarlsonj
135*3431Scarlsonj if (dsmp->dsm_ia.ia_fd == -1) {
136*3431Scarlsonj dhcpmsg(MSG_ERROR,
137*3431Scarlsonj "ipc_action_finish: attempted to finish unknown action "
138*3431Scarlsonj "on %s", dsmp->dsm_name);
139*3431Scarlsonj return;
140*3431Scarlsonj }
1410Sstevel@tonic-gate
142*3431Scarlsonj dhcpmsg(MSG_DEBUG,
143*3431Scarlsonj "ipc_action_finish: finished %s (command %d) on %s: %d",
144*3431Scarlsonj dhcp_ipc_type_to_string(ia->ia_cmd), (int)ia->ia_cmd,
145*3431Scarlsonj dsmp->dsm_name, reason);
146*3431Scarlsonj
147*3431Scarlsonj /*
148*3431Scarlsonj * if we can't cancel this timer, we're really in the
149*3431Scarlsonj * twilight zone. however, as long as we don't drop the
150*3431Scarlsonj * reference to the state machine, it shouldn't hurt us
151*3431Scarlsonj */
152*3431Scarlsonj
153*3431Scarlsonj if (dsmp->dsm_ia.ia_tid != -1 &&
154*3431Scarlsonj iu_cancel_timer(tq, dsmp->dsm_ia.ia_tid, NULL) == 1) {
155*3431Scarlsonj dsmp->dsm_ia.ia_tid = -1;
156*3431Scarlsonj release_smach(dsmp);
157*3431Scarlsonj }
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate if (reason == 0)
160*3431Scarlsonj send_ok_reply(ia);
1610Sstevel@tonic-gate else
162*3431Scarlsonj send_error_reply(ia, reason);
1630Sstevel@tonic-gate
164*3431Scarlsonj async_finish(dsmp);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /*
168*3431Scarlsonj * ipc_action_timeout(): times out an ipc_action on a state machine (the
169*3431Scarlsonj * request continues asynchronously, however)
1700Sstevel@tonic-gate *
1710Sstevel@tonic-gate * input: iu_tq_t *: unused
172*3431Scarlsonj * void *: the dhcp_smach_t * the ipc_action was pending on
1730Sstevel@tonic-gate * output: void
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /* ARGSUSED */
1770Sstevel@tonic-gate static void
ipc_action_timeout(iu_tq_t * tq,void * arg)1780Sstevel@tonic-gate ipc_action_timeout(iu_tq_t *tq, void *arg)
1790Sstevel@tonic-gate {
180*3431Scarlsonj dhcp_smach_t *dsmp = arg;
181*3431Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia;
1820Sstevel@tonic-gate
183*3431Scarlsonj dsmp->dsm_dflags &= ~DHCP_IF_BUSY;
184*3431Scarlsonj
185*3431Scarlsonj ia->ia_tid = -1;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate dhcpmsg(MSG_VERBOSE, "ipc timeout waiting for agent to complete "
188*3431Scarlsonj "%s (command %d) for %s", dhcp_ipc_type_to_string(ia->ia_cmd),
189*3431Scarlsonj ia->ia_cmd, dsmp->dsm_name);
190*3431Scarlsonj
191*3431Scarlsonj send_error_reply(ia, DHCP_IPC_E_TIMEOUT);
192*3431Scarlsonj
193*3431Scarlsonj async_finish(dsmp);
194*3431Scarlsonj release_smach(dsmp);
195*3431Scarlsonj }
1960Sstevel@tonic-gate
197*3431Scarlsonj /*
198*3431Scarlsonj * send_ok_reply(): sends an "ok" reply to a request and closes the ipc
199*3431Scarlsonj * connection
200*3431Scarlsonj *
201*3431Scarlsonj * input: ipc_action_t *: the request to reply to
202*3431Scarlsonj * output: void
203*3431Scarlsonj * note: the request is freed (thus the request must be on the heap).
204*3431Scarlsonj */
205*3431Scarlsonj
206*3431Scarlsonj void
send_ok_reply(ipc_action_t * ia)207*3431Scarlsonj send_ok_reply(ipc_action_t *ia)
208*3431Scarlsonj {
209*3431Scarlsonj send_error_reply(ia, 0);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /*
213*3431Scarlsonj * send_error_reply(): sends an "error" reply to a request and closes the ipc
214*3431Scarlsonj * connection
2150Sstevel@tonic-gate *
216*3431Scarlsonj * input: ipc_action_t *: the request to reply to
217*3431Scarlsonj * int: the error to send back on the ipc connection
2180Sstevel@tonic-gate * output: void
219*3431Scarlsonj * note: the request is freed (thus the request must be on the heap).
220*3431Scarlsonj */
221*3431Scarlsonj
222*3431Scarlsonj void
send_error_reply(ipc_action_t * ia,int error)223*3431Scarlsonj send_error_reply(ipc_action_t *ia, int error)
224*3431Scarlsonj {
225*3431Scarlsonj send_data_reply(ia, error, DHCP_TYPE_NONE, NULL, 0);
226*3431Scarlsonj }
227*3431Scarlsonj
228*3431Scarlsonj /*
229*3431Scarlsonj * send_data_reply(): sends a reply to a request and closes the ipc connection
230*3431Scarlsonj *
231*3431Scarlsonj * input: ipc_action_t *: the request to reply to
232*3431Scarlsonj * int: the status to send back on the ipc connection (zero for
233*3431Scarlsonj * success, DHCP_IPC_E_* otherwise).
234*3431Scarlsonj * dhcp_data_type_t: the type of the payload in the reply
235*3431Scarlsonj * const void *: the payload for the reply, or NULL if there is no
236*3431Scarlsonj * payload
237*3431Scarlsonj * size_t: the size of the payload
238*3431Scarlsonj * output: void
239*3431Scarlsonj * note: the request is freed (thus the request must be on the heap).
2400Sstevel@tonic-gate */
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate void
send_data_reply(ipc_action_t * ia,int error,dhcp_data_type_t type,const void * buffer,size_t size)243*3431Scarlsonj send_data_reply(ipc_action_t *ia, int error, dhcp_data_type_t type,
244*3431Scarlsonj const void *buffer, size_t size)
2450Sstevel@tonic-gate {
246*3431Scarlsonj dhcp_ipc_reply_t *reply;
247*3431Scarlsonj int retval;
248*3431Scarlsonj
249*3431Scarlsonj if (ia->ia_fd == -1 || ia->ia_request == NULL)
2500Sstevel@tonic-gate return;
2510Sstevel@tonic-gate
252*3431Scarlsonj reply = dhcp_ipc_alloc_reply(ia->ia_request, error, buffer, size,
253*3431Scarlsonj type);
254*3431Scarlsonj if (reply == NULL) {
255*3431Scarlsonj dhcpmsg(MSG_ERR, "send_data_reply: cannot allocate reply");
256*3431Scarlsonj
257*3431Scarlsonj } else if ((retval = dhcp_ipc_send_reply(ia->ia_fd, reply)) != 0) {
258*3431Scarlsonj dhcpmsg(MSG_ERROR, "send_data_reply: dhcp_ipc_send_reply: %s",
259*3431Scarlsonj dhcp_ipc_strerror(retval));
260*3431Scarlsonj }
261*3431Scarlsonj
2620Sstevel@tonic-gate /*
263*3431Scarlsonj * free the request since we've now used it to send our reply.
264*3431Scarlsonj * we can also close the socket since the reply has been sent.
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate
267*3431Scarlsonj free(reply);
268*3431Scarlsonj free(ia->ia_request);
269*3431Scarlsonj if (ia->ia_eid != -1)
270*3431Scarlsonj (void) iu_unregister_event(eh, ia->ia_eid, NULL);
271*3431Scarlsonj (void) dhcp_ipc_close(ia->ia_fd);
272*3431Scarlsonj ia->ia_request = NULL;
273*3431Scarlsonj ia->ia_fd = -1;
274*3431Scarlsonj ia->ia_eid = -1;
2750Sstevel@tonic-gate }
276