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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #ifndef INTERFACE_H 27 #define INTERFACE_H 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 /* 32 * interface.[ch] encapsulate all of the agent's knowledge of network 33 * interfaces from the DHCP agent's perspective. see interface.c 34 * for documentation on how to use the exported functions. note that 35 * there are not functional interfaces for manipulating all of the fields 36 * in an ifslist -- please read the comments in the ifslist structure 37 * definition below for the rules on accessing various fields. 38 */ 39 40 #ifdef __cplusplus 41 extern "C" { 42 #endif 43 44 #include <netinet/in.h> 45 #include <sys/socket.h> 46 #include <net/if.h> /* IFNAMSIZ */ 47 #include <sys/types.h> 48 #include <netinet/dhcp.h> 49 #include <dhcpagent_ipc.h> 50 #include <libinetutil.h> 51 52 #include "async.h" 53 #include "agent.h" 54 #include "dlpi_io.h" 55 #include "ipc_action.h" 56 #include "packet.h" 57 #include "util.h" 58 59 enum { DHCP_T1_TIMER, DHCP_T2_TIMER, DHCP_LEASE_TIMER }; 60 61 typedef int script_callback_t (struct ifslist *, const char *); 62 63 struct ifslist { 64 65 /* 66 * ifslist chain pointers, maintained by insert_ifs() / 67 * remove_ifs(). 68 */ 69 70 struct ifslist *next; 71 struct ifslist *prev; 72 73 /* 74 * hold count on this ifslist, maintained by hold_ifs() / 75 * release_ifs() -- see below for a discussion of ifs memory 76 * management. 77 */ 78 79 uchar_t if_hold_count; 80 81 /* 82 * each interface can have at most one pending asynchronous 83 * action, which is represented in a `struct async_action'. 84 * if that asynchronous action was a result of a user request, 85 * then the `struct ipc_action' is used to hold information 86 * about the user request. these structures are opaque to 87 * users of the ifslist, and the functional interfaces 88 * provided in async.[ch] and ipc_action.[ch] should be used 89 * to maintain them. 90 */ 91 92 struct ipc_action if_ia; 93 struct async_action if_async; 94 95 /* 96 * current state of the interface 97 */ 98 99 DHCPSTATE if_state; 100 101 /* 102 * flags specific to DHCP (see dhcpagent_ipc.h) 103 */ 104 105 uint16_t if_dflags; 106 107 /* 108 * general interface information -- this information is initialized 109 * in insert_ifs() and does not change over the lifetime of the 110 * interface. 111 */ 112 113 char if_name[IFNAMSIZ]; 114 115 uint32_t if_index; /* interface index */ 116 117 uint16_t if_max; /* largest DHCP packet on this if */ 118 uint16_t if_min; /* minimum mtu size on this if */ 119 uint16_t if_opt; /* amount of space for options in PKT */ 120 121 uchar_t *if_hwaddr; /* our link-layer address */ 122 uchar_t if_hwlen; /* our link-layer address len */ 123 uchar_t if_hwtype; /* type of link-layer */ 124 125 uchar_t *if_cid; /* client id, if set in defaults file */ 126 uchar_t if_cidlen; /* client id len */ 127 128 uchar_t *if_prl; /* if non-NULL, param request list */ 129 uchar_t if_prllen; /* param request list len */ 130 131 /* 132 * the destination address is the broadcast address of 133 * the interface, in DLPI terms (which means it 134 * includes both a link-layer broadcast address and a 135 * sap, and the order isn't consistent.) fun, huh? 136 * blame AT&T. we store it as a token like this 137 * because it's generally how we need to use it. we 138 * can pull it apart using the saplen and sap_before 139 * fields below. 140 */ 141 142 uchar_t *if_daddr; /* our destination address */ 143 uchar_t if_dlen; /* our destination address len */ 144 145 uchar_t if_saplen; /* the SAP len */ 146 uchar_t if_sap_before; /* does SAP come before address? */ 147 148 /* 149 * network descriptors; one is used for the DLPI 150 * traffic before we have our IP address configured; 151 * the other two are used afterwards. there have to 152 * be two socket descriptors since: 153 * 154 * o we need one to be bound to IPPORT_BOOTPC and 155 * and INADDR_BROADCAST, so it can receive all 156 * broadcast traffic. this is if_sock_fd. it 157 * is also used as a general descriptor to perform 158 * socket-related ioctls on, like SIOCGIFFLAGS. 159 * 160 * o we need another to be bound to IPPORT_BOOTPC and 161 * the IP address given to us by the DHCP server, 162 * so we can guarantee the IP address of outgoing 163 * packets when multihomed. (the problem being that 164 * if a packet goes out with the wrong IP address, 165 * then the server's response will come back on the 166 * wrong interface). this is if_sock_ip_fd. 167 * 168 * note that if_sock_fd is created in init_ifs() but 169 * not bound until dhcp_bound(); this is because we 170 * cannot even bind to the broadcast address until we 171 * have an IP address. 172 * 173 * if_sock_ip_fd isn't created until dhcp_bound(), 174 * since we don't need it until then and we can't 175 * bind it until after we have an IP address anyway. 176 * 177 * both socket descriptors are closed in reset_ifs(). 178 */ 179 180 int if_dlpi_fd; 181 int if_sock_fd; 182 int if_sock_ip_fd; 183 184 /* 185 * the following fields are set when a lease is acquired, and 186 * may be updated over the lifetime of the lease. they are 187 * all reset by reset_ifs(). 188 */ 189 190 iu_timer_id_t if_timer[3]; /* T1, T2, and LEASE timers */ 191 192 lease_t if_t1; /* relative renewal start time, hbo */ 193 lease_t if_t2; /* relative rebinding start time, hbo */ 194 lease_t if_lease; /* relative expire time, hbo */ 195 196 unsigned int if_nrouters; /* the number of default routers */ 197 struct in_addr *if_routers; /* an array of default routers */ 198 struct in_addr if_server; /* our DHCP server, nbo */ 199 200 /* 201 * while in any states except ADOPTING, INIT, INFORMATION and 202 * INFORM_SENT, the following three fields are equal to what 203 * we believe the current address, netmask, and broadcast 204 * address on the interface to be. this is so we can detect 205 * if the user changes them and abandon the interface. 206 */ 207 208 struct in_addr if_addr; /* our IP address, nbo */ 209 struct in_addr if_netmask; /* our netmask, nbo */ 210 struct in_addr if_broadcast; /* our broadcast address, nbo */ 211 212 PKT_LIST *if_ack; /* ACK from the server */ 213 214 /* 215 * We retain the very first ack obtained on the interface to 216 * provide access to options which were originally assigned by 217 * the server but may not have been included in subsequent 218 * acks, as there are servers which do this and customers have 219 * had unsatisfactory results when using our agent with them. 220 * ipc_event() in agent.c provides a fallback to the original 221 * ack when the current ack doesn't have the information 222 * requested. 223 */ 224 225 PKT_LIST *if_orig_ack; 226 227 /* 228 * other miscellaneous variables set or needed in the process 229 * of acquiring a lease. 230 */ 231 232 int if_offer_wait; /* seconds between sending offers */ 233 iu_timer_id_t if_offer_timer; /* timer associated with offer wait */ 234 iu_event_id_t if_offer_id; /* event offer id */ 235 iu_event_id_t if_acknak_id; /* event acknak id */ 236 iu_event_id_t if_acknak_bcast_id; 237 238 /* 239 * `if_neg_monosec' represents the time since lease 240 * acquisition or renewal began, and is used for 241 * computing the pkt->secs field. `if_newstart_monosec' 242 * represents the time the ACKed REQUEST was sent, 243 * which represents the start time of a new lease. 244 * when the lease actually begins (and thus becomes 245 * current), `if_curstart_monosec' is set to 246 * `if_newstart_monosec'. 247 */ 248 249 monosec_t if_neg_monosec; 250 monosec_t if_newstart_monosec; 251 monosec_t if_curstart_monosec; 252 253 /* 254 * time we sent the DISCOVER relative to if_neg_monosec, 255 * so that the REQUEST can have the same pkt->secs. 256 */ 257 258 uint16_t if_disc_secs; 259 260 /* 261 * the host name we've been asked to request is remembered 262 * here between the DISCOVER and the REQUEST 263 */ 264 char *if_reqhost; 265 266 /* 267 * this is a chain of packets which have been received on this 268 * interface over some interval of time. the packets may have 269 * to meet some criteria in order to be put on this list. in 270 * general, packets are put on this list through recv_pkt() 271 */ 272 273 PKT_LIST *if_recv_pkt_list; 274 275 /* 276 * these three fields are initially zero, and get incremented 277 * as the ifslist goes from INIT -> BOUND. if and when the 278 * ifslist moves to the RENEWING state, these fields are 279 * reset, so they always either indicate the number of packets 280 * sent, received, and declined while obtaining the current 281 * lease (if BOUND), or the number of packets sent, received, 282 * and declined while attempting to obtain a future lease 283 * (if any other state). 284 */ 285 286 uint32_t if_sent; 287 uint32_t if_received; 288 uint32_t if_bad_offers; 289 290 /* 291 * if_send_pkt.pkt is dynamically allocated to be as big a 292 * packet as we can send out on this interface. the remainder 293 * of this information is needed to make it easy to handle 294 * retransmissions. note that other than if_bad_offers, all 295 * of these fields are maintained internally in send_pkt(), 296 * and consequently should never need to be modified by any 297 * other functions. 298 */ 299 300 dhcp_pkt_t if_send_pkt; 301 uint32_t if_send_timeout; 302 struct sockaddr_in if_send_dest; 303 stop_func_t *if_send_stop_func; 304 uint32_t if_packet_sent; 305 iu_timer_id_t if_retrans_timer; 306 307 int if_script_fd; 308 pid_t if_script_pid; 309 pid_t if_script_helper_pid; 310 const char *if_script_event; 311 iu_event_id_t if_script_event_id; 312 const char *if_callback_msg; 313 script_callback_t *if_script_callback; 314 }; 315 316 /* 317 * a word on memory management and ifslists: 318 * 319 * since ifslists are often passed as context to callback functions, 320 * they cannot be freed when the interface they represent is dropped 321 * or released (or when those callbacks finally go off, they will be 322 * hosed). to handle this situation, ifslists are reference counted. 323 * here are the rules for managing ifslists: 324 * 325 * an ifslist is created through insert_ifs(). along with 326 * initializing the ifslist, this puts a hold on the ifslist through 327 * hold_ifs(). 328 * 329 * whenever an ifslist is released or dropped (implicitly or 330 * explicitly), remove_ifs() is called, which sets the DHCP_IF_REMOVED 331 * flag and removes the interface from the internal list of managed 332 * interfaces. lastly, remove_ifs() calls release_ifs() to remove the 333 * hold acquired in insert_ifs(). if this decrements the hold count 334 * on the interface to zero, then free_ifs() is called. if there are 335 * holds other than the hold acquired in insert_ifs(), the hold count 336 * will still be > 0, and the interface will remain allocated (though 337 * dormant). 338 * 339 * whenever a callback is scheduled against an ifslist, another hold 340 * must be put on the ifslist through hold_ifs(). 341 * 342 * whenever a callback is called back against an ifslist, 343 * release_ifs() must be called to decrement the hold count, which may 344 * end up freeing the ifslist if the hold count becomes zero. 345 * 346 * if release_ifs() returns 0, then there are no remaining holds 347 * against this ifslist, and the ifslist in fact no longer exists. 348 * 349 * since some callbacks may take a long time to get called back (such 350 * as timeout callbacks for lease expiration, etc), it is sometimes 351 * more appropriate to cancel the callbacks and call release_ifs() if 352 * the cancellation succeeds. this is done in remove_ifs() for the 353 * lease, t1, and t2 callbacks. 354 * 355 * in general, a callback should also call verify_ifs() when it gets 356 * called back in addition to release_ifs(), to make sure that the 357 * interface is still in fact under the dhcpagent's control. to make 358 * coding simpler, there is a third function, check_ifs(), which 359 * performs both the release_ifs() and the verify_ifs(). in addition, 360 * if check_ifs() detects that the callback has the last hold against 361 * a given interface, it informs it instead of performing the final 362 * release, and thus allows it to clean up appropriately before 363 * performing the final release. 364 */ 365 366 int canonize_ifs(struct ifslist *); 367 int check_ifs(struct ifslist *); 368 void hold_ifs(struct ifslist *); 369 struct ifslist *insert_ifs(const char *, boolean_t, int *); 370 struct ifslist *lookup_ifs(const char *); 371 struct ifslist *lookup_ifs_by_xid(uint32_t); 372 struct ifslist *lookup_ifs_by_uindex(uint16_t, struct ifslist *); 373 void nuke_ifslist(boolean_t); 374 void refresh_ifslist(iu_eh_t *, int, void *); 375 int release_ifs(struct ifslist *); 376 void remove_ifs(struct ifslist *); 377 void reset_ifs(struct ifslist *); 378 int verify_ifs(struct ifslist *); 379 unsigned int ifs_count(void); 380 void cancel_ifs_timers(struct ifslist *); 381 int schedule_ifs_timer(struct ifslist *, int, uint32_t, 382 iu_tq_callback_t *); 383 384 #ifdef __cplusplus 385 } 386 #endif 387 388 #endif /* INTERFACE_H */ 389