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 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>. 25 */ 26 27 #ifndef STATES_H 28 #define STATES_H 29 30 #include <sys/types.h> 31 #include <netinet/in.h> 32 #include <netinet/dhcp.h> 33 #include <libinetutil.h> 34 35 #include "common.h" 36 #include "ipc_action.h" 37 #include "async.h" 38 #include "packet.h" 39 #include "util.h" 40 41 /* 42 * interfaces for state transition/action functions. these functions 43 * can be found in suitably named .c files, such as inform.c, select.c, 44 * renew.c, etc. 45 */ 46 47 #ifdef __cplusplus 48 extern "C" { 49 #endif 50 51 /* 52 * DHCP state machine representation: includes all of the information used for 53 * a state machine instance. For IPv4, this represents a single logical 54 * interface and (usually) a leased address. For IPv6, it represents a 55 * DUID+IAID combination. Note that if multiple DUID+IAID instances are one 56 * day allowed per interface, this will need to become a list. 57 */ 58 struct dhcp_smach_s { 59 dhcp_smach_t *dsm_next; /* Note: must be first */ 60 dhcp_smach_t *dsm_prev; 61 62 /* 63 * The name of the state machine. This is currently just a pointer to 64 * the controlling LIF's name, but could be otherwise. 65 */ 66 const char *dsm_name; 67 dhcp_lif_t *dsm_lif; /* Controlling LIF */ 68 uint_t dsm_hold_count; /* reference count */ 69 70 dhcp_lease_t *dsm_leases; /* List of leases */ 71 uint_t dsm_lif_wait; /* LIFs waiting on DAD */ 72 uint_t dsm_lif_down; /* LIFs failed */ 73 74 /* 75 * each state machine can have at most one pending asynchronous 76 * action, which is represented in a `struct async_action'. 77 * if that asynchronous action was a result of a user request, 78 * then the `struct ipc_action' is used to hold information 79 * about the user request. these structures are opaque to 80 * users of the ifslist, and the functional interfaces 81 * provided in async.[ch] and ipc_action.[ch] should be used 82 * to maintain them. 83 */ 84 85 ipc_action_t dsm_ia; 86 async_action_t dsm_async; 87 88 uchar_t *dsm_cid; /* client id */ 89 uchar_t dsm_cidlen; /* client id len */ 90 91 /* 92 * current state of the machine 93 */ 94 95 DHCPSTATE dsm_state; 96 boolean_t dsm_droprelease; /* soon to call finished_smach */ 97 98 uint16_t dsm_dflags; /* DHCP_IF_* (shared with IPC) */ 99 100 uint16_t *dsm_prl; /* if non-NULL, param request list */ 101 uint_t dsm_prllen; /* param request list len */ 102 uint16_t *dsm_pil; /* if non-NULL, param ignore list */ 103 uint_t dsm_pillen; /* param ignore 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 * The host name we've been asked by IPC message (e.g., 206 * `ipadm -T dhcp -h ...') to request is remembered here until it is 207 * reset by another external message. 208 */ 209 char *dsm_msg_reqhost; 210 211 /* 212 * The domain name returned for v4 DNSdmain is decoded here for use 213 * (if configured and needed) to determine an FQDN. 214 */ 215 char *dsm_dhcp_domainname; 216 217 /* 218 * V4 and V6 use slightly different timers. For v4, we must count 219 * seconds from the point where we first try to configure the 220 * interface. For v6, only seconds while performing a transaction 221 * matter. 222 * 223 * In v4, `dsm_neg_hrtime' represents the time since DHCP started 224 * configuring the interface, and is used for computing the pkt->secs 225 * field in v4. In v6, it represents the time since the current 226 * transaction (if any) was started, and is used for the ELAPSED_TIME 227 * option. 228 * 229 * `dsm_newstart_monosec' represents the time the ACKed REQUEST was 230 * sent, which represents the start time of a new batch of leases. 231 * When the lease time actually begins (and thus becomes current), 232 * `dsm_curstart_monosec' is set to `dsm_newstart_monosec'. 233 */ 234 hrtime_t dsm_neg_hrtime; 235 monosec_t dsm_newstart_monosec; 236 monosec_t dsm_curstart_monosec; 237 238 int dsm_script_fd; 239 pid_t dsm_script_pid; 240 pid_t dsm_script_helper_pid; 241 const char *dsm_script_event; 242 iu_event_id_t dsm_script_event_id; 243 void *dsm_callback_arg; 244 script_callback_t *dsm_script_callback; 245 246 iu_timer_id_t dsm_start_timer; 247 }; 248 249 #define dsm_isv6 dsm_lif->lif_pif->pif_isv6 250 #define dsm_hwtype dsm_lif->lif_pif->pif_hwtype 251 252 struct dhcp_lease_s { 253 dhcp_lease_t *dl_next; /* Note: must be first */ 254 dhcp_lease_t *dl_prev; 255 256 dhcp_smach_t *dl_smach; /* back pointer to state machine */ 257 dhcp_lif_t *dl_lifs; /* LIFs configured by this lease */ 258 uint_t dl_nlifs; /* Number of configured LIFs */ 259 uint_t dl_hold_count; /* reference counter */ 260 boolean_t dl_removed; /* Set if removed from list */ 261 boolean_t dl_stale; /* not updated by Renew/bind */ 262 263 /* 264 * the following fields are set when a lease is acquired, and 265 * may be updated over the lifetime of the lease. they are 266 * all reset by reset_smach(). 267 */ 268 269 dhcp_timer_t dl_t1; /* relative renewal start time, hbo */ 270 dhcp_timer_t dl_t2; /* relative rebinding start time, hbo */ 271 }; 272 273 /* The IU event callback functions */ 274 iu_eh_callback_t dhcp_acknak_global; 275 iu_eh_callback_t dhcp_packet_lif; 276 277 /* Common state-machine related routines throughout dhcpagent */ 278 boolean_t dhcp_adopt(void); 279 void dhcp_adopt_complete(dhcp_smach_t *); 280 boolean_t dhcp_bound(dhcp_smach_t *, PKT_LIST *); 281 void dhcp_bound_complete(dhcp_smach_t *); 282 int dhcp_drop(dhcp_smach_t *, void *); 283 void dhcp_deprecate(iu_tq_t *, void *); 284 void dhcp_expire(iu_tq_t *, void *); 285 boolean_t dhcp_extending(dhcp_smach_t *); 286 void dhcp_inform(dhcp_smach_t *); 287 void dhcp_init_reboot(dhcp_smach_t *); 288 void dhcp_rebind(iu_tq_t *, void *); 289 int dhcp_release(dhcp_smach_t *, void *); 290 void dhcp_renew(iu_tq_t *, void *); 291 void dhcp_requesting(iu_tq_t *, void *); 292 void dhcp_restart(dhcp_smach_t *); 293 void dhcp_selecting(dhcp_smach_t *); 294 boolean_t set_start_timer(dhcp_smach_t *); 295 void send_declines(dhcp_smach_t *); 296 void send_v6_request(dhcp_smach_t *); 297 boolean_t save_server_id(dhcp_smach_t *, PKT_LIST *); 298 void server_unicast_option(dhcp_smach_t *, PKT_LIST *); 299 300 /* State machine support functions in states.c */ 301 dhcp_smach_t *insert_smach(dhcp_lif_t *, int *); 302 void hold_smach(dhcp_smach_t *); 303 void release_smach(dhcp_smach_t *); 304 void remove_smach(dhcp_smach_t *); 305 dhcp_smach_t *next_smach(dhcp_smach_t *, boolean_t); 306 dhcp_smach_t *primary_smach(boolean_t); 307 dhcp_smach_t *info_primary_smach(boolean_t); 308 void make_primary(dhcp_smach_t *); 309 dhcp_smach_t *lookup_smach(const char *, boolean_t); 310 dhcp_smach_t *lookup_smach_by_uindex(uint16_t, dhcp_smach_t *, boolean_t); 311 dhcp_smach_t *lookup_smach_by_xid(uint32_t, dhcp_smach_t *, boolean_t); 312 dhcp_smach_t *lookup_smach_by_event(iu_event_id_t); 313 void finished_smach(dhcp_smach_t *, int); 314 boolean_t set_smach_state(dhcp_smach_t *, DHCPSTATE); 315 int get_smach_cid(dhcp_smach_t *); 316 boolean_t verify_smach(dhcp_smach_t *); 317 uint_t smach_count(void); 318 void reset_smach(dhcp_smach_t *); 319 void refresh_smachs(iu_eh_t *, int, void *); 320 void refresh_smach(dhcp_smach_t *); 321 void nuke_smach_list(void); 322 boolean_t schedule_smach_timer(dhcp_smach_t *, int, uint32_t, 323 iu_tq_callback_t *); 324 void cancel_offer_timer(dhcp_smach_t *); 325 void cancel_smach_timers(dhcp_smach_t *); 326 void discard_default_routes(dhcp_smach_t *); 327 void remove_default_routes(dhcp_smach_t *); 328 boolean_t is_bound_state(DHCPSTATE); 329 330 /* Lease-related support functions in states.c */ 331 dhcp_lease_t *insert_lease(dhcp_smach_t *); 332 void hold_lease(dhcp_lease_t *); 333 void release_lease(dhcp_lease_t *); 334 void remove_lease(dhcp_lease_t *); 335 void deprecate_leases(dhcp_smach_t *); 336 void cancel_lease_timers(dhcp_lease_t *); 337 boolean_t schedule_lease_timer(dhcp_lease_t *, dhcp_timer_t *, 338 iu_tq_callback_t *); 339 340 #ifdef __cplusplus 341 } 342 #endif 343 344 #endif /* STATES_H */ 345