xref: /illumos-gate/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #ifndef	STATES_H
27 #define	STATES_H
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <sys/types.h>
32 #include <netinet/in.h>
33 #include <netinet/dhcp.h>
34 #include <libinetutil.h>
35 
36 #include "common.h"
37 #include "ipc_action.h"
38 #include "async.h"
39 #include "packet.h"
40 #include "util.h"
41 
42 /*
43  * interfaces for state transition/action functions.  these functions
44  * can be found in suitably named .c files, such as inform.c, select.c,
45  * renew.c, etc.
46  */
47 
48 #ifdef	__cplusplus
49 extern "C" {
50 #endif
51 
52 /*
53  * DHCP state machine representation: includes all of the information used for
54  * a state machine instance.  For IPv4, this represents a single logical
55  * interface and (usually) a leased address.  For IPv6, it represents a
56  * DUID+IAID combination.  Note that if multiple DUID+IAID instances are one
57  * day allowed per interface, this will need to become a list.
58  */
59 struct dhcp_smach_s {
60 	dhcp_smach_t		*dsm_next;	/* Note: must be first */
61 	dhcp_smach_t		*dsm_prev;
62 
63 	/*
64 	 * The name of the state machine.  This is currently just a pointer to
65 	 * the controlling LIF's name, but could be otherwise.
66 	 */
67 	const char		*dsm_name;
68 	dhcp_lif_t		*dsm_lif;	/* Controlling LIF */
69 	uint_t			dsm_hold_count;	/* reference count */
70 
71 	dhcp_lease_t		*dsm_leases;	/* List of leases */
72 	uint_t			dsm_lif_wait;	/* LIFs waiting on DAD */
73 	uint_t			dsm_lif_down;	/* LIFs failed */
74 
75 	boolean_t		dsm_using_dlpi;
76 
77 	/*
78 	 * each state machine can have at most one pending asynchronous
79 	 * action, which is represented in a `struct async_action'.
80 	 * if that asynchronous action was a result of a user request,
81 	 * then the `struct ipc_action' is used to hold information
82 	 * about the user request.  these structures are opaque to
83 	 * users of the ifslist, and the functional interfaces
84 	 * provided in async.[ch] and ipc_action.[ch] should be used
85 	 * to maintain them.
86 	 */
87 
88 	ipc_action_t		dsm_ia;
89 	async_action_t		dsm_async;
90 
91 	uchar_t		*dsm_cid;	/* client id */
92 	uchar_t		dsm_cidlen;	/* client id len */
93 
94 	/*
95 	 * current state of the machine
96 	 */
97 
98 	DHCPSTATE		dsm_state;
99 
100 	uint16_t	dsm_dflags;	/* DHCP_IF_* (shared with IPC) */
101 
102 	uint16_t	*dsm_prl;	/* if non-NULL, param request list */
103 	uint_t		dsm_prllen;	/* param request list len */
104 
105 	uint_t		dsm_nrouters;	/* the number of default routers */
106 	struct in_addr	*dsm_routers;	/* an array of default routers */
107 
108 	in6_addr_t	dsm_server;	/* our DHCP server */
109 	uchar_t		*dsm_serverid;	/* server DUID for v6 */
110 	uint_t		dsm_serveridlen; /* DUID length */
111 
112 	/*
113 	 * We retain the very first ack obtained on the state machine to
114 	 * provide access to options which were originally assigned by
115 	 * the server but may not have been included in subsequent
116 	 * acks, as there are servers which do this and customers have
117 	 * had unsatisfactory results when using our agent with them.
118 	 * ipc_event() in agent.c provides a fallback to the original
119 	 * ack when the current ack doesn't have the information
120 	 * requested.
121 	 *
122 	 * Note that neither of these is actually a list of packets.  There's
123 	 * exactly one packet here, so use free_pkt_entry.
124 	 */
125 	PKT_LIST	*dsm_ack;
126 	PKT_LIST	*dsm_orig_ack;
127 
128 	/*
129 	 * other miscellaneous variables set or needed in the process
130 	 * of acquiring a lease.
131 	 */
132 
133 	int		dsm_offer_wait;	/* seconds between sending offers */
134 	iu_timer_id_t	dsm_offer_timer; /* timer associated with offer wait */
135 
136 	/*
137 	 * time we sent the DISCOVER relative to dsm_neg_hrtime, so that the
138 	 * REQUEST can have the same pkt->secs.
139 	 */
140 
141 	uint16_t		dsm_disc_secs;
142 
143 	/*
144 	 * this is a chain of packets which have been received on this
145 	 * state machine over some interval of time.  the packets may have
146 	 * to meet some criteria in order to be put on this list.  in
147 	 * general, packets are put on this list through recv_pkt()
148 	 */
149 
150 	PKT_LIST		*dsm_recv_pkt_list;
151 
152 	/*
153 	 * these three fields are initially zero, and get incremented
154 	 * as the ifslist goes from INIT -> BOUND.  if and when the
155 	 * ifslist moves to the RENEWING state, these fields are
156 	 * reset, so they always either indicate the number of packets
157 	 * sent, received, and declined while obtaining the current
158 	 * lease (if BOUND), or the number of packets sent, received,
159 	 * and declined while attempting to obtain a future lease
160 	 * (if any other state).
161 	 */
162 
163 	uint32_t		dsm_sent;
164 	uint32_t		dsm_received;
165 	uint32_t		dsm_bad_offers;
166 
167 	/*
168 	 * dsm_send_pkt.pkt is dynamically allocated to be as big a
169 	 * packet as we can send out on this state machine.  the remainder
170 	 * of this information is needed to make it easy to handle
171 	 * retransmissions.  note that other than dsm_bad_offers, all
172 	 * of these fields are maintained internally in send_pkt(),
173 	 * and consequently should never need to be modified by any
174 	 * other functions.
175 	 */
176 
177 	dhcp_pkt_t		dsm_send_pkt;
178 	union {
179 		struct sockaddr_in v4;
180 		struct sockaddr_in6 v6;
181 	} dsm_send_dest;
182 
183 	/*
184 	 * For v4, dsm_send_tcenter is used to track the central timer value in
185 	 * milliseconds (4000, 8000, 16000, 32000, 64000), and dsm_send_timeout
186 	 * is that value plus the +/- 1000 millisecond fuzz.
187 	 *
188 	 * For v6, dsm_send_tcenter is the MRT (maximum retransmit timer)
189 	 * value, and dsm_send_timeout must be set to the IRT (initial
190 	 * retransmit timer) value by the sender.
191 	 */
192 	uint_t			dsm_send_timeout;
193 	uint_t			dsm_send_tcenter;
194 	stop_func_t		*dsm_send_stop_func;
195 	uint32_t		dsm_packet_sent;
196 	iu_timer_id_t		dsm_retrans_timer;
197 
198 	/*
199 	 * The host name we've been asked to request is remembered
200 	 * here between the DISCOVER and the REQUEST.  (v4 only)
201 	 */
202 	char		*dsm_reqhost;
203 
204 	/*
205 	 * V4 and V6 use slightly different timers.  For v4, we must count
206 	 * seconds from the point where we first try to configure the
207 	 * interface.  For v6, only seconds while performing a transaction
208 	 * matter.
209 	 *
210 	 * In v4, `dsm_neg_hrtime' represents the time since DHCP started
211 	 * configuring the interface, and is used for computing the pkt->secs
212 	 * field in v4.  In v6, it represents the time since the current
213 	 * transaction (if any) was started, and is used for the ELAPSED_TIME
214 	 * option.
215 	 *
216 	 * `dsm_newstart_monosec' represents the time the ACKed REQUEST was
217 	 * sent, which represents the start time of a new batch of leases.
218 	 * When the lease time actually begins (and thus becomes current),
219 	 * `dsm_curstart_monosec' is set to `dsm_newstart_monosec'.
220 	 */
221 	hrtime_t		dsm_neg_hrtime;
222 	monosec_t		dsm_newstart_monosec;
223 	monosec_t		dsm_curstart_monosec;
224 
225 	int			dsm_script_fd;
226 	pid_t			dsm_script_pid;
227 	pid_t			dsm_script_helper_pid;
228 	const char		*dsm_script_event;
229 	iu_event_id_t		dsm_script_event_id;
230 	void			*dsm_callback_arg;
231 	script_callback_t	*dsm_script_callback;
232 };
233 
234 #define	dsm_isv6	dsm_lif->lif_pif->pif_isv6
235 #define	dsm_hwtype	dsm_lif->lif_pif->pif_hwtype
236 
237 struct dhcp_lease_s {
238 	dhcp_lease_t	*dl_next;	/* Note: must be first */
239 	dhcp_lease_t	*dl_prev;
240 
241 	dhcp_smach_t	*dl_smach;	/* back pointer to state machine */
242 	dhcp_lif_t	*dl_lifs;	/* LIFs configured by this lease */
243 	uint_t		dl_nlifs;	/* Number of configured LIFs */
244 	uint_t		dl_hold_count;	/* reference counter */
245 	boolean_t	dl_removed;	/* Set if removed from list */
246 	boolean_t	dl_stale;	/* not updated by Renew/bind */
247 
248 	/*
249 	 * the following fields are set when a lease is acquired, and
250 	 * may be updated over the lifetime of the lease.  they are
251 	 * all reset by reset_smach().
252 	 */
253 
254 	dhcp_timer_t	dl_t1;		/* relative renewal start time, hbo */
255 	dhcp_timer_t	dl_t2;		/* relative rebinding start time, hbo */
256 };
257 
258 /* The IU event callback functions */
259 iu_eh_callback_t	dhcp_acknak_common;
260 iu_eh_callback_t	dhcp_acknak_lif;
261 iu_eh_callback_t	dhcp_collect_dlpi;
262 
263 /* Common state-machine related routines throughout dhcpagent */
264 boolean_t	dhcp_adopt(void);
265 void		dhcp_adopt_complete(dhcp_smach_t *);
266 boolean_t	dhcp_bound(dhcp_smach_t *, PKT_LIST *);
267 void		dhcp_bound_complete(dhcp_smach_t *);
268 int		dhcp_drop(dhcp_smach_t *, void *);
269 void		dhcp_deprecate(iu_tq_t *, void *);
270 void		dhcp_expire(iu_tq_t *, void *);
271 boolean_t	dhcp_extending(dhcp_smach_t *);
272 void		dhcp_inform(dhcp_smach_t *);
273 void		dhcp_init_reboot(dhcp_smach_t *);
274 void		dhcp_rebind(iu_tq_t *, void *);
275 int		dhcp_release(dhcp_smach_t *, void *);
276 void		dhcp_renew(iu_tq_t *, void *);
277 void		dhcp_requesting(iu_tq_t *, void *);
278 void		dhcp_restart(dhcp_smach_t *);
279 void		dhcp_selecting(dhcp_smach_t *);
280 void		dhcp_start(iu_tq_t *, void *);
281 void		send_declines(dhcp_smach_t *);
282 void		send_v6_request(dhcp_smach_t *);
283 boolean_t	save_server_id(dhcp_smach_t *, PKT_LIST *);
284 void		server_unicast_option(dhcp_smach_t *, PKT_LIST *);
285 
286 /* State machine support functions in states.c */
287 dhcp_smach_t	*insert_smach(dhcp_lif_t *, int *);
288 void		hold_smach(dhcp_smach_t *);
289 void		release_smach(dhcp_smach_t *);
290 dhcp_smach_t	*next_smach(dhcp_smach_t *, boolean_t);
291 dhcp_smach_t	*primary_smach(boolean_t);
292 void		make_primary(dhcp_smach_t *);
293 dhcp_smach_t	*lookup_smach(const char *, boolean_t);
294 dhcp_smach_t	*lookup_smach_by_uindex(uint16_t, dhcp_smach_t *, boolean_t);
295 dhcp_smach_t	*lookup_smach_by_xid(uint32_t, dhcp_smach_t *, boolean_t);
296 dhcp_smach_t	*lookup_smach_by_event(iu_event_id_t);
297 void		finished_smach(dhcp_smach_t *, int);
298 boolean_t	set_smach_state(dhcp_smach_t *, DHCPSTATE);
299 int		get_smach_cid(dhcp_smach_t *);
300 boolean_t	verify_smach(dhcp_smach_t *);
301 uint_t		smach_count(void);
302 void		reset_smach(dhcp_smach_t *);
303 void		refresh_smachs(iu_eh_t *, int, void *);
304 void		refresh_smach(dhcp_smach_t *);
305 void		nuke_smach_list(void);
306 boolean_t	schedule_smach_timer(dhcp_smach_t *, int, uint32_t,
307 		    iu_tq_callback_t *);
308 void		cancel_offer_timer(dhcp_smach_t *);
309 void		remove_default_routes(dhcp_smach_t *);
310 
311 /* Lease-related support functions in states.c */
312 dhcp_lease_t	*insert_lease(dhcp_smach_t *);
313 void		hold_lease(dhcp_lease_t *);
314 void		release_lease(dhcp_lease_t *);
315 void		remove_lease(dhcp_lease_t *);
316 void		deprecate_leases(dhcp_smach_t *);
317 void		cancel_lease_timers(dhcp_lease_t *);
318 boolean_t	schedule_lease_timer(dhcp_lease_t *, dhcp_timer_t *,
319 		    iu_tq_callback_t *);
320 
321 #ifdef	__cplusplus
322 }
323 #endif
324 
325 #endif	/* STATES_H */
326