dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / sbin / dhcpagent / agent.c
blobd223c256b4348670971817c12dec2fb3c7204c10
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <locale.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdio_ext.h>
35 #include <dhcp_hostconf.h>
36 #include <dhcpagent_ipc.h>
37 #include <dhcpagent_util.h>
38 #include <dhcpmsg.h>
39 #include <netinet/dhcp.h>
40 #include <net/route.h>
41 #include <sys/sockio.h>
42 #include <sys/stat.h>
43 #include <stropts.h>
44 #include <fcntl.h>
45 #include <sys/scsi/adapters/iscsi_if.h>
46 #include <poll.h>
48 #include "async.h"
49 #include "agent.h"
50 #include "script_handler.h"
51 #include "util.h"
52 #include "class_id.h"
53 #include "states.h"
54 #include "packet.h"
55 #include "interface.h"
56 #include "defaults.h"
58 #ifndef TEXT_DOMAIN
59 #define TEXT_DOMAIN "SYS_TEST"
60 #endif
62 iu_timer_id_t inactivity_id;
63 int class_id_len = 0;
64 char *class_id;
65 iu_eh_t *eh;
66 iu_tq_t *tq;
67 pid_t grandparent;
68 int rtsock_fd;
70 static boolean_t shutdown_started = B_FALSE;
71 static boolean_t do_adopt = B_FALSE;
72 static unsigned int debug_level = 0;
73 static iu_eh_callback_t accept_event, ipc_event, rtsock_event;
76 * The ipc_cmd_allowed[] table indicates which IPC commands are allowed in
77 * which states; a non-zero value indicates the command is permitted.
79 * START is permitted if the state machine is fresh, or if we are in the
80 * process of trying to obtain a lease (as a convenience to save the
81 * administrator from having to do an explicit DROP). EXTEND, RELEASE, and
82 * GET_TAG require a lease to be obtained in order to make sense. INFORM is
83 * permitted if the interface is fresh or has an INFORM in progress or
84 * previously done on it -- otherwise a DROP or RELEASE is first required.
85 * PING and STATUS always make sense and thus are always permitted, as is DROP
86 * in order to permit the administrator to always bail out.
88 static int ipc_cmd_allowed[DHCP_NSTATES][DHCP_NIPC] = {
89 /* D E P R S S I G */
90 /* R X I E T T N E */
91 /* O T N L A A F T */
92 /* P E G E R T O _ */
93 /* . N . A T U R T */
94 /* . D . S . S M A */
95 /* . . . E . . . G */
96 /* INIT */ { 1, 0, 1, 0, 1, 1, 1, 0 },
97 /* SELECTING */ { 1, 0, 1, 0, 1, 1, 0, 0 },
98 /* REQUESTING */ { 1, 0, 1, 0, 1, 1, 0, 0 },
99 /* PRE_BOUND */ { 1, 1, 1, 1, 0, 1, 0, 1 },
100 /* BOUND */ { 1, 1, 1, 1, 0, 1, 0, 1 },
101 /* RENEWING */ { 1, 1, 1, 1, 0, 1, 0, 1 },
102 /* REBINDING */ { 1, 1, 1, 1, 0, 1, 0, 1 },
103 /* INFORMATION */ { 1, 0, 1, 0, 1, 1, 1, 1 },
104 /* INIT_REBOOT */ { 1, 0, 1, 1, 1, 1, 0, 0 },
105 /* ADOPTING */ { 1, 0, 1, 1, 0, 1, 0, 0 },
106 /* INFORM_SENT */ { 1, 0, 1, 0, 1, 1, 1, 0 },
107 /* DECLINING */ { 1, 1, 1, 1, 0, 1, 0, 1 },
108 /* RELEASING */ { 1, 0, 1, 0, 0, 1, 0, 1 },
111 #define CMD_ISPRIV 0x1 /* Command requires privileges */
112 #define CMD_CREATE 0x2 /* Command creates an interface */
113 #define CMD_BOOTP 0x4 /* Command is valid with BOOTP */
114 #define CMD_IMMED 0x8 /* Reply is immediate (no BUSY state) */
116 static uint_t ipc_cmd_flags[DHCP_NIPC] = {
117 /* DHCP_DROP */ CMD_ISPRIV|CMD_BOOTP,
118 /* DHCP_EXTEND */ CMD_ISPRIV,
119 /* DHCP_PING */ CMD_BOOTP|CMD_IMMED,
120 /* DHCP_RELEASE */ CMD_ISPRIV,
121 /* DHCP_START */ CMD_CREATE|CMD_ISPRIV|CMD_BOOTP,
122 /* DHCP_STATUS */ CMD_BOOTP|CMD_IMMED,
123 /* DHCP_INFORM */ CMD_CREATE|CMD_ISPRIV,
124 /* DHCP_GET_TAG */ CMD_BOOTP|CMD_IMMED
127 static boolean_t is_iscsi_active(void);
130 main(int argc, char **argv)
132 boolean_t is_daemon = B_TRUE;
133 boolean_t is_verbose;
134 int ipc_fd;
135 int c;
136 int aware = RTAW_UNDER_IPMP;
137 struct rlimit rl;
139 debug_level = df_get_int("", B_FALSE, DF_DEBUG_LEVEL);
140 is_verbose = df_get_bool("", B_FALSE, DF_VERBOSE);
143 * -l is ignored for compatibility with old agent.
146 while ((c = getopt(argc, argv, "vd:l:fa")) != EOF) {
148 switch (c) {
150 case 'a':
151 do_adopt = B_TRUE;
152 grandparent = getpid();
153 break;
155 case 'd':
156 debug_level = strtoul(optarg, NULL, 0);
157 break;
159 case 'f':
160 is_daemon = B_FALSE;
161 break;
163 case 'v':
164 is_verbose = B_TRUE;
165 break;
167 case '?':
168 (void) fprintf(stderr, "usage: %s [-a] [-d n] [-f] [-v]"
169 "\n", argv[0]);
170 return (EXIT_FAILURE);
172 default:
173 break;
177 (void) setlocale(LC_ALL, "");
178 (void) textdomain(TEXT_DOMAIN);
180 if (geteuid() != 0) {
181 dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level);
182 dhcpmsg(MSG_ERROR, "must be super-user");
183 dhcpmsg_fini();
184 return (EXIT_FAILURE);
187 if (is_daemon && daemonize() == 0) {
188 dhcpmsg_init(argv[0], B_FALSE, is_verbose, debug_level);
189 dhcpmsg(MSG_ERR, "cannot become daemon, exiting");
190 dhcpmsg_fini();
191 return (EXIT_FAILURE);
195 * Seed the random number generator, since we're going to need it
196 * to set transaction id's and for exponential backoff.
198 srand48(gethrtime() ^ gethostid() ^ getpid());
200 dhcpmsg_init(argv[0], is_daemon, is_verbose, debug_level);
201 (void) atexit(dhcpmsg_fini);
203 tq = iu_tq_create();
204 eh = iu_eh_create();
206 if (eh == NULL || tq == NULL) {
207 errno = ENOMEM;
208 dhcpmsg(MSG_ERR, "cannot create timer queue or event handler");
209 return (EXIT_FAILURE);
213 * ignore most signals that could be reasonably generated.
216 (void) signal(SIGTERM, graceful_shutdown);
217 (void) signal(SIGQUIT, graceful_shutdown);
218 (void) signal(SIGPIPE, SIG_IGN);
219 (void) signal(SIGUSR1, SIG_IGN);
220 (void) signal(SIGUSR2, SIG_IGN);
221 (void) signal(SIGINT, SIG_IGN);
222 (void) signal(SIGHUP, SIG_IGN);
223 (void) signal(SIGCHLD, SIG_IGN);
226 * upon SIGTHAW we need to refresh any non-infinite leases.
229 (void) iu_eh_register_signal(eh, SIGTHAW, refresh_smachs, NULL);
231 class_id = get_class_id();
232 if (class_id != NULL)
233 class_id_len = strlen(class_id);
234 else
235 dhcpmsg(MSG_WARNING, "get_class_id failed, continuing "
236 "with no vendor class id");
239 * the inactivity timer is enabled any time there are no
240 * interfaces under DHCP control. if DHCP_INACTIVITY_WAIT
241 * seconds transpire without an interface under DHCP control,
242 * the agent shuts down.
245 inactivity_id = iu_schedule_timer(tq, DHCP_INACTIVITY_WAIT,
246 inactivity_shutdown, NULL);
249 * max out the number available descriptors, just in case..
252 rl.rlim_cur = RLIM_INFINITY;
253 rl.rlim_max = RLIM_INFINITY;
254 if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
255 dhcpmsg(MSG_ERR, "setrlimit failed");
257 (void) enable_extended_FILE_stdio(-1, -1);
260 * Create and bind default IP sockets used to control interfaces and to
261 * catch stray packets.
264 if (!dhcp_ip_default())
265 return (EXIT_FAILURE);
268 * create the ipc channel that the agent will listen for
269 * requests on, and register it with the event handler so that
270 * `accept_event' will be called back.
273 switch (dhcp_ipc_init(&ipc_fd)) {
275 case 0:
276 break;
278 case DHCP_IPC_E_BIND:
279 dhcpmsg(MSG_ERROR, "dhcp_ipc_init: cannot bind to port "
280 "%i (agent already running?)", IPPORT_DHCPAGENT);
281 return (EXIT_FAILURE);
283 default:
284 dhcpmsg(MSG_ERROR, "dhcp_ipc_init failed");
285 return (EXIT_FAILURE);
288 if (iu_register_event(eh, ipc_fd, POLLIN, accept_event, 0) == -1) {
289 dhcpmsg(MSG_ERR, "cannot register ipc fd for messages");
290 return (EXIT_FAILURE);
294 * Create the global routing socket. This is used for monitoring
295 * interface transitions, so that we learn about the kernel's Duplicate
296 * Address Detection status, and for inserting and removing default
297 * routes as learned from DHCP servers. Both v4 and v6 are handed
298 * with this one socket.
300 rtsock_fd = socket(PF_ROUTE, SOCK_RAW, 0);
301 if (rtsock_fd == -1) {
302 dhcpmsg(MSG_ERR, "cannot open routing socket");
303 return (EXIT_FAILURE);
307 * We're IPMP-aware and can manage IPMP test addresses, so issue
308 * RT_AWARE to get routing socket messages for interfaces under IPMP.
310 if (setsockopt(rtsock_fd, SOL_ROUTE, RT_AWARE, &aware,
311 sizeof (aware)) == -1) {
312 dhcpmsg(MSG_ERR, "cannot set RT_AWARE on routing socket");
313 return (EXIT_FAILURE);
316 if (iu_register_event(eh, rtsock_fd, POLLIN, rtsock_event, 0) == -1) {
317 dhcpmsg(MSG_ERR, "cannot register routing socket for messages");
318 return (EXIT_FAILURE);
322 * if the -a (adopt) option was specified, try to adopt the
323 * kernel-managed interface before we start.
326 if (do_adopt && !dhcp_adopt())
327 return (EXIT_FAILURE);
330 * For DHCPv6, we own all of the interfaces marked DHCPRUNNING. As
331 * we're starting operation here, if there are any of those interfaces
332 * lingering around, they're strays, and need to be removed.
334 * It might be nice to save these addresses off somewhere -- for both
335 * v4 and v6 -- and use them as hints for later negotiation.
337 remove_v6_strays();
340 * enter the main event loop; this is where all the real work
341 * takes place (through registering events and scheduling timers).
342 * this function only returns when the agent is shutting down.
345 switch (iu_handle_events(eh, tq)) {
347 case -1:
348 dhcpmsg(MSG_WARNING, "iu_handle_events exited abnormally");
349 break;
351 case DHCP_REASON_INACTIVITY:
352 dhcpmsg(MSG_INFO, "no interfaces to manage, shutting down...");
353 break;
355 case DHCP_REASON_TERMINATE:
356 dhcpmsg(MSG_INFO, "received SIGTERM, shutting down...");
357 break;
359 case DHCP_REASON_SIGNAL:
360 dhcpmsg(MSG_WARNING, "received unexpected signal, shutting "
361 "down...");
362 break;
365 (void) iu_eh_unregister_signal(eh, SIGTHAW, NULL);
367 iu_eh_destroy(eh);
368 iu_tq_destroy(tq);
370 return (EXIT_SUCCESS);
374 * drain_script(): event loop callback during shutdown
376 * input: eh_t *: unused
377 * void *: unused
378 * output: boolean_t: B_TRUE if event loop should exit; B_FALSE otherwise
381 /* ARGSUSED */
382 boolean_t
383 drain_script(iu_eh_t *ehp, void *arg)
385 if (shutdown_started == B_FALSE) {
386 shutdown_started = B_TRUE;
388 * Check if the system is diskless client and/or
389 * there are active iSCSI sessions
391 * Do not drop the lease, or the system will be
392 * unable to sync(dump) through nfs/iSCSI driver
394 if (!do_adopt && !is_iscsi_active()) {
395 nuke_smach_list();
398 return (script_count == 0);
402 * accept_event(): accepts a new connection on the ipc socket and registers
403 * to receive its messages with the event handler
405 * input: iu_eh_t *: unused
406 * int: the file descriptor in the iu_eh_t * the connection came in on
407 * (other arguments unused)
408 * output: void
411 /* ARGSUSED */
412 static void
413 accept_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
415 int client_fd;
416 int is_priv;
418 if (dhcp_ipc_accept(fd, &client_fd, &is_priv) != 0) {
419 dhcpmsg(MSG_ERR, "accept_event: accept on ipc socket");
420 return;
423 if (iu_register_event(eh, client_fd, POLLIN, ipc_event,
424 (void *)is_priv) == -1) {
425 dhcpmsg(MSG_ERROR, "accept_event: cannot register ipc socket "
426 "for callback");
431 * ipc_event(): processes incoming ipc requests
433 * input: iu_eh_t *: unused
434 * int: the file descriptor in the iu_eh_t * the request came in on
435 * short: unused
436 * iu_event_id_t: event ID
437 * void *: indicates whether the request is from a privileged client
438 * output: void
441 /* ARGSUSED */
442 static void
443 ipc_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
445 ipc_action_t ia, *iap;
446 dhcp_smach_t *dsmp;
447 int error, is_priv = (int)arg;
448 const char *ifname;
449 boolean_t isv6;
450 boolean_t dsm_created = B_FALSE;
452 ipc_action_init(&ia);
453 error = dhcp_ipc_recv_request(fd, &ia.ia_request,
454 DHCP_IPC_REQUEST_WAIT);
455 if (error != DHCP_IPC_SUCCESS) {
456 if (error != DHCP_IPC_E_EOF) {
457 dhcpmsg(MSG_ERROR,
458 "ipc_event: dhcp_ipc_recv_request failed: %s",
459 dhcp_ipc_strerror(error));
460 } else {
461 dhcpmsg(MSG_DEBUG, "ipc_event: connection closed");
463 if ((dsmp = lookup_smach_by_event(id)) != NULL) {
464 ipc_action_finish(dsmp, error);
465 } else {
466 (void) iu_unregister_event(eh, id, NULL);
467 (void) dhcp_ipc_close(fd);
469 return;
472 /* Fill in temporary ipc_action structure for utility functions */
473 ia.ia_cmd = DHCP_IPC_CMD(ia.ia_request->message_type);
474 ia.ia_fd = fd;
475 ia.ia_eid = id;
477 if (ia.ia_cmd >= DHCP_NIPC) {
478 dhcpmsg(MSG_ERROR,
479 "ipc_event: invalid command (%s) attempted on %s",
480 dhcp_ipc_type_to_string(ia.ia_cmd), ia.ia_request->ifname);
481 send_error_reply(&ia, DHCP_IPC_E_CMD_UNKNOWN);
482 return;
485 /* return EPERM for any of the privileged actions */
487 if (!is_priv && (ipc_cmd_flags[ia.ia_cmd] & CMD_ISPRIV)) {
488 dhcpmsg(MSG_WARNING,
489 "ipc_event: privileged ipc command (%s) attempted on %s",
490 dhcp_ipc_type_to_string(ia.ia_cmd), ia.ia_request->ifname);
491 send_error_reply(&ia, DHCP_IPC_E_PERM);
492 return;
496 * Try to locate the state machine associated with this command. If
497 * the command is DHCP_START or DHCP_INFORM and there isn't a state
498 * machine already, make one (there may already be one from a previous
499 * failed attempt to START or INFORM). Otherwise, verify the reference
500 * is still valid.
502 * The interface name may be blank. In that case, we look up the
503 * primary interface, and the requested type (v4 or v6) doesn't matter.
506 isv6 = (ia.ia_request->message_type & DHCP_V6) != 0;
507 ifname = ia.ia_request->ifname;
508 if (*ifname == '\0')
509 dsmp = primary_smach(isv6);
510 else
511 dsmp = lookup_smach(ifname, isv6);
513 if (dsmp != NULL) {
514 /* Note that verify_smach drops a reference */
515 hold_smach(dsmp);
516 if (!verify_smach(dsmp))
517 dsmp = NULL;
520 if (dsmp == NULL) {
522 * If the user asked for the primary DHCP interface by giving
523 * an empty string and there is no primary, then check if we're
524 * handling dhcpinfo. If so, then simulate primary selection.
525 * Otherwise, report failure.
527 if (ifname[0] == '\0') {
528 if (ia.ia_cmd == DHCP_GET_TAG)
529 dsmp = info_primary_smach(isv6);
530 if (dsmp == NULL)
531 error = DHCP_IPC_E_NOPRIMARY;
534 * If there's no interface, and we're starting up, then create
535 * it now, along with a state machine for it. Note that if
536 * insert_smach fails, it discards the LIF reference.
538 } else if (ipc_cmd_flags[ia.ia_cmd] & CMD_CREATE) {
539 dhcp_lif_t *lif;
541 lif = attach_lif(ifname, isv6, &error);
542 if (lif != NULL &&
543 (dsmp = insert_smach(lif, &error)) != NULL) {
545 * Get client ID for logical interface. (V4
546 * only, because V6 plumbs its own interfaces.)
548 error = get_smach_cid(dsmp);
549 if (error != DHCP_IPC_SUCCESS) {
550 remove_smach(dsmp);
551 dsmp = NULL;
553 dsm_created = (dsmp != NULL);
557 * Otherwise, this is an operation on an unknown interface.
559 } else {
560 error = DHCP_IPC_E_UNKIF;
562 if (dsmp == NULL) {
563 send_error_reply(&ia, error);
564 return;
569 * If this is a request for DHCP to manage a lease on an address,
570 * ensure that IFF_DHCPRUNNING is set (we don't set this when the lif
571 * is created because the lif may have been created for INFORM).
573 if (ia.ia_cmd == DHCP_START &&
574 (error = set_lif_dhcp(dsmp->dsm_lif)) != DHCP_IPC_SUCCESS) {
575 if (dsm_created)
576 remove_smach(dsmp);
577 send_error_reply(&ia, error);
578 return;
581 if ((dsmp->dsm_dflags & DHCP_IF_BOOTP) &&
582 !(ipc_cmd_flags[ia.ia_cmd] & CMD_BOOTP)) {
583 dhcpmsg(MSG_ERROR, "command %s not valid for BOOTP on %s",
584 dhcp_ipc_type_to_string(ia.ia_cmd), dsmp->dsm_name);
585 send_error_reply(&ia, DHCP_IPC_E_BOOTP);
586 return;
590 * verify that the state machine is in a state which will allow the
591 * command. we do this up front so that we can return an error
592 * *before* needlessly cancelling an in-progress transaction.
595 if (!check_cmd_allowed(dsmp->dsm_state, ia.ia_cmd)) {
596 dhcpmsg(MSG_DEBUG,
597 "in state %s; not allowing %s command on %s",
598 dhcp_state_to_string(dsmp->dsm_state),
599 dhcp_ipc_type_to_string(ia.ia_cmd), dsmp->dsm_name);
600 send_error_reply(&ia,
601 ia.ia_cmd == DHCP_START && dsmp->dsm_state != INIT ?
602 DHCP_IPC_E_RUNNING : DHCP_IPC_E_OUTSTATE);
603 return;
606 dhcpmsg(MSG_DEBUG, "in state %s; allowing %s command on %s",
607 dhcp_state_to_string(dsmp->dsm_state),
608 dhcp_ipc_type_to_string(ia.ia_cmd), dsmp->dsm_name);
610 if ((ia.ia_request->message_type & DHCP_PRIMARY) && is_priv)
611 make_primary(dsmp);
614 * The current design dictates that there can be only one outstanding
615 * transaction per state machine -- this simplifies the code
616 * considerably and also fits well with RFCs 2131 and 3315. It is
617 * worth classifying the different DHCP commands into synchronous
618 * (those which we will handle now and reply to immediately) and
619 * asynchronous (those which require transactions and will be completed
620 * at an indeterminate time in the future):
622 * DROP: removes the agent's management of a state machine.
623 * asynchronous as the script program may be invoked.
625 * PING: checks to see if the agent has a named state machine.
626 * synchronous, since no packets need to be sent
627 * to the DHCP server.
629 * STATUS: returns information about a state machine.
630 * synchronous, since no packets need to be sent
631 * to the DHCP server.
633 * RELEASE: releases the agent's management of a state machine
634 * and brings the associated interfaces down. asynchronous
635 * as the script program may be invoked.
637 * EXTEND: renews a lease. asynchronous, since the agent
638 * needs to wait for an ACK, etc.
640 * START: starts DHCP on a named state machine. asynchronous since
641 * the agent needs to wait for OFFERs, ACKs, etc.
643 * INFORM: obtains configuration parameters for the system using
644 * externally configured interface. asynchronous, since the
645 * agent needs to wait for an ACK.
647 * Notice that EXTEND, INFORM, START, DROP and RELEASE are
648 * asynchronous. Notice also that asynchronous commands may occur from
649 * within the agent -- for instance, the agent will need to do implicit
650 * EXTENDs to extend the lease. In order to make the code simpler, the
651 * following rules apply for asynchronous commands:
653 * There can only be one asynchronous command at a time per state
654 * machine. The current asynchronous command is managed by the async_*
655 * api: async_start(), async_finish(), and async_cancel().
656 * async_start() starts management of a new asynchronous command on an
657 * state machine, which should only be done after async_cancel() to
658 * terminate a previous command. When the command is completed,
659 * async_finish() should be called.
661 * Asynchronous commands started by a user command have an associated
662 * ipc_action which provides the agent with information for how to get
663 * in touch with the user command when the action completes. These
664 * ipc_action records also have an associated timeout which may be
665 * infinite. ipc_action_start() should be called when starting an
666 * asynchronous command requested by a user, which sets up the timer
667 * and keeps track of the ipc information (file descriptor, request
668 * type). When the asynchronous command completes, ipc_action_finish()
669 * should be called to return a command status code to the user and
670 * close the ipc connection). If the command does not complete before
671 * the timer fires, ipc_action_timeout() is called which closes the ipc
672 * connection and returns DHCP_IPC_E_TIMEOUT to the user. Note that
673 * independent of ipc_action_timeout(), ipc_action_finish() should be
674 * called.
676 * on a case-by-case basis, here is what happens (per state machine):
678 * o When an asynchronous command is requested, then
679 * async_cancel() is called to terminate any non-user
680 * action in progress. If there's a user action running,
681 * the user command is sent DHCP_IPC_E_PEND.
683 * o otherwise, the the transaction is started with
684 * async_start(). if the transaction is on behalf
685 * of a user, ipc_action_start() is called to keep
686 * track of the ipc information and set up the
687 * ipc_action timer.
689 * o if the command completes normally and before a
690 * timeout fires, then async_finish() is called.
691 * if there was an associated ipc_action,
692 * ipc_action_finish() is called to complete it.
694 * o if the command fails before a timeout fires, then
695 * async_finish() is called, and the state machine is
696 * is returned to a known state based on the command.
697 * if there was an associated ipc_action,
698 * ipc_action_finish() is called to complete it.
700 * o if the ipc_action timer fires before command
701 * completion, then DHCP_IPC_E_TIMEOUT is returned to
702 * the user. however, the transaction continues to
703 * be carried out asynchronously.
706 if (ipc_cmd_flags[ia.ia_cmd] & CMD_IMMED) {
708 * Only immediate commands (ping, status, get_tag) need to
709 * worry about freeing ia through one of the reply functions
710 * before returning.
712 iap = &ia;
713 } else {
715 * if shutdown request has been received, send back an error.
717 if (shutdown_started) {
718 send_error_reply(&ia, DHCP_IPC_E_OUTSTATE);
719 return;
722 if (dsmp->dsm_dflags & DHCP_IF_BUSY) {
723 send_error_reply(&ia, DHCP_IPC_E_PEND);
724 return;
727 if (!ipc_action_start(dsmp, &ia)) {
728 dhcpmsg(MSG_WARNING, "ipc_event: ipc_action_start "
729 "failed for %s", dsmp->dsm_name);
730 send_error_reply(&ia, DHCP_IPC_E_MEMORY);
731 return;
734 /* Action structure consumed by above function */
735 iap = &dsmp->dsm_ia;
738 switch (iap->ia_cmd) {
740 case DHCP_DROP:
741 if (dsmp->dsm_droprelease)
742 break;
743 dsmp->dsm_droprelease = B_TRUE;
746 * Ensure that a timer associated with the existing state
747 * doesn't pop while we're waiting for the script to complete.
748 * (If so, chaos can result -- e.g., a timer causes us to end
749 * up in dhcp_selecting() would start acquiring a new lease on
750 * dsmp while our DHCP_DROP dismantling is ongoing.)
752 cancel_smach_timers(dsmp);
753 (void) script_start(dsmp, isv6 ? EVENT_DROP6 : EVENT_DROP,
754 dhcp_drop, NULL, NULL);
755 break; /* not an immediate function */
757 case DHCP_EXTEND:
758 (void) dhcp_extending(dsmp);
759 break;
761 case DHCP_GET_TAG: {
762 dhcp_optnum_t optnum;
763 void *opt = NULL;
764 uint_t optlen;
765 boolean_t did_alloc = B_FALSE;
766 PKT_LIST *ack = dsmp->dsm_ack;
767 int i;
770 * verify the request makes sense.
773 if (iap->ia_request->data_type != DHCP_TYPE_OPTNUM ||
774 iap->ia_request->data_length != sizeof (dhcp_optnum_t)) {
775 send_error_reply(iap, DHCP_IPC_E_PROTO);
776 break;
779 (void) memcpy(&optnum, iap->ia_request->buffer,
780 sizeof (dhcp_optnum_t));
782 load_option:
783 switch (optnum.category) {
785 case DSYM_SITE: /* FALLTHRU */
786 case DSYM_STANDARD:
787 for (i = 0; i < dsmp->dsm_pillen; i++) {
788 if (dsmp->dsm_pil[i] == optnum.code)
789 break;
791 if (i < dsmp->dsm_pillen)
792 break;
793 if (isv6) {
794 opt = dhcpv6_pkt_option(ack, NULL, optnum.code,
795 NULL);
796 } else {
797 if (optnum.code <= DHCP_LAST_OPT)
798 opt = ack->opts[optnum.code];
800 break;
802 case DSYM_VENDOR:
803 if (isv6) {
804 dhcpv6_option_t *d6o;
805 uint32_t ent;
808 * Look through vendor options to find our
809 * enterprise number.
811 d6o = NULL;
812 for (;;) {
813 d6o = dhcpv6_pkt_option(ack, d6o,
814 DHCPV6_OPT_VENDOR_OPT, &optlen);
815 if (d6o == NULL)
816 break;
817 optlen -= sizeof (*d6o);
818 if (optlen < sizeof (ent))
819 continue;
820 (void) memcpy(&ent, d6o + 1,
821 sizeof (ent));
822 if (ntohl(ent) != DHCPV6_SUN_ENT)
823 continue;
824 break;
826 if (d6o != NULL) {
828 * Now find the requested vendor option
829 * within the vendor options block.
831 opt = dhcpv6_find_option(
832 (char *)(d6o + 1) + sizeof (ent),
833 optlen - sizeof (ent), NULL,
834 optnum.code, NULL);
836 } else {
838 * the test against VS_OPTION_START is broken
839 * up into two tests to avoid compiler warnings
840 * under intel.
842 if ((optnum.code > VS_OPTION_START ||
843 optnum.code == VS_OPTION_START) &&
844 optnum.code <= VS_OPTION_END)
845 opt = ack->vs[optnum.code];
847 break;
849 case DSYM_FIELD:
850 if (isv6) {
851 dhcpv6_message_t *d6m =
852 (dhcpv6_message_t *)ack->pkt;
853 dhcpv6_option_t *d6o;
855 /* Validate the packet field the user wants */
856 optlen = optnum.code + optnum.size;
857 if (d6m->d6m_msg_type ==
858 DHCPV6_MSG_RELAY_FORW ||
859 d6m->d6m_msg_type ==
860 DHCPV6_MSG_RELAY_REPL) {
861 if (optlen > sizeof (dhcpv6_relay_t))
862 break;
863 } else {
864 if (optlen > sizeof (*d6m))
865 break;
868 opt = malloc(sizeof (*d6o) + optnum.size);
869 if (opt != NULL) {
870 d6o = opt;
871 d6o->d6o_code = htons(optnum.code);
872 d6o->d6o_len = htons(optnum.size);
873 (void) memcpy(d6o + 1, (caddr_t)d6m +
874 optnum.code, optnum.size);
876 } else {
877 if (optnum.code + optnum.size > sizeof (PKT))
878 break;
881 * + 2 to account for option code and length
882 * byte
884 opt = malloc(optnum.size + 2);
885 if (opt != NULL) {
886 DHCP_OPT *v4opt = opt;
888 v4opt->len = optnum.size;
889 v4opt->code = optnum.code;
890 (void) memcpy(v4opt->value,
891 (caddr_t)ack->pkt + optnum.code,
892 optnum.size);
896 if (opt == NULL) {
897 send_error_reply(iap, DHCP_IPC_E_MEMORY);
898 return;
900 did_alloc = B_TRUE;
901 break;
903 default:
904 send_error_reply(iap, DHCP_IPC_E_PROTO);
905 return;
909 * return the option payload, if there was one. the "+ 2"
910 * accounts for the option code number and length byte.
913 if (opt != NULL) {
914 if (isv6) {
915 dhcpv6_option_t d6ov;
917 (void) memcpy(&d6ov, opt, sizeof (d6ov));
918 optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov);
919 } else {
920 optlen = ((DHCP_OPT *)opt)->len + 2;
922 send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen);
924 if (did_alloc)
925 free(opt);
926 break;
927 } else if (ack != dsmp->dsm_orig_ack) {
929 * There wasn't any definition for the option in the
930 * current ack, so now retry with the original ack if
931 * the original ack is not the current ack.
933 ack = dsmp->dsm_orig_ack;
934 goto load_option;
938 * note that an "okay" response is returned either in
939 * the case of an unknown option or a known option
940 * with no payload. this is okay (for now) since
941 * dhcpinfo checks whether an option is valid before
942 * ever performing ipc with the agent.
945 send_ok_reply(iap);
946 break;
949 case DHCP_INFORM:
950 dhcp_inform(dsmp);
951 /* next destination: dhcp_acknak() */
952 break; /* not an immediate function */
954 case DHCP_PING:
955 if (dsmp->dsm_dflags & DHCP_IF_FAILED)
956 send_error_reply(iap, DHCP_IPC_E_FAILEDIF);
957 else
958 send_ok_reply(iap);
959 break;
961 case DHCP_RELEASE:
962 if (dsmp->dsm_droprelease)
963 break;
964 dsmp->dsm_droprelease = B_TRUE;
965 cancel_smach_timers(dsmp); /* see comment in DHCP_DROP above */
966 (void) script_start(dsmp, isv6 ? EVENT_RELEASE6 :
967 EVENT_RELEASE, dhcp_release, "Finished with lease.", NULL);
968 break; /* not an immediate function */
970 case DHCP_START: {
971 PKT_LIST *ack, *oack;
972 PKT_LIST *plp[2];
974 deprecate_leases(dsmp);
977 * if we have a valid hostconf lying around, then jump
978 * into INIT_REBOOT. if it fails, we'll end up going
979 * through the whole selecting() procedure again.
982 error = read_hostconf(dsmp->dsm_name, plp, 2, dsmp->dsm_isv6);
983 ack = error > 0 ? plp[0] : NULL;
984 oack = error > 1 ? plp[1] : NULL;
987 * If the allocation of the old ack fails, that's fine;
988 * continue without it.
990 if (oack == NULL)
991 oack = ack;
994 * As long as we've allocated something, start using it.
996 if (ack != NULL) {
997 dsmp->dsm_orig_ack = oack;
998 dsmp->dsm_ack = ack;
999 dhcp_init_reboot(dsmp);
1000 /* next destination: dhcp_acknak() */
1001 break;
1005 * if not debugging, wait for a few seconds before
1006 * going into SELECTING.
1009 if (debug_level == 0 && set_start_timer(dsmp)) {
1010 /* next destination: dhcp_start() */
1011 break;
1012 } else {
1013 dhcp_selecting(dsmp);
1014 /* next destination: dhcp_requesting() */
1015 break;
1019 case DHCP_STATUS: {
1020 dhcp_status_t status;
1021 dhcp_lease_t *dlp;
1023 status.if_began = monosec_to_time(dsmp->dsm_curstart_monosec);
1026 * We return information on just the first lease as being
1027 * representative of the lot. A better status mechanism is
1028 * needed.
1030 dlp = dsmp->dsm_leases;
1032 if (dlp == NULL ||
1033 dlp->dl_lifs->lif_expire.dt_start == DHCP_PERM) {
1034 status.if_t1 = DHCP_PERM;
1035 status.if_t2 = DHCP_PERM;
1036 status.if_lease = DHCP_PERM;
1037 } else {
1038 status.if_t1 = status.if_began +
1039 dlp->dl_t1.dt_start;
1040 status.if_t2 = status.if_began +
1041 dlp->dl_t2.dt_start;
1042 status.if_lease = status.if_began +
1043 dlp->dl_lifs->lif_expire.dt_start;
1046 status.version = DHCP_STATUS_VER;
1047 status.if_state = dsmp->dsm_state;
1048 status.if_dflags = dsmp->dsm_dflags;
1049 status.if_sent = dsmp->dsm_sent;
1050 status.if_recv = dsmp->dsm_received;
1051 status.if_bad_offers = dsmp->dsm_bad_offers;
1053 (void) strlcpy(status.if_name, dsmp->dsm_name, LIFNAMSIZ);
1055 send_data_reply(iap, 0, DHCP_TYPE_STATUS, &status,
1056 sizeof (dhcp_status_t));
1057 break;
1063 * check_rtm_addr(): determine if routing socket message matches interface
1064 * address
1066 * input: const struct if_msghdr *: pointer to routing socket message
1067 * int: routing socket message length
1068 * boolean_t: set to B_TRUE if IPv6
1069 * const in6_addr_t *: pointer to IP address
1070 * output: boolean_t: B_TRUE if address is a match
1073 static boolean_t
1074 check_rtm_addr(const struct ifa_msghdr *ifam, int msglen, boolean_t isv6,
1075 const in6_addr_t *addr)
1077 const char *cp, *lim;
1078 uint_t flag;
1079 const struct sockaddr *sa;
1081 if (!(ifam->ifam_addrs & RTA_IFA))
1082 return (B_FALSE);
1084 cp = (const char *)(ifam + 1);
1085 lim = (const char *)ifam + msglen;
1086 for (flag = 1; flag < RTA_IFA; flag <<= 1) {
1087 if (ifam->ifam_addrs & flag) {
1088 /* LINTED: alignment */
1089 sa = (const struct sockaddr *)cp;
1090 if ((const char *)(sa + 1) > lim)
1091 return (B_FALSE);
1092 switch (sa->sa_family) {
1093 case AF_INET:
1094 cp += sizeof (struct sockaddr_in);
1095 break;
1096 case AF_LINK:
1097 cp += sizeof (struct sockaddr_dl);
1098 break;
1099 case AF_INET6:
1100 cp += sizeof (struct sockaddr_in6);
1101 break;
1102 default:
1103 cp += sizeof (struct sockaddr);
1104 break;
1108 if (isv6) {
1109 const struct sockaddr_in6 *sin6;
1111 /* LINTED: alignment */
1112 sin6 = (const struct sockaddr_in6 *)cp;
1113 if ((const char *)(sin6 + 1) > lim)
1114 return (B_FALSE);
1115 if (sin6->sin6_family != AF_INET6)
1116 return (B_FALSE);
1117 return (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, addr));
1118 } else {
1119 const struct sockaddr_in *sinp;
1120 ipaddr_t v4addr;
1122 /* LINTED: alignment */
1123 sinp = (const struct sockaddr_in *)cp;
1124 if ((const char *)(sinp + 1) > lim)
1125 return (B_FALSE);
1126 if (sinp->sin_family != AF_INET)
1127 return (B_FALSE);
1128 IN6_V4MAPPED_TO_IPADDR(addr, v4addr);
1129 return (sinp->sin_addr.s_addr == v4addr);
1134 * is_rtm_v6(): determine if routing socket message is IPv6
1136 * input: struct ifa_msghdr *: pointer to routing socket message
1137 * int: message length
1138 * output: boolean_t
1141 static boolean_t
1142 is_rtm_v6(const struct ifa_msghdr *ifam, int msglen)
1144 const char *cp, *lim;
1145 uint_t flag;
1146 const struct sockaddr *sa;
1148 cp = (const char *)(ifam + 1);
1149 lim = (const char *)ifam + msglen;
1150 for (flag = ifam->ifam_addrs; flag != 0; flag &= flag - 1) {
1151 /* LINTED: alignment */
1152 sa = (const struct sockaddr *)cp;
1153 if ((const char *)(sa + 1) > lim)
1154 return (B_FALSE);
1155 switch (sa->sa_family) {
1156 case AF_INET:
1157 return (B_FALSE);
1158 case AF_LINK:
1159 cp += sizeof (struct sockaddr_dl);
1160 break;
1161 case AF_INET6:
1162 return (B_TRUE);
1163 default:
1164 cp += sizeof (struct sockaddr);
1165 break;
1168 return (B_FALSE);
1172 * check_lif(): check the state of a given logical interface and its DHCP
1173 * lease. We've been told by the routing socket that the
1174 * corresponding ifIndex has changed. This may mean that DAD has
1175 * completed or failed.
1177 * input: dhcp_lif_t *: pointer to the LIF
1178 * const struct ifa_msghdr *: routing socket message
1179 * int: size of routing socket message
1180 * output: boolean_t: B_TRUE if DAD has completed on this interface
1183 static boolean_t
1184 check_lif(dhcp_lif_t *lif, const struct ifa_msghdr *ifam, int msglen)
1186 boolean_t isv6, dad_wait, unplumb;
1187 int fd;
1188 struct lifreq lifr;
1190 isv6 = lif->lif_pif->pif_isv6;
1191 fd = isv6 ? v6_sock_fd : v4_sock_fd;
1194 * Get the real (64 bit) logical interface flags. Note that the
1195 * routing socket message has flags, but these are just the lower 32
1196 * bits.
1198 unplumb = B_FALSE;
1199 (void) memset(&lifr, 0, sizeof (lifr));
1200 (void) strlcpy(lifr.lifr_name, lif->lif_name, sizeof (lifr.lifr_name));
1201 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1203 * Failing to retrieve flags means that the interface is gone.
1204 * It hasn't failed to verify with DAD, but we still have to
1205 * give up on it.
1207 lifr.lifr_flags = 0;
1208 if (errno == ENXIO) {
1209 lif->lif_plumbed = B_FALSE;
1210 dhcpmsg(MSG_INFO, "%s has been removed; abandoning",
1211 lif->lif_name);
1212 if (!isv6)
1213 discard_default_routes(lif->lif_smachs);
1214 } else {
1215 dhcpmsg(MSG_ERR,
1216 "unable to retrieve interface flags on %s",
1217 lif->lif_name);
1219 unplumb = B_TRUE;
1220 } else if (!check_rtm_addr(ifam, msglen, isv6, &lif->lif_v6addr)) {
1222 * If the message is not about this logical interface,
1223 * then just ignore it.
1225 return (B_FALSE);
1226 } else if (lifr.lifr_flags & IFF_DUPLICATE) {
1227 dhcpmsg(MSG_ERROR, "interface %s has duplicate address",
1228 lif->lif_name);
1229 lif_mark_decline(lif, "duplicate address");
1230 close_ip_lif(lif);
1231 (void) open_ip_lif(lif, INADDR_ANY, B_TRUE);
1234 dad_wait = lif->lif_dad_wait;
1235 if (dad_wait) {
1236 dhcpmsg(MSG_VERBOSE, "check_lif: %s has finished DAD",
1237 lif->lif_name);
1238 lif->lif_dad_wait = B_FALSE;
1241 if (unplumb)
1242 unplumb_lif(lif);
1244 return (dad_wait);
1248 * check_main_lif(): check the state of a main logical interface for a state
1249 * machine. This is used only for DHCPv6.
1251 * input: dhcp_smach_t *: pointer to the state machine
1252 * const struct ifa_msghdr *: routing socket message
1253 * int: size of routing socket message
1254 * output: boolean_t: B_TRUE if LIF is ok.
1257 static boolean_t
1258 check_main_lif(dhcp_smach_t *dsmp, const struct ifa_msghdr *ifam, int msglen)
1260 dhcp_lif_t *lif = dsmp->dsm_lif;
1261 struct lifreq lifr;
1264 * Get the real (64 bit) logical interface flags. Note that the
1265 * routing socket message has flags, but these are just the lower 32
1266 * bits.
1268 (void) memset(&lifr, 0, sizeof (lifr));
1269 (void) strlcpy(lifr.lifr_name, lif->lif_name, sizeof (lifr.lifr_name));
1270 if (ioctl(v6_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) {
1272 * Failing to retrieve flags means that the interface is gone.
1273 * Our state machine is now trash.
1275 if (errno == ENXIO) {
1276 dhcpmsg(MSG_INFO, "%s has been removed; abandoning",
1277 lif->lif_name);
1278 } else {
1279 dhcpmsg(MSG_ERR,
1280 "unable to retrieve interface flags on %s",
1281 lif->lif_name);
1283 return (B_FALSE);
1284 } else if (!check_rtm_addr(ifam, msglen, B_TRUE, &lif->lif_v6addr)) {
1286 * If the message is not about this logical interface,
1287 * then just ignore it.
1289 return (B_TRUE);
1290 } else if (lifr.lifr_flags & IFF_DUPLICATE) {
1291 dhcpmsg(MSG_ERROR, "interface %s has duplicate address",
1292 lif->lif_name);
1293 return (B_FALSE);
1294 } else {
1295 return (B_TRUE);
1300 * process_link_up_down(): check the state of a physical interface for up/down
1301 * transitions; must go through INIT_REBOOT state if
1302 * the link flaps.
1304 * input: dhcp_pif_t *: pointer to the physical interface to check
1305 * const struct if_msghdr *: routing socket message
1306 * output: none
1309 static void
1310 process_link_up_down(dhcp_pif_t *pif, const struct if_msghdr *ifm)
1312 struct lifreq lifr;
1313 boolean_t isv6;
1314 int fd;
1317 * If the message implies no change of flags, then we're done; no need
1318 * to check further. Note that if we have multiple state machines on a
1319 * single physical interface, this test keeps us from issuing an ioctl
1320 * for each one.
1322 if ((ifm->ifm_flags & IFF_RUNNING) && pif->pif_running ||
1323 !(ifm->ifm_flags & IFF_RUNNING) && !pif->pif_running)
1324 return;
1327 * We don't know what the real interface flags are, because the
1328 * if_index number is only 16 bits; we must go ask.
1330 isv6 = pif->pif_isv6;
1331 fd = isv6 ? v6_sock_fd : v4_sock_fd;
1332 (void) memset(&lifr, 0, sizeof (lifr));
1333 (void) strlcpy(lifr.lifr_name, pif->pif_name, sizeof (lifr.lifr_name));
1335 if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1 ||
1336 !(lifr.lifr_flags & IFF_RUNNING)) {
1338 * If we've lost the interface or it has gone down, then
1339 * nothing special to do; just turn off the running flag.
1341 pif_status(pif, B_FALSE);
1342 } else {
1344 * Interface has come back up: go through verification process.
1346 pif_status(pif, B_TRUE);
1351 * rtsock_event(): fetches routing socket messages and updates internal
1352 * interface state based on those messages.
1354 * input: iu_eh_t *: unused
1355 * int: the routing socket file descriptor
1356 * (other arguments unused)
1357 * output: void
1360 /* ARGSUSED */
1361 static void
1362 rtsock_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
1364 dhcp_smach_t *dsmp, *dsmnext;
1365 union {
1366 struct ifa_msghdr ifam;
1367 struct if_msghdr ifm;
1368 char buf[1024];
1369 } msg;
1370 uint16_t ifindex;
1371 int msglen;
1372 boolean_t isv6;
1374 if ((msglen = read(fd, &msg, sizeof (msg))) <= 0)
1375 return;
1377 /* Note that the routing socket interface index is just 16 bits */
1378 if (msg.ifm.ifm_type == RTM_IFINFO) {
1379 ifindex = msg.ifm.ifm_index;
1380 isv6 = (msg.ifm.ifm_flags & IFF_IPV6) ? B_TRUE : B_FALSE;
1381 } else if (msg.ifam.ifam_type == RTM_DELADDR ||
1382 msg.ifam.ifam_type == RTM_NEWADDR) {
1383 ifindex = msg.ifam.ifam_index;
1384 isv6 = is_rtm_v6(&msg.ifam, msglen);
1385 } else {
1386 return;
1389 for (dsmp = lookup_smach_by_uindex(ifindex, NULL, isv6);
1390 dsmp != NULL; dsmp = dsmnext) {
1391 DHCPSTATE oldstate;
1392 boolean_t lif_finished;
1393 boolean_t lease_removed;
1394 dhcp_lease_t *dlp, *dlnext;
1397 * Note that script_start can call dhcp_drop directly, and
1398 * that will do release_smach.
1400 dsmnext = lookup_smach_by_uindex(ifindex, dsmp, isv6);
1401 oldstate = dsmp->dsm_state;
1404 * Ignore state machines that are currently processing drop or
1405 * release; there is nothing more we can do for them.
1407 if (dsmp->dsm_droprelease)
1408 continue;
1411 * Look for link up/down notifications. These occur on a
1412 * physical interface basis.
1414 if (msg.ifm.ifm_type == RTM_IFINFO) {
1415 process_link_up_down(dsmp->dsm_lif->lif_pif, &msg.ifm);
1416 continue;
1420 * Since we cannot trust the flags reported by the routing
1421 * socket (they're just 32 bits -- and thus never include
1422 * IFF_DUPLICATE), and we can't trust the ifindex (it's only 16
1423 * bits and also doesn't reflect the alias in use), we get
1424 * flags on all matching interfaces, and go by that.
1426 lif_finished = B_FALSE;
1427 lease_removed = B_FALSE;
1428 for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlnext) {
1429 dhcp_lif_t *lif, *lifnext;
1430 uint_t nlifs = dlp->dl_nlifs;
1432 dlnext = dlp->dl_next;
1433 for (lif = dlp->dl_lifs; lif != NULL && nlifs > 0;
1434 lif = lifnext, nlifs--) {
1435 lifnext = lif->lif_next;
1436 if (check_lif(lif, &msg.ifam, msglen)) {
1437 dsmp->dsm_lif_wait--;
1438 lif_finished = B_TRUE;
1441 if (dlp->dl_nlifs == 0) {
1442 remove_lease(dlp);
1443 lease_removed = B_TRUE;
1447 if ((isv6 && !check_main_lif(dsmp, &msg.ifam, msglen)) ||
1448 (!isv6 && !verify_lif(dsmp->dsm_lif))) {
1449 finished_smach(dsmp, DHCP_IPC_E_INVIF);
1450 continue;
1454 * Ignore this state machine if nothing interesting has
1455 * happened.
1457 if (!lif_finished && dsmp->dsm_lif_down == 0 &&
1458 (dsmp->dsm_leases != NULL || !lease_removed))
1459 continue;
1462 * If we're still waiting for DAD to complete on some of the
1463 * configured LIFs, then don't send a response.
1465 if (dsmp->dsm_lif_wait != 0) {
1466 dhcpmsg(MSG_VERBOSE, "rtsock_event: %s still has %d "
1467 "LIFs waiting on DAD", dsmp->dsm_name,
1468 dsmp->dsm_lif_wait);
1469 continue;
1473 * If we have some failed LIFs, then handle them now. We'll
1474 * remove them from the list. Any leases that become empty are
1475 * also removed as part of the decline-generation process.
1477 if (dsmp->dsm_lif_down != 0)
1478 send_declines(dsmp);
1480 if (dsmp->dsm_leases == NULL) {
1481 dsmp->dsm_bad_offers++;
1483 * For DHCPv6, we'll process the restart once we're
1484 * done sending Decline messages, because these are
1485 * supposed to be acknowledged. With DHCPv4, there's
1486 * no acknowledgment for a DECLINE, so after sending
1487 * it, we just restart right away.
1489 if (!dsmp->dsm_isv6) {
1490 dhcpmsg(MSG_VERBOSE, "rtsock_event: %s has no "
1491 "LIFs left", dsmp->dsm_name);
1492 dhcp_restart(dsmp);
1494 } else {
1496 * If we're now up on at least some of the leases and
1497 * we were waiting for that, then kick off the rest of
1498 * configuration. Lease validation and DAD are done.
1500 dhcpmsg(MSG_VERBOSE, "rtsock_event: all LIFs verified "
1501 "on %s in %s state", dsmp->dsm_name,
1502 dhcp_state_to_string(oldstate));
1503 if (oldstate == PRE_BOUND ||
1504 oldstate == ADOPTING)
1505 dhcp_bound_complete(dsmp);
1506 if (oldstate == ADOPTING)
1507 dhcp_adopt_complete(dsmp);
1513 * check_cmd_allowed(): check whether the requested command is allowed in the
1514 * state specified.
1516 * input: DHCPSTATE: current state
1517 * dhcp_ipc_type_t: requested command
1518 * output: boolean_t: B_TRUE if command is allowed in this state
1521 boolean_t
1522 check_cmd_allowed(DHCPSTATE state, dhcp_ipc_type_t cmd)
1524 return (ipc_cmd_allowed[state][cmd] != 0);
1527 static boolean_t
1528 is_iscsi_active(void)
1530 int fd;
1531 int active = 0;
1533 if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) != -1) {
1534 if (ioctl(fd, ISCSI_IS_ACTIVE, &active) != 0)
1535 active = 0;
1536 (void) close(fd);
1539 return (active != 0);