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, 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 determined FQDN is remembered here between the DISCOVER/SOLICIT
 213          * and the REQUEST.
 214          */
 215         char            *dsm_reqfqdn;
 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 */