xref: /titanic_41/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c (revision 3af08d828975d7e2581b6829e0eecff14d87a483)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <locale.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <stdio_ext.h>
37 #include <dhcp_hostconf.h>
38 #include <dhcpagent_ipc.h>
39 #include <dhcpmsg.h>
40 #include <netinet/dhcp.h>
41 #include <net/route.h>
42 #include <sys/sockio.h>
43 
44 #include "async.h"
45 #include "agent.h"
46 #include "script_handler.h"
47 #include "util.h"
48 #include "class_id.h"
49 #include "states.h"
50 #include "packet.h"
51 
52 #ifndef	TEXT_DOMAIN
53 #define	TEXT_DOMAIN	"SYS_TEST"
54 #endif
55 
56 iu_timer_id_t		inactivity_id;
57 int			class_id_len = 0;
58 char			*class_id;
59 iu_eh_t			*eh;
60 iu_tq_t			*tq;
61 pid_t			grandparent;
62 int			rtsock_fd;
63 
64 static boolean_t	shutdown_started = B_FALSE;
65 static boolean_t	do_adopt = B_FALSE;
66 static unsigned int	debug_level = 0;
67 static iu_eh_callback_t	accept_event, ipc_event, rtsock_event;
68 
69 /*
70  * The ipc_cmd_allowed[] table indicates which IPC commands are allowed in
71  * which states; a non-zero value indicates the command is permitted.
72  *
73  * START is permitted if the interface is fresh, or if we are in the process
74  * of trying to obtain a lease (as a convenience to save the administrator
75  * from having to do an explicit DROP).  EXTEND, RELEASE, and GET_TAG require
76  * a lease to be obtained in order to make sense.  INFORM is permitted if the
77  * interface is fresh or has an INFORM in progress or previously done on it --
78  * otherwise a DROP or RELEASE is first required.  PING and STATUS always make
79  * sense and thus are always permitted, as is DROP in order to permit the
80  * administrator to always bail out.
81  */
82 static int ipc_cmd_allowed[DHCP_NSTATES][DHCP_NIPC] = {
83 	/*			  D  E	P  R  S	 S  I  G */
84 	/*			  R  X	I  E  T	 T  N  E */
85 	/*			  O  T	N  L  A	 A  F  T */
86 	/*			  P  E	G  E  R	 T  O  _ */
87 	/*			  .  N  .  A  T  U  R  T */
88 	/*			  .  D	.  S  .  S  M  A */
89 	/*			  .  .  .  E  .  .  .  G */
90 	/* INIT		*/	{ 1, 0, 1, 0, 1, 1, 1, 0 },
91 	/* SELECTING	*/	{ 1, 0, 1, 0, 1, 1, 0, 0 },
92 	/* REQUESTING	*/	{ 1, 0, 1, 0, 1, 1, 0, 0 },
93 	/* PRE_BOUND	*/	{ 1, 1, 1, 1, 0, 1, 0, 1 },
94 	/* BOUND	*/	{ 1, 1, 1, 1, 0, 1, 0, 1 },
95 	/* RENEWING	*/	{ 1, 1, 1, 1, 0, 1, 0, 1 },
96 	/* REBINDING	*/	{ 1, 1, 1, 1, 0, 1, 0, 1 },
97 	/* INFORMATION  */	{ 1, 0, 1, 0, 0, 1, 1, 1 },
98 	/* INIT_REBOOT  */	{ 1, 0, 1, 0, 1, 1, 0, 0 },
99 	/* ADOPTING	*/	{ 1, 0, 1, 0, 0, 1, 0, 0 },
100 	/* INFORM_SENT  */	{ 1, 0, 1, 0, 0, 1, 1, 0 }
101 };
102 
103 int
104 main(int argc, char **argv)
105 {
106 	boolean_t	is_daemon  = B_TRUE;
107 	boolean_t	is_verbose = B_FALSE;
108 	int		ipc_fd;
109 	int		c;
110 	struct rlimit	rl;
111 
112 	/*
113 	 * -l is ignored for compatibility with old agent.
114 	 */
115 
116 	while ((c = getopt(argc, argv, "vd:l:fa")) != EOF) {
117 
118 		switch (c) {
119 
120 		case 'a':
121 			do_adopt = B_TRUE;
122 			grandparent = getpid();
123 			break;
124 
125 		case 'd':
126 			debug_level = strtoul(optarg, NULL, 0);
127 			break;
128 
129 		case 'f':
130 			is_daemon = B_FALSE;
131 			break;
132 
133 		case 'v':
134 			is_verbose = B_TRUE;
135 			break;
136 
137 		case '?':
138 			(void) fprintf(stderr, "usage: %s [-a] [-d n] [-f] [-v]"
139 			    "\n", argv[0]);
140 			return (EXIT_FAILURE);
141 
142 		default:
143 			break;
144 		}
145 	}
146 
147 	(void) setlocale(LC_ALL, "");
148 	(void) textdomain(TEXT_DOMAIN);
149 
150 	if (geteuid() != 0) {
151 		dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level);
152 		dhcpmsg(MSG_ERROR, "must be super-user");
153 		dhcpmsg_fini();
154 		return (EXIT_FAILURE);
155 	}
156 
157 	if (is_daemon && daemonize() == 0) {
158 		dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level);
159 		dhcpmsg(MSG_ERR, "cannot become daemon, exiting");
160 		dhcpmsg_fini();
161 		return (EXIT_FAILURE);
162 	}
163 
164 	dhcpmsg_init(argv[0], is_daemon, is_verbose, debug_level);
165 	(void) atexit(dhcpmsg_fini);
166 
167 	tq = iu_tq_create();
168 	eh = iu_eh_create();
169 
170 	if (eh == NULL || tq == NULL) {
171 		errno = ENOMEM;
172 		dhcpmsg(MSG_ERR, "cannot create timer queue or event handler");
173 		return (EXIT_FAILURE);
174 	}
175 
176 	/*
177 	 * ignore most signals that could be reasonably generated.
178 	 */
179 
180 	(void) signal(SIGTERM, graceful_shutdown);
181 	(void) signal(SIGQUIT, graceful_shutdown);
182 	(void) signal(SIGPIPE, SIG_IGN);
183 	(void) signal(SIGUSR1, SIG_IGN);
184 	(void) signal(SIGUSR2, SIG_IGN);
185 	(void) signal(SIGINT,  SIG_IGN);
186 	(void) signal(SIGHUP,  SIG_IGN);
187 	(void) signal(SIGCHLD, SIG_IGN);
188 
189 	/*
190 	 * upon SIGTHAW we need to refresh any non-infinite leases.
191 	 */
192 
193 	(void) iu_eh_register_signal(eh, SIGTHAW, refresh_ifslist, NULL);
194 
195 	class_id = get_class_id();
196 	if (class_id != NULL)
197 		class_id_len = strlen(class_id);
198 	else
199 		dhcpmsg(MSG_WARNING, "get_class_id failed, continuing "
200 		    "with no vendor class id");
201 
202 	/*
203 	 * the inactivity timer is enabled any time there are no
204 	 * interfaces under DHCP control.  if DHCP_INACTIVITY_WAIT
205 	 * seconds transpire without an interface under DHCP control,
206 	 * the agent shuts down.
207 	 */
208 
209 	inactivity_id = iu_schedule_timer(tq, DHCP_INACTIVITY_WAIT,
210 	    inactivity_shutdown, NULL);
211 
212 	/*
213 	 * max out the number available descriptors, just in case..
214 	 */
215 
216 	rl.rlim_cur = RLIM_INFINITY;
217 	rl.rlim_max = RLIM_INFINITY;
218 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
219 		dhcpmsg(MSG_ERR, "setrlimit failed");
220 
221 	(void) enable_extended_FILE_stdio(-1, -1);
222 
223 	/*
224 	 * create the ipc channel that the agent will listen for
225 	 * requests on, and register it with the event handler so that
226 	 * `accept_event' will be called back.
227 	 */
228 
229 	switch (dhcp_ipc_init(&ipc_fd)) {
230 
231 	case 0:
232 		break;
233 
234 	case DHCP_IPC_E_BIND:
235 		dhcpmsg(MSG_ERROR, "dhcp_ipc_init: cannot bind to port "
236 		    "%i (agent already running?)", IPPORT_DHCPAGENT);
237 		return (EXIT_FAILURE);
238 
239 	default:
240 		dhcpmsg(MSG_ERROR, "dhcp_ipc_init failed");
241 		return (EXIT_FAILURE);
242 	}
243 
244 	if (iu_register_event(eh, ipc_fd, POLLIN, accept_event, 0) == -1) {
245 		dhcpmsg(MSG_ERR, "cannot register ipc fd for messages");
246 		return (EXIT_FAILURE);
247 	}
248 
249 	/*
250 	 * Create the global routing socket.  This is used for monitoring
251 	 * interface transitions, so that we learn about the kernel's Duplicate
252 	 * Address Detection status, and for inserting and removing default
253 	 * routes as learned from DHCP servers.
254 	 */
255 	rtsock_fd = socket(PF_ROUTE, SOCK_RAW, AF_INET);
256 	if (rtsock_fd == -1) {
257 		dhcpmsg(MSG_ERR, "cannot open routing socket");
258 		return (EXIT_FAILURE);
259 	}
260 	if (iu_register_event(eh, rtsock_fd, POLLIN, rtsock_event, 0) == -1) {
261 		dhcpmsg(MSG_ERR, "cannot register routing socket for messages");
262 		return (EXIT_FAILURE);
263 	}
264 
265 	/*
266 	 * if the -a (adopt) option was specified, try to adopt the
267 	 * kernel-managed interface before we start.
268 	 */
269 
270 	if (do_adopt && dhcp_adopt() == 0)
271 		return (EXIT_FAILURE);
272 
273 	/*
274 	 * enter the main event loop; this is where all the real work
275 	 * takes place (through registering events and scheduling timers).
276 	 * this function only returns when the agent is shutting down.
277 	 */
278 
279 	switch (iu_handle_events(eh, tq)) {
280 
281 	case -1:
282 		dhcpmsg(MSG_WARNING, "iu_handle_events exited abnormally");
283 		break;
284 
285 	case DHCP_REASON_INACTIVITY:
286 		dhcpmsg(MSG_INFO, "no interfaces to manage, shutting down...");
287 		break;
288 
289 	case DHCP_REASON_TERMINATE:
290 		dhcpmsg(MSG_INFO, "received SIGTERM, shutting down...");
291 		break;
292 
293 	case DHCP_REASON_SIGNAL:
294 		dhcpmsg(MSG_WARNING, "received unexpected signal, shutting "
295 		    "down...");
296 		break;
297 	}
298 
299 	(void) iu_eh_unregister_signal(eh, SIGTHAW, NULL);
300 
301 	iu_eh_destroy(eh);
302 	iu_tq_destroy(tq);
303 
304 	return (EXIT_SUCCESS);
305 }
306 
307 /*
308  * drain_script(): event loop callback during shutdown
309  *
310  *   input: eh_t *: unused
311  *	    void *: unused
312  *  output: boolean_t: B_TRUE if event loop should exit; B_FALSE otherwise
313  */
314 
315 /* ARGSUSED */
316 boolean_t
317 drain_script(iu_eh_t *ehp, void *arg)
318 {
319 	if (shutdown_started == B_FALSE) {
320 		shutdown_started = B_TRUE;
321 		if (do_adopt == B_FALSE)	/* see 4291141 */
322 			nuke_ifslist(B_TRUE);
323 	}
324 	return (script_count == 0);
325 }
326 
327 /*
328  * accept_event(): accepts a new connection on the ipc socket and registers
329  *		   to receive its messages with the event handler
330  *
331  *   input: iu_eh_t *: unused
332  *	    int: the file descriptor in the iu_eh_t * the connection came in on
333  *	    (other arguments unused)
334  *  output: void
335  */
336 
337 /* ARGSUSED */
338 static void
339 accept_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
340 {
341 	int	client_fd;
342 	int	is_priv;
343 
344 	if (dhcp_ipc_accept(fd, &client_fd, &is_priv) != 0) {
345 		dhcpmsg(MSG_ERR, "accept_event: accept on ipc socket");
346 		return;
347 	}
348 
349 	if (iu_register_event(eh, client_fd, POLLIN, ipc_event,
350 	    (void *)is_priv) == -1) {
351 		dhcpmsg(MSG_ERROR, "accept_event: cannot register ipc socket "
352 		    "for callback");
353 	}
354 }
355 
356 /*
357  * ipc_event(): processes incoming ipc requests
358  *
359  *   input: iu_eh_t *: unused
360  *	    int: the file descriptor in the iu_eh_t * the request came in on
361  *	    short: unused
362  *	    iu_event_id_t: unused
363  *	    void *: indicates whether the request is from a privileged client
364  *  output: void
365  */
366 
367 /* ARGSUSED */
368 static void
369 ipc_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
370 {
371 	dhcp_ipc_request_t	*request;
372 	struct ifslist		*ifsp, *primary_ifsp;
373 	int			error, is_priv = (int)arg;
374 	PKT_LIST 		*plp[2];
375 	dhcp_ipc_type_t		cmd;
376 
377 	(void) iu_unregister_event(eh, id, NULL);
378 
379 	if (dhcp_ipc_recv_request(fd, &request, DHCP_IPC_REQUEST_WAIT) != 0) {
380 		dhcpmsg(MSG_ERROR, "ipc_event: dhcp_ipc_recv_request failed");
381 		(void) dhcp_ipc_close(fd);
382 		return;
383 	}
384 
385 	cmd = DHCP_IPC_CMD(request->message_type);
386 	if (cmd >= DHCP_NIPC) {
387 		send_error_reply(request, DHCP_IPC_E_CMD_UNKNOWN, &fd);
388 		return;
389 	}
390 
391 	/* return EPERM for any of the privileged actions */
392 
393 	if (!is_priv) {
394 		switch (cmd) {
395 
396 		case DHCP_STATUS:
397 		case DHCP_PING:
398 		case DHCP_GET_TAG:
399 			break;
400 
401 		default:
402 			dhcpmsg(MSG_WARNING, "ipc_event: privileged ipc "
403 			    "command (%i) attempted on %s", cmd,
404 			    request->ifname);
405 
406 			send_error_reply(request, DHCP_IPC_E_PERM, &fd);
407 			return;
408 		}
409 	}
410 
411 	/*
412 	 * try to locate the ifs associated with this command.  if the
413 	 * command is DHCP_START or DHCP_INFORM, then if there isn't
414 	 * an ifs already, make one (there may already be one from a
415 	 * previous failed attempt to START or INFORM).  otherwise,
416 	 * verify the interface is still valid.
417 	 */
418 
419 	ifsp = lookup_ifs(request->ifname);
420 
421 	switch (cmd) {
422 
423 	case DHCP_START:			/* FALLTHRU */
424 	case DHCP_INFORM:
425 		/*
426 		 * it's possible that the interface already exists, but
427 		 * has been abandoned.  usually in those cases we should
428 		 * return DHCP_IPC_E_UNKIF, but that makes little sense
429 		 * in the case of "start" or "inform", so just ignore
430 		 * the abandoned interface and start over anew.
431 		 */
432 
433 		if (ifsp != NULL && verify_ifs(ifsp) == 0)
434 			ifsp = NULL;
435 
436 		/*
437 		 * as part of initializing the ifs, insert_ifs()
438 		 * creates a DLPI stream at ifsp->if_dlpi_fd.
439 		 */
440 
441 		if (ifsp == NULL) {
442 			ifsp = insert_ifs(request->ifname, B_FALSE, &error);
443 			if (ifsp == NULL) {
444 				send_error_reply(request, error, &fd);
445 				return;
446 			}
447 		}
448 		break;
449 
450 	default:
451 		if (ifsp == NULL) {
452 			if (request->ifname[0] == '\0')
453 				error = DHCP_IPC_E_NOPRIMARY;
454 			else
455 				error = DHCP_IPC_E_UNKIF;
456 
457 			send_error_reply(request, error, &fd);
458 			return;
459 		}
460 		break;
461 	}
462 
463 	if (verify_ifs(ifsp) == 0) {
464 		send_error_reply(request, DHCP_IPC_E_UNKIF, &fd);
465 		return;
466 	}
467 
468 	if (ifsp->if_dflags & DHCP_IF_BOOTP) {
469 		switch (cmd) {
470 
471 		case DHCP_EXTEND:
472 		case DHCP_RELEASE:
473 		case DHCP_INFORM:
474 			send_error_reply(request, DHCP_IPC_E_BOOTP, &fd);
475 			return;
476 
477 		default:
478 			break;
479 		}
480 	}
481 
482 	/*
483 	 * verify that the interface is in a state which will allow the
484 	 * command.  we do this up front so that we can return an error
485 	 * *before* needlessly cancelling an in-progress transaction.
486 	 */
487 
488 	if (!ipc_cmd_allowed[ifsp->if_state][cmd]) {
489 		send_error_reply(request, DHCP_IPC_E_OUTSTATE, &fd);
490 		return;
491 	}
492 
493 	if ((request->message_type & DHCP_PRIMARY) && is_priv) {
494 		if ((primary_ifsp = lookup_ifs("")) != NULL)
495 			primary_ifsp->if_dflags &= ~DHCP_IF_PRIMARY;
496 		ifsp->if_dflags |= DHCP_IF_PRIMARY;
497 	}
498 
499 	/*
500 	 * current design dictates that there can be only one
501 	 * outstanding transaction per interface -- this simplifies
502 	 * the code considerably and also fits well with RFC2131.
503 	 * it is worth classifying the different DHCP commands into
504 	 * synchronous (those which we will handle now and be done
505 	 * with) and asynchronous (those which require transactions
506 	 * and will be completed at an indeterminate time in the
507 	 * future):
508 	 *
509 	 *    DROP: removes the agent's management of an interface.
510 	 *	    asynchronous as the script program may be invoked.
511 	 *
512 	 *    PING: checks to see if the agent controls an interface.
513 	 *	    synchronous, since no packets need to be sent
514 	 *	    to the DHCP server.
515 	 *
516 	 *  STATUS: returns information about the an interface.
517 	 *	    synchronous, since no packets need to be sent
518 	 *	    to the DHCP server.
519 	 *
520 	 * RELEASE: releases the agent's management of an interface
521 	 *	    and brings the interface down.  asynchronous as
522 	 *	    the script program may be invoked.
523 	 *
524 	 *  EXTEND: renews a lease.  asynchronous, since the agent
525 	 *	    needs to wait for an ACK, etc.
526 	 *
527 	 *   START: starts DHCP on an interface.  asynchronous since
528 	 *	    the agent needs to wait for OFFERs, ACKs, etc.
529 	 *
530 	 *  INFORM: obtains configuration parameters for an externally
531 	 *	    configured interface.  asynchronous, since the
532 	 *	    agent needs to wait for an ACK.
533 	 *
534 	 * notice that EXTEND, INFORM, START, DROP and RELEASE are
535 	 * asynchronous. notice also that asynchronous commands may
536 	 * occur from within the agent -- for instance, the agent
537 	 * will need to do implicit EXTENDs to extend the lease. in
538 	 * order to make the code simpler, the following rules apply
539 	 * for asynchronous commands:
540 	 *
541 	 * there can only be one asynchronous command at a time per
542 	 * interface.  the current asynchronous command is managed by
543 	 * the async_* api: async_start(), async_finish(),
544 	 * async_timeout(), async_cancel(), and async_pending().
545 	 * async_start() starts management of a new asynchronous
546 	 * command on an interface, which should only be done after
547 	 * async_pending() is called to check that there are no
548 	 * pending asynchronous commands on that interface.  when the
549 	 * command is completed, async_finish() should be called.  all
550 	 * asynchronous commands have an associated timer, which calls
551 	 * async_timeout() when it times out.  if async_timeout()
552 	 * decides that the asynchronous command should be cancelled
553 	 * (see below), it calls async_cancel() to attempt
554 	 * cancellation.
555 	 *
556 	 * asynchronous commands started by a user command have an
557 	 * associated ipc_action which provides the agent with
558 	 * information for how to get in touch with the user command
559 	 * when the action completes.  these ipc_action records also
560 	 * have an associated timeout which may be infinite.
561 	 * ipc_action_start() should be called when starting an
562 	 * asynchronous command requested by a user, which sets up the
563 	 * timer and keeps track of the ipc information (file
564 	 * descriptor, request type).  when the asynchronous command
565 	 * completes, ipc_action_finish() should be called to return a
566 	 * command status code to the user and close the ipc
567 	 * connection).  if the command does not complete before the
568 	 * timer fires, ipc_action_timeout() is called which closes
569 	 * the ipc connection and returns DHCP_IPC_E_TIMEOUT to the
570 	 * user.  note that independent of ipc_action_timeout(),
571 	 * ipc_action_finish() should be called.
572 	 *
573 	 * on a case-by-case basis, here is what happens (per interface):
574 	 *
575 	 *    o when an asynchronous command is requested, then
576 	 *	async_pending() is called to see if there is already
577 	 *	an asynchronous event.  if so, the command does not
578 	 *	proceed, and if there is an associated ipc_action,
579 	 *	the user command is sent DHCP_IPC_E_PEND.
580 	 *
581 	 *    o otherwise, the the transaction is started with
582 	 *	async_start().  if the transaction is on behalf
583 	 *	of a user, ipc_action_start() is called to keep
584 	 *	track of the ipc information and set up the
585 	 *	ipc_action timer.
586 	 *
587 	 *    o if the command completes normally and before a
588 	 *	timeout fires, then async_finish() is called.
589 	 *	if there was an associated ipc_action,
590 	 *	ipc_action_finish() is called to complete it.
591 	 *
592 	 *    o if the command fails before a timeout fires, then
593 	 *	async_finish() is called, and the interface is
594 	 *	is returned to a known state based on the command.
595 	 *	if there was an associated ipc_action,
596 	 *	ipc_action_finish() is called to complete it.
597 	 *
598 	 *    o if the ipc_action timer fires before command
599 	 *	completion, then DHCP_IPC_E_TIMEOUT is returned to
600 	 *	the user.  however, the transaction continues to
601 	 *	be carried out asynchronously.
602 	 *
603 	 *    o if async_timeout() fires before command completion,
604 	 *	then if the command was internal to the agent, it
605 	 *	is cancelled.  otherwise, if it was a user command,
606 	 *	then if the user is still waiting for the command
607 	 *	to complete, the command continues and async_timeout()
608 	 *	is rescheduled.
609 	 */
610 
611 	switch (cmd) {
612 
613 	case DHCP_DROP:					/* FALLTHRU */
614 	case DHCP_RELEASE:				/* FALLTHRU */
615 	case DHCP_EXTEND:				/* FALLTHRU */
616 	case DHCP_INFORM:				/* FALLTHRU */
617 	case DHCP_START:
618 		/*
619 		 * if shutdown request has been received, send back an error.
620 		 */
621 		if (shutdown_started) {
622 			send_error_reply(request, DHCP_IPC_E_OUTSTATE, &fd);
623 			return;
624 		}
625 
626 		if (async_pending(ifsp)) {
627 			send_error_reply(request, DHCP_IPC_E_PEND, &fd);
628 			return;
629 		}
630 
631 		if (ipc_action_start(ifsp, request, fd) == 0) {
632 			dhcpmsg(MSG_WARNING, "ipc_event: ipc_action_start "
633 			    "failed for %s", ifsp->if_name);
634 			send_error_reply(request, DHCP_IPC_E_MEMORY, &fd);
635 			return;
636 		}
637 
638 		if (async_start(ifsp, cmd, B_TRUE) == 0) {
639 			ipc_action_finish(ifsp, DHCP_IPC_E_MEMORY);
640 			return;
641 		}
642 		break;
643 
644 	default:
645 		break;
646 	}
647 
648 	switch (cmd) {
649 
650 	case DHCP_DROP:
651 		(void) script_start(ifsp, EVENT_DROP, dhcp_drop, NULL, NULL);
652 		return;
653 
654 	case DHCP_EXTEND:
655 		(void) dhcp_extending(ifsp);
656 		break;
657 
658 	case DHCP_GET_TAG: {
659 		dhcp_optnum_t	optnum;
660 		DHCP_OPT	*opt = NULL;
661 		boolean_t	did_alloc = B_FALSE;
662 		PKT_LIST	*ack = ifsp->if_ack;
663 
664 		/*
665 		 * verify the request makes sense.
666 		 */
667 
668 		if (request->data_type   != DHCP_TYPE_OPTNUM ||
669 		    request->data_length != sizeof (dhcp_optnum_t)) {
670 			send_error_reply(request, DHCP_IPC_E_PROTO, &fd);
671 			return;
672 		}
673 
674 		(void) memcpy(&optnum, request->buffer, sizeof (dhcp_optnum_t));
675 load_option:
676 		switch (optnum.category) {
677 
678 		case DSYM_SITE:			/* FALLTHRU */
679 		case DSYM_STANDARD:
680 			if (optnum.code <= DHCP_LAST_OPT)
681 				opt = ack->opts[optnum.code];
682 			break;
683 
684 		case DSYM_VENDOR:
685 			/*
686 			 * the test against VS_OPTION_START is broken up into
687 			 * two tests to avoid compiler warnings under intel.
688 			 */
689 
690 			if ((optnum.code > VS_OPTION_START ||
691 			    optnum.code == VS_OPTION_START) &&
692 			    optnum.code <= VS_OPTION_END)
693 				opt = ack->vs[optnum.code];
694 			break;
695 
696 		case DSYM_FIELD:
697 			if (optnum.code + optnum.size > sizeof (PKT))
698 				break;
699 
700 			/* + 2 to account for option code and length byte */
701 			opt = malloc(optnum.size + 2);
702 			if (opt == NULL) {
703 				send_error_reply(request, DHCP_IPC_E_MEMORY,
704 				    &fd);
705 				return;
706 			}
707 
708 			did_alloc = B_TRUE;
709 			opt->len  = optnum.size;
710 			opt->code = optnum.code;
711 			(void) memcpy(&opt->value, (caddr_t)ack->pkt +
712 			    opt->code, opt->len);
713 
714 			break;
715 
716 		default:
717 			send_error_reply(request, DHCP_IPC_E_PROTO, &fd);
718 			return;
719 		}
720 
721 		/*
722 		 * return the option payload, if there was one.  the "+ 2"
723 		 * accounts for the option code number and length byte.
724 		 */
725 
726 		if (opt != NULL) {
727 			send_data_reply(request, &fd, 0, DHCP_TYPE_OPTION, opt,
728 			    opt->len + 2);
729 
730 			if (did_alloc)
731 				free(opt);
732 			return;
733 		} else if (ack != ifsp->if_orig_ack) {
734 			/*
735 			 * There wasn't any definition for the option in the
736 			 * current ack, so now retry with the original ack if
737 			 * the original ack is not the current ack.
738 			 */
739 			ack = ifsp->if_orig_ack;
740 			goto load_option;
741 		}
742 
743 		/*
744 		 * note that an "okay" response is returned either in
745 		 * the case of an unknown option or a known option
746 		 * with no payload.  this is okay (for now) since
747 		 * dhcpinfo checks whether an option is valid before
748 		 * ever performing ipc with the agent.
749 		 */
750 
751 		send_ok_reply(request, &fd);
752 		return;
753 	}
754 
755 	case DHCP_INFORM:
756 		dhcp_inform(ifsp);
757 		/* next destination: dhcp_acknak() */
758 		return;
759 
760 	case DHCP_PING:
761 		if (ifsp->if_dflags & DHCP_IF_FAILED)
762 			send_error_reply(request, DHCP_IPC_E_FAILEDIF, &fd);
763 		else
764 			send_ok_reply(request, &fd);
765 		return;
766 
767 	case DHCP_RELEASE:
768 		(void) script_start(ifsp, EVENT_RELEASE, dhcp_release,
769 		    "Finished with lease.", NULL);
770 		return;
771 
772 	case DHCP_START:
773 		(void) canonize_ifs(ifsp);
774 
775 		/*
776 		 * if we have a valid hostconf lying around, then jump
777 		 * into INIT_REBOOT.  if it fails, we'll end up going
778 		 * through the whole selecting() procedure again.
779 		 */
780 
781 		error = read_hostconf(ifsp->if_name, plp, 2);
782 		if (error != -1) {
783 			ifsp->if_orig_ack = ifsp->if_ack = plp[0];
784 			if (error > 1) {
785 				/*
786 				 * Return indicated we had more than one packet
787 				 * second one is the original ack.  Older
788 				 * versions of the agent wrote only one ack
789 				 * to the file, we now keep both the first
790 				 * ack as well as the last one.
791 				 */
792 				ifsp->if_orig_ack = plp[1];
793 			}
794 			dhcp_init_reboot(ifsp);
795 			/* next destination: dhcp_acknak() */
796 			return;
797 		}
798 
799 		/*
800 		 * if not debugging, wait for a few seconds before
801 		 * going into SELECTING.
802 		 */
803 
804 		if (debug_level == 0) {
805 			if (iu_schedule_timer_ms(tq,
806 			    lrand48() % DHCP_SELECT_WAIT, dhcp_start, ifsp)
807 			    != -1) {
808 				hold_ifs(ifsp);
809 				/* next destination: dhcp_start() */
810 				return;
811 			}
812 		}
813 
814 		dhcp_selecting(ifsp);
815 		/* next destination: dhcp_requesting() */
816 		return;
817 
818 	case DHCP_STATUS: {
819 		dhcp_status_t	status;
820 
821 		status.if_began = monosec_to_time(ifsp->if_curstart_monosec);
822 
823 		if (ifsp->if_lease == DHCP_PERM) {
824 			status.if_t1	= DHCP_PERM;
825 			status.if_t2	= DHCP_PERM;
826 			status.if_lease	= DHCP_PERM;
827 		} else {
828 			status.if_t1	= status.if_began + ifsp->if_t1;
829 			status.if_t2	= status.if_began + ifsp->if_t2;
830 			status.if_lease	= status.if_began + ifsp->if_lease;
831 		}
832 
833 		status.version		= DHCP_STATUS_VER;
834 		status.if_state		= ifsp->if_state;
835 		status.if_dflags	= ifsp->if_dflags;
836 		status.if_sent		= ifsp->if_sent;
837 		status.if_recv		= ifsp->if_received;
838 		status.if_bad_offers	= ifsp->if_bad_offers;
839 
840 		(void) strlcpy(status.if_name, ifsp->if_name, IFNAMSIZ);
841 
842 		send_data_reply(request, &fd, 0, DHCP_TYPE_STATUS, &status,
843 		    sizeof (dhcp_status_t));
844 		return;
845 	}
846 
847 	default:
848 		return;
849 	}
850 }
851 
852 /*
853  * check_rtm_addr(): determine if routing socket message matches interface
854  *		     address
855  *
856  *   input: struct if_msghdr *: pointer to routing socket message
857  *	    struct in_addr: IP address
858  *  output: boolean_t
859  */
860 static boolean_t
861 check_rtm_addr(struct ifa_msghdr *ifam, int msglen, struct in_addr addr)
862 {
863 	char *cp, *lim;
864 	uint_t flag;
865 	struct sockaddr *sa;
866 	struct sockaddr_in *sinp;
867 
868 	if (!(ifam->ifam_addrs & RTA_IFA))
869 		return (B_FALSE);
870 
871 	cp = (char *)(ifam + 1);
872 	lim = (char *)ifam + msglen;
873 	for (flag = 1; flag < RTA_IFA; flag <<= 1) {
874 		if (ifam->ifam_addrs & flag) {
875 			/* LINTED: alignment */
876 			sa = (struct sockaddr *)cp;
877 			if ((char *)(sa + 1) > lim)
878 				return (B_FALSE);
879 			switch (sa->sa_family) {
880 			case AF_UNIX:
881 				cp += sizeof (struct sockaddr_un);
882 				break;
883 			case AF_INET:
884 				cp += sizeof (struct sockaddr_in);
885 				break;
886 			case AF_LINK:
887 				cp += sizeof (struct sockaddr_dl);
888 				break;
889 			case AF_INET6:
890 				cp += sizeof (struct sockaddr_in6);
891 				break;
892 			default:
893 				cp += sizeof (struct sockaddr);
894 				break;
895 			}
896 		}
897 	}
898 	/* LINTED: alignment */
899 	sinp = (struct sockaddr_in *)cp;
900 	if ((char *)(sinp + 1) > lim)
901 		return (B_FALSE);
902 	return (sinp->sin_addr.s_addr == addr.s_addr);
903 }
904 
905 /*
906  * rtsock_event(): fetches routing socket messages and updates internal
907  *		   interface state based on those messages.
908  *
909  *   input: iu_eh_t *: unused
910  *	    int: the routing socket file descriptor
911  *	    (other arguments unused)
912  *  output: void
913  */
914 
915 /* ARGSUSED */
916 static void
917 rtsock_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
918 {
919 	struct ifslist *ifs;
920 	union {
921 		struct ifa_msghdr ifam;
922 		char buf[1024];
923 	} msg;
924 	uint16_t ifindex;
925 	struct lifreq lifr;
926 	char *fail;
927 	int msglen;
928 	DHCPSTATE oldstate;
929 
930 	if ((msglen = read(fd, &msg, sizeof (msg))) <= 0)
931 		return;
932 
933 	/*
934 	 * These are the messages that can identify a particular logical
935 	 * interface by local IP address.
936 	 */
937 	if (msg.ifam.ifam_type != RTM_DELADDR &&
938 	    msg.ifam.ifam_type != RTM_NEWADDR)
939 		return;
940 
941 	/* Note that ifam_index is just 16 bits */
942 	ifindex = msg.ifam.ifam_index;
943 
944 	for (ifs = lookup_ifs_by_uindex(ifindex, NULL);
945 	    ifs != NULL;
946 	    ifs = lookup_ifs_by_uindex(ifindex, ifs)) {
947 
948 		/*
949 		 * The if_sock_ip_fd is set to a non-negative integer by
950 		 * configure_bound().  If it's negative, then DHCP doesn't
951 		 * think we're bound.
952 		 *
953 		 * For pre-bound interfaces, we want to check to see if the
954 		 * IFF_UP bit has been reported.  This means that DAD is
955 		 * complete.
956 		 */
957 		oldstate = ifs->if_state;
958 		if (ifs->if_sock_ip_fd == -1 &&
959 		    (oldstate != PRE_BOUND && oldstate != ADOPTING))
960 			continue;
961 
962 		/*
963 		 * Since we cannot trust the flags reported by the routing
964 		 * socket (they're just 32 bits -- and thus never include
965 		 * IFF_DUPLICATE), and we can't trust the ifindex (it's only 16
966 		 * bits and also doesn't reflect the alias in use), we get
967 		 * flags on all matching interfaces, and go by that.
968 		 */
969 		(void) strlcpy(lifr.lifr_name, ifs->if_name,
970 		    sizeof (lifr.lifr_name));
971 		if (ioctl(ifs->if_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) {
972 			fail = "unable to retrieve interface flags on %s";
973 			lifr.lifr_flags = 0;
974 		} else if (!check_rtm_addr(&msg.ifam, msglen, ifs->if_addr)) {
975 			/*
976 			 * If the message is not about this logical interface,
977 			 * then just ignore it.
978 			 */
979 			continue;
980 		} else if (lifr.lifr_flags & IFF_DUPLICATE) {
981 			fail = "interface %s has duplicate address";
982 		} else {
983 			/*
984 			 * If we're now up and we were waiting for that, then
985 			 * kick off this interface.  DAD is done.
986 			 */
987 			if (lifr.lifr_flags & IFF_UP) {
988 				if (oldstate == PRE_BOUND ||
989 				    oldstate == ADOPTING)
990 					dhcp_bound_complete(ifs);
991 				if (oldstate == ADOPTING)
992 					dhcp_adopt_complete(ifs);
993 			}
994 			continue;
995 		}
996 
997 		if (ifs->if_sock_ip_fd != -1) {
998 			(void) close(ifs->if_sock_ip_fd);
999 			ifs->if_sock_ip_fd = -1;
1000 		}
1001 		dhcpmsg(MSG_ERROR, fail, ifs->if_name);
1002 
1003 		/*
1004 		 * The binding has evidently failed, so it's as though it never
1005 		 * happened.  We need to do switch back to PRE_BOUND state so
1006 		 * that send_pkt_internal() uses DLPI instead of sockets.  Our
1007 		 * logical interface has already been torn down by the kernel,
1008 		 * and thus we can't send DHCPDECLINE by way of regular IP.
1009 		 * (Unless we're adopting -- allow the grandparent to be
1010 		 * handled as expected.)
1011 		 */
1012 		if (oldstate != ADOPTING)
1013 			ifs->if_state = PRE_BOUND;
1014 
1015 		if (ifs->if_ack->opts[CD_DHCP_TYPE] != NULL &&
1016 		    (lifr.lifr_flags & IFF_DUPLICATE))
1017 			send_decline(ifs, fail, &ifs->if_addr);
1018 
1019 		ifs->if_bad_offers++;
1020 		dhcp_restart(ifs);
1021 	}
1022 }
1023