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