xref: /titanic_52/usr/src/cmd/cmd-inet/sbin/dhcpagent/ipc_action.c (revision f63f7506be0210195779706f51c58646e568cc40)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/poll.h>
31 #include <dhcpmsg.h>
32 
33 #include "interface.h"
34 #include "ipc_action.h"
35 #include "util.h"
36 
37 static iu_tq_callback_t	ipc_action_timeout;
38 
39 /*
40  * ipc_action_init(): initializes the ipc_action structure
41  *
42  *   input: struct ifslist *: the interface to initialize it for
43  *  output: void
44  */
45 
46 void
47 ipc_action_init(struct ifslist *ifsp)
48 {
49 	ifsp->if_ia.ia_tid = -1;
50 }
51 
52 /*
53  * ipc_action_start(): starts an ipc_action request on an interface
54  *
55  *   input: struct ifslist *: the interface to start the action on
56  *	    dhcp_ipc_request_t *: the type of request
57  *	    int: the descriptor to contact the action requestor
58  *  output: int: 1 if the request is started successfully, 0 otherwise
59  */
60 
61 int
62 ipc_action_start(struct ifslist *ifsp, dhcp_ipc_request_t *request, int fd)
63 {
64 	if (request->timeout == DHCP_IPC_WAIT_DEFAULT)
65 		request->timeout = DHCP_IPC_DEFAULT_WAIT;
66 
67 	ifsp->if_ia.ia_request	= request;
68 	ifsp->if_ia.ia_fd	= fd;
69 	ifsp->if_ia.ia_cmd	= DHCP_IPC_CMD(request->message_type);
70 
71 	if (request->timeout == DHCP_IPC_WAIT_FOREVER)
72 		ifsp->if_ia.ia_tid = -1;
73 	else {
74 		ifsp->if_ia.ia_tid = iu_schedule_timer(tq, request->timeout,
75 		    ipc_action_timeout, ifsp);
76 
77 		if (ifsp->if_ia.ia_tid == -1)
78 			return (0);
79 
80 		hold_ifs(ifsp);
81 	}
82 
83 	return (1);
84 }
85 
86 /*
87  * ipc_action_pending(): checks if there is a pending ipc_action request on
88  *			 an interface
89  *
90  *   input: struct ifslist *: the interface to check for a pending ipc_action on
91  *  output: boolean_t: B_TRUE if there is a pending ipc_action request
92  */
93 
94 boolean_t
95 ipc_action_pending(struct ifslist *ifsp)
96 {
97 	struct pollfd		pollfd;
98 
99 	if (ifsp->if_ia.ia_fd > 0) {
100 
101 		pollfd.events	= POLLIN;
102 		pollfd.fd	= ifsp->if_ia.ia_fd;
103 
104 		if (poll(&pollfd, 1, 0) == 0)
105 			return (B_TRUE);
106 	}
107 
108 	return (B_FALSE);
109 }
110 
111 /*
112  * ipc_action_finish(): completes an ipc_action request on an interface
113  *
114  *   input: struct ifslist *: the interface to complete the action on
115  *	    int: the reason why the action finished (nonzero on error)
116  *  output: void
117  */
118 
119 void
120 ipc_action_finish(struct ifslist *ifsp, int reason)
121 {
122 	struct ipc_action *ia = &ifsp->if_ia;
123 
124 	if (ipc_action_pending(ifsp) == B_FALSE)
125 		return;
126 
127 	if (reason == 0)
128 		send_ok_reply(ia->ia_request, &ia->ia_fd);
129 	else
130 		send_error_reply(ia->ia_request, reason, &ia->ia_fd);
131 
132 	ipc_action_cancel_timer(ifsp);
133 }
134 
135 /*
136  * ipc_action_timeout(): times out an ipc_action on an interface (the request
137  *			 continues asynchronously, however)
138  *
139  *   input: iu_tq_t *: unused
140  *	    void *: the struct ifslist * the ipc_action was pending on
141  *  output: void
142  */
143 
144 /* ARGSUSED */
145 static void
146 ipc_action_timeout(iu_tq_t *tq, void *arg)
147 {
148 	struct ifslist		*ifsp = (struct ifslist *)arg;
149 	struct ipc_action	*ia = &ifsp->if_ia;
150 
151 	if (check_ifs(ifsp) == 0) {
152 		(void) release_ifs(ifsp);
153 		return;
154 	}
155 
156 	dhcpmsg(MSG_VERBOSE, "ipc timeout waiting for agent to complete "
157 	    "command %d for %s", ia->ia_cmd, ifsp->if_name);
158 
159 	send_error_reply(ia->ia_request, DHCP_IPC_E_TIMEOUT, &ia->ia_fd);
160 	ia->ia_tid = -1;
161 }
162 
163 /*
164  * ipc_action_cancel_timer(): cancels the pending ipc_action timer for this
165  *			      request
166  *
167  *   input: struct ifslist *: the interface with a pending request to cancel
168  *  output: void
169  */
170 
171 void
172 ipc_action_cancel_timer(struct ifslist *ifsp)
173 {
174 	if (ifsp->if_ia.ia_tid == -1)
175 		return;
176 
177 	/*
178 	 * if we can't cancel this timer, we're really in the
179 	 * twilight zone.  however, as long as we don't drop the
180 	 * reference to the ifsp, it shouldn't hurt us
181 	 */
182 
183 	if (iu_cancel_timer(tq, ifsp->if_ia.ia_tid, NULL) == 1) {
184 		ifsp->if_ia.ia_tid = -1;
185 		(void) release_ifs(ifsp);
186 	}
187 }
188