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