17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*d04ccbb3Scarlsonj * Common Development and Distribution License (the "License").
6*d04ccbb3Scarlsonj * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*d04ccbb3Scarlsonj * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
28*d04ccbb3Scarlsonj #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <dhcpmsg.h>
31*d04ccbb3Scarlsonj #include <dhcpagent_ipc.h>
327c478bd9Sstevel@tonic-gate
33*d04ccbb3Scarlsonj #include "agent.h"
34*d04ccbb3Scarlsonj #include "states.h"
357c478bd9Sstevel@tonic-gate #include "interface.h"
367c478bd9Sstevel@tonic-gate #include "ipc_action.h"
377c478bd9Sstevel@tonic-gate #include "util.h"
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate static iu_tq_callback_t ipc_action_timeout;
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * ipc_action_init(): initializes the ipc_action structure
437c478bd9Sstevel@tonic-gate *
44*d04ccbb3Scarlsonj * input: ipc_action_t *: the structure to initialize
457c478bd9Sstevel@tonic-gate * output: void
467c478bd9Sstevel@tonic-gate */
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate void
ipc_action_init(ipc_action_t * ia)49*d04ccbb3Scarlsonj ipc_action_init(ipc_action_t *ia)
507c478bd9Sstevel@tonic-gate {
51*d04ccbb3Scarlsonj ia->ia_cmd = 0;
52*d04ccbb3Scarlsonj ia->ia_fd = -1;
53*d04ccbb3Scarlsonj ia->ia_tid = -1;
54*d04ccbb3Scarlsonj ia->ia_eid = -1;
55*d04ccbb3Scarlsonj ia->ia_request = NULL;
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate /*
59*d04ccbb3Scarlsonj * ipc_action_start(): starts an ipc_action request on a DHCP state machine
607c478bd9Sstevel@tonic-gate *
61*d04ccbb3Scarlsonj * input: dhcp_smach_t *: the state machine to start the action on
62*d04ccbb3Scarlsonj * ipc_action_t *: request structure
63*d04ccbb3Scarlsonj * output: B_TRUE if the request is started successfully, B_FALSE otherwise
64*d04ccbb3Scarlsonj * original request is still valid on failure, consumed otherwise.
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate boolean_t
ipc_action_start(dhcp_smach_t * dsmp,ipc_action_t * iareq)68*d04ccbb3Scarlsonj ipc_action_start(dhcp_smach_t *dsmp, ipc_action_t *iareq)
697c478bd9Sstevel@tonic-gate {
70*d04ccbb3Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia;
717c478bd9Sstevel@tonic-gate
72*d04ccbb3Scarlsonj if (ia->ia_fd != -1 || ia->ia_tid != -1 || iareq->ia_fd == -1) {
73*d04ccbb3Scarlsonj dhcpmsg(MSG_CRIT, "ipc_action_start: attempted restart on %s",
74*d04ccbb3Scarlsonj dsmp->dsm_name);
75*d04ccbb3Scarlsonj return (B_FALSE);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate
78*d04ccbb3Scarlsonj if (!async_cancel(dsmp)) {
79*d04ccbb3Scarlsonj dhcpmsg(MSG_WARNING, "ipc_action_start: unable to cancel "
80*d04ccbb3Scarlsonj "action on %s", dsmp->dsm_name);
817c478bd9Sstevel@tonic-gate return (B_FALSE);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate
84*d04ccbb3Scarlsonj if (iareq->ia_request->timeout == DHCP_IPC_WAIT_DEFAULT)
85*d04ccbb3Scarlsonj iareq->ia_request->timeout = DHCP_IPC_DEFAULT_WAIT;
86*d04ccbb3Scarlsonj
87*d04ccbb3Scarlsonj if (iareq->ia_request->timeout == DHCP_IPC_WAIT_FOREVER) {
88*d04ccbb3Scarlsonj iareq->ia_tid = -1;
89*d04ccbb3Scarlsonj } else {
90*d04ccbb3Scarlsonj iareq->ia_tid = iu_schedule_timer(tq,
91*d04ccbb3Scarlsonj iareq->ia_request->timeout, ipc_action_timeout, dsmp);
92*d04ccbb3Scarlsonj
93*d04ccbb3Scarlsonj if (iareq->ia_tid == -1) {
94*d04ccbb3Scarlsonj dhcpmsg(MSG_ERROR, "ipc_action_start: failed to set "
95*d04ccbb3Scarlsonj "timer for %s on %s",
96*d04ccbb3Scarlsonj dhcp_ipc_type_to_string(iareq->ia_cmd),
97*d04ccbb3Scarlsonj dsmp->dsm_name);
98*d04ccbb3Scarlsonj return (B_FALSE);
99*d04ccbb3Scarlsonj }
100*d04ccbb3Scarlsonj
101*d04ccbb3Scarlsonj hold_smach(dsmp);
102*d04ccbb3Scarlsonj }
103*d04ccbb3Scarlsonj
104*d04ccbb3Scarlsonj *ia = *iareq;
105*d04ccbb3Scarlsonj
106*d04ccbb3Scarlsonj /* We've taken ownership, so the input request is now invalid */
107*d04ccbb3Scarlsonj ipc_action_init(iareq);
108*d04ccbb3Scarlsonj
109*d04ccbb3Scarlsonj dhcpmsg(MSG_DEBUG, "ipc_action_start: started %s (command %d) on %s",
110*d04ccbb3Scarlsonj dhcp_ipc_type_to_string(ia->ia_cmd), ia->ia_cmd, dsmp->dsm_name);
111*d04ccbb3Scarlsonj
112*d04ccbb3Scarlsonj dsmp->dsm_dflags |= DHCP_IF_BUSY;
113*d04ccbb3Scarlsonj
114*d04ccbb3Scarlsonj /* This cannot fail due to the async_cancel above */
115*d04ccbb3Scarlsonj (void) async_start(dsmp, ia->ia_cmd, B_TRUE);
116*d04ccbb3Scarlsonj
117*d04ccbb3Scarlsonj return (B_TRUE);
118*d04ccbb3Scarlsonj }
119*d04ccbb3Scarlsonj
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate * ipc_action_finish(): completes an ipc_action request on an interface
1227c478bd9Sstevel@tonic-gate *
123*d04ccbb3Scarlsonj * input: dhcp_smach_t *: the state machine to complete the action on
1247c478bd9Sstevel@tonic-gate * int: the reason why the action finished (nonzero on error)
1257c478bd9Sstevel@tonic-gate * output: void
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate void
ipc_action_finish(dhcp_smach_t * dsmp,int reason)129*d04ccbb3Scarlsonj ipc_action_finish(dhcp_smach_t *dsmp, int reason)
1307c478bd9Sstevel@tonic-gate {
131*d04ccbb3Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia;
1327c478bd9Sstevel@tonic-gate
133*d04ccbb3Scarlsonj dsmp->dsm_dflags &= ~DHCP_IF_BUSY;
134*d04ccbb3Scarlsonj
135*d04ccbb3Scarlsonj if (dsmp->dsm_ia.ia_fd == -1) {
136*d04ccbb3Scarlsonj dhcpmsg(MSG_ERROR,
137*d04ccbb3Scarlsonj "ipc_action_finish: attempted to finish unknown action "
138*d04ccbb3Scarlsonj "on %s", dsmp->dsm_name);
1397c478bd9Sstevel@tonic-gate return;
140*d04ccbb3Scarlsonj }
141*d04ccbb3Scarlsonj
142*d04ccbb3Scarlsonj dhcpmsg(MSG_DEBUG,
143*d04ccbb3Scarlsonj "ipc_action_finish: finished %s (command %d) on %s: %d",
144*d04ccbb3Scarlsonj dhcp_ipc_type_to_string(ia->ia_cmd), (int)ia->ia_cmd,
145*d04ccbb3Scarlsonj dsmp->dsm_name, reason);
146*d04ccbb3Scarlsonj
147*d04ccbb3Scarlsonj /*
148*d04ccbb3Scarlsonj * if we can't cancel this timer, we're really in the
149*d04ccbb3Scarlsonj * twilight zone. however, as long as we don't drop the
150*d04ccbb3Scarlsonj * reference to the state machine, it shouldn't hurt us
151*d04ccbb3Scarlsonj */
152*d04ccbb3Scarlsonj
153*d04ccbb3Scarlsonj if (dsmp->dsm_ia.ia_tid != -1 &&
154*d04ccbb3Scarlsonj iu_cancel_timer(tq, dsmp->dsm_ia.ia_tid, NULL) == 1) {
155*d04ccbb3Scarlsonj dsmp->dsm_ia.ia_tid = -1;
156*d04ccbb3Scarlsonj release_smach(dsmp);
157*d04ccbb3Scarlsonj }
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate if (reason == 0)
160*d04ccbb3Scarlsonj send_ok_reply(ia);
1617c478bd9Sstevel@tonic-gate else
162*d04ccbb3Scarlsonj send_error_reply(ia, reason);
1637c478bd9Sstevel@tonic-gate
164*d04ccbb3Scarlsonj async_finish(dsmp);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate /*
168*d04ccbb3Scarlsonj * ipc_action_timeout(): times out an ipc_action on a state machine (the
169*d04ccbb3Scarlsonj * request continues asynchronously, however)
1707c478bd9Sstevel@tonic-gate *
1717c478bd9Sstevel@tonic-gate * input: iu_tq_t *: unused
172*d04ccbb3Scarlsonj * void *: the dhcp_smach_t * the ipc_action was pending on
1737c478bd9Sstevel@tonic-gate * output: void
1747c478bd9Sstevel@tonic-gate */
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate /* ARGSUSED */
1777c478bd9Sstevel@tonic-gate static void
ipc_action_timeout(iu_tq_t * tq,void * arg)1787c478bd9Sstevel@tonic-gate ipc_action_timeout(iu_tq_t *tq, void *arg)
1797c478bd9Sstevel@tonic-gate {
180*d04ccbb3Scarlsonj dhcp_smach_t *dsmp = arg;
181*d04ccbb3Scarlsonj struct ipc_action *ia = &dsmp->dsm_ia;
1827c478bd9Sstevel@tonic-gate
183*d04ccbb3Scarlsonj dsmp->dsm_dflags &= ~DHCP_IF_BUSY;
184*d04ccbb3Scarlsonj
185*d04ccbb3Scarlsonj ia->ia_tid = -1;
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate dhcpmsg(MSG_VERBOSE, "ipc timeout waiting for agent to complete "
188*d04ccbb3Scarlsonj "%s (command %d) for %s", dhcp_ipc_type_to_string(ia->ia_cmd),
189*d04ccbb3Scarlsonj ia->ia_cmd, dsmp->dsm_name);
1907c478bd9Sstevel@tonic-gate
191*d04ccbb3Scarlsonj send_error_reply(ia, DHCP_IPC_E_TIMEOUT);
192*d04ccbb3Scarlsonj
193*d04ccbb3Scarlsonj async_finish(dsmp);
194*d04ccbb3Scarlsonj release_smach(dsmp);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate /*
198*d04ccbb3Scarlsonj * send_ok_reply(): sends an "ok" reply to a request and closes the ipc
199*d04ccbb3Scarlsonj * connection
2007c478bd9Sstevel@tonic-gate *
201*d04ccbb3Scarlsonj * input: ipc_action_t *: the request to reply to
2027c478bd9Sstevel@tonic-gate * output: void
203*d04ccbb3Scarlsonj * note: the request is freed (thus the request must be on the heap).
2047c478bd9Sstevel@tonic-gate */
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate void
send_ok_reply(ipc_action_t * ia)207*d04ccbb3Scarlsonj send_ok_reply(ipc_action_t *ia)
2087c478bd9Sstevel@tonic-gate {
209*d04ccbb3Scarlsonj send_error_reply(ia, 0);
210*d04ccbb3Scarlsonj }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*
213*d04ccbb3Scarlsonj * send_error_reply(): sends an "error" reply to a request and closes the ipc
214*d04ccbb3Scarlsonj * connection
215*d04ccbb3Scarlsonj *
216*d04ccbb3Scarlsonj * input: ipc_action_t *: the request to reply to
217*d04ccbb3Scarlsonj * int: the error to send back on the ipc connection
218*d04ccbb3Scarlsonj * output: void
219*d04ccbb3Scarlsonj * note: the request is freed (thus the request must be on the heap).
2207c478bd9Sstevel@tonic-gate */
2217c478bd9Sstevel@tonic-gate
222*d04ccbb3Scarlsonj void
send_error_reply(ipc_action_t * ia,int error)223*d04ccbb3Scarlsonj send_error_reply(ipc_action_t *ia, int error)
224*d04ccbb3Scarlsonj {
225*d04ccbb3Scarlsonj send_data_reply(ia, error, DHCP_TYPE_NONE, NULL, 0);
2267c478bd9Sstevel@tonic-gate }
227*d04ccbb3Scarlsonj
228*d04ccbb3Scarlsonj /*
229*d04ccbb3Scarlsonj * send_data_reply(): sends a reply to a request and closes the ipc connection
230*d04ccbb3Scarlsonj *
231*d04ccbb3Scarlsonj * input: ipc_action_t *: the request to reply to
232*d04ccbb3Scarlsonj * int: the status to send back on the ipc connection (zero for
233*d04ccbb3Scarlsonj * success, DHCP_IPC_E_* otherwise).
234*d04ccbb3Scarlsonj * dhcp_data_type_t: the type of the payload in the reply
235*d04ccbb3Scarlsonj * const void *: the payload for the reply, or NULL if there is no
236*d04ccbb3Scarlsonj * payload
237*d04ccbb3Scarlsonj * size_t: the size of the payload
238*d04ccbb3Scarlsonj * output: void
239*d04ccbb3Scarlsonj * note: the request is freed (thus the request must be on the heap).
240*d04ccbb3Scarlsonj */
241*d04ccbb3Scarlsonj
242*d04ccbb3Scarlsonj void
send_data_reply(ipc_action_t * ia,int error,dhcp_data_type_t type,const void * buffer,size_t size)243*d04ccbb3Scarlsonj send_data_reply(ipc_action_t *ia, int error, dhcp_data_type_t type,
244*d04ccbb3Scarlsonj const void *buffer, size_t size)
245*d04ccbb3Scarlsonj {
246*d04ccbb3Scarlsonj dhcp_ipc_reply_t *reply;
247*d04ccbb3Scarlsonj int retval;
248*d04ccbb3Scarlsonj
249*d04ccbb3Scarlsonj if (ia->ia_fd == -1 || ia->ia_request == NULL)
250*d04ccbb3Scarlsonj return;
251*d04ccbb3Scarlsonj
252*d04ccbb3Scarlsonj reply = dhcp_ipc_alloc_reply(ia->ia_request, error, buffer, size,
253*d04ccbb3Scarlsonj type);
254*d04ccbb3Scarlsonj if (reply == NULL) {
255*d04ccbb3Scarlsonj dhcpmsg(MSG_ERR, "send_data_reply: cannot allocate reply");
256*d04ccbb3Scarlsonj
257*d04ccbb3Scarlsonj } else if ((retval = dhcp_ipc_send_reply(ia->ia_fd, reply)) != 0) {
258*d04ccbb3Scarlsonj dhcpmsg(MSG_ERROR, "send_data_reply: dhcp_ipc_send_reply: %s",
259*d04ccbb3Scarlsonj dhcp_ipc_strerror(retval));
260*d04ccbb3Scarlsonj }
261*d04ccbb3Scarlsonj
262*d04ccbb3Scarlsonj /*
263*d04ccbb3Scarlsonj * free the request since we've now used it to send our reply.
264*d04ccbb3Scarlsonj * we can also close the socket since the reply has been sent.
265*d04ccbb3Scarlsonj */
266*d04ccbb3Scarlsonj
267*d04ccbb3Scarlsonj free(reply);
268*d04ccbb3Scarlsonj free(ia->ia_request);
269*d04ccbb3Scarlsonj if (ia->ia_eid != -1)
270*d04ccbb3Scarlsonj (void) iu_unregister_event(eh, ia->ia_eid, NULL);
271*d04ccbb3Scarlsonj (void) dhcp_ipc_close(ia->ia_fd);
272*d04ccbb3Scarlsonj ia->ia_request = NULL;
273*d04ccbb3Scarlsonj ia->ia_fd = -1;
274*d04ccbb3Scarlsonj ia->ia_eid = -1;
2757c478bd9Sstevel@tonic-gate }
276