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]
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 * This module contains core functions for managing DHCP state machine
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <netinet/arp.h>
37 #include <arpa/inet.h>
39 #include <dhcpagent_util.h>
40 #include <dhcp_stable.h>
41 #include <dhcp_inittab.h>
45 #include "interface.h"
47 #include "script_handler.h"
49 static uint_t global_smach_count
;
51 static uchar_t
*global_duid
;
52 static size_t global_duidlen
;
55 * iaid_retry(): attempt to write LIF IAID again
57 * input: iu_tq_t *: ignored
58 * void *: pointer to LIF
64 iaid_retry(iu_tq_t
*tqp
, void *arg
)
66 dhcp_lif_t
*lif
= arg
;
68 if (write_stable_iaid(lif
->lif_name
, lif
->lif_iaid
) == -1) {
71 "iaid_retry: unable to write out IAID for %s",
75 lif
->lif_iaid_id
= iu_schedule_timer(tq
, 60,
84 * parse_param_list(): parse a parameter list.
86 * input: const char *: parameter list string with comma-separated entries
87 * uint_t *: return parameter; number of entries decoded
88 * const char *: name of parameter list for logging purposes
89 * dhcp_smach_t *: smach pointer for logging
90 * output: uint16_t *: allocated array of parameters, or NULL if none.
94 parse_param_list(const char *param_list
, uint_t
*param_cnt
,
95 const char *param_name
, dhcp_smach_t
*dsmp
)
98 char tsym
[DSYM_MAX_SYM_LEN
+ 1];
101 dhcp_symbol_t
*entry
;
105 if (param_list
== NULL
)
108 for (maxparam
= 1, i
= 0; param_list
[i
] != '\0'; i
++) {
109 if (param_list
[i
] == ',')
113 params
= malloc(maxparam
* sizeof (*params
));
114 if (params
== NULL
) {
116 "cannot allocate parameter %s list for %s (continuing)",
117 param_name
, dsmp
->dsm_name
);
121 for (i
= 0; i
< maxparam
; ) {
123 if (isspace(*param_list
))
126 /* extract the next element on the list */
127 cp
= strchr(param_list
, ',');
128 if (cp
== NULL
|| cp
- param_list
>= sizeof (tsym
))
129 (void) strlcpy(tsym
, param_list
, sizeof (tsym
));
131 (void) strlcpy(tsym
, param_list
, cp
- param_list
+ 1);
133 /* LINTED -- do nothing with blanks on purpose */
134 if (tsym
[0] == '\0') {
136 } else if (isalpha(tsym
[0])) {
137 entry
= inittab_getbyname(ITAB_CAT_SITE
|
139 (dsmp
->dsm_isv6
? ITAB_CAT_V6
: 0),
140 ITAB_CONS_INFO
, tsym
);
142 dhcpmsg(MSG_INFO
, "ignored unknown %s list "
143 "entry '%s' for %s", param_name
, tsym
,
146 params
[i
++] = entry
->ds_code
;
150 params
[i
++] = strtoul(tsym
, NULL
, 0);
162 * insert_smach(): Create a state machine instance on a given logical
163 * interface. The state machine holds the caller's LIF
164 * reference on success, and frees it on failure.
166 * input: dhcp_lif_t *: logical interface name
167 * int *: set to DHCP_IPC_E_* if creation fails
168 * output: dhcp_smach_t *: state machine instance
172 insert_smach(dhcp_lif_t
*lif
, int *error
)
174 dhcp_smach_t
*dsmp
, *alt_primary
;
178 if ((dsmp
= calloc(1, sizeof (*dsmp
))) == NULL
) {
179 dhcpmsg(MSG_ERR
, "cannot allocate state machine entry for %s",
183 *error
= DHCP_IPC_E_MEMORY
;
186 dsmp
->dsm_name
= lif
->lif_name
;
188 dsmp
->dsm_hold_count
= 1;
189 dsmp
->dsm_state
= INIT
;
190 dsmp
->dsm_dflags
= DHCP_IF_REMOVED
; /* until added to list */
191 isv6
= lif
->lif_pif
->pif_isv6
;
194 * Now that we have a controlling LIF, we need to assign an IAID to
197 if (lif
->lif_iaid
== 0 &&
198 (lif
->lif_iaid
= read_stable_iaid(lif
->lif_name
)) == 0) {
199 static uint32_t iaidctr
= 0x80000000u
;
202 * If this is a logical interface, then use an arbitrary seed
203 * value. Otherwise, use the ifIndex.
205 lif
->lif_iaid
= make_stable_iaid(lif
->lif_name
,
206 strchr(lif
->lif_name
, ':') != NULL
? iaidctr
++ :
207 lif
->lif_pif
->pif_index
);
209 "insert_smach: manufactured IAID %u for v%d %s",
210 lif
->lif_iaid
, isv6
? 6 : 4, lif
->lif_name
);
212 iaid_retry(NULL
, lif
);
216 dsmp
->dsm_dflags
|= DHCP_IF_V6
;
217 dsmp
->dsm_server
= ipv6_all_dhcp_relay_and_servers
;
220 * With DHCPv6, we do all of our I/O using the common
221 * v6_sock_fd. There's no need for per-interface file
222 * descriptors because we have IPV6_PKTINFO.
225 IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST
),
229 * With IPv4 DHCP, we use a socket per lif.
231 if (!open_ip_lif(lif
, INADDR_ANY
, B_TRUE
)) {
232 dhcpmsg(MSG_ERR
, "unable to open socket for %s",
234 /* This will also dispose of the LIF */
236 *error
= DHCP_IPC_E_SOCKET
;
242 ipc_action_init(&dsmp
->dsm_ia
);
244 dsmp
->dsm_neg_hrtime
= gethrtime();
245 dsmp
->dsm_offer_timer
= -1;
246 dsmp
->dsm_start_timer
= -1;
247 dsmp
->dsm_retrans_timer
= -1;
250 * Initialize the parameter request and ignore lists, if any.
252 plist
= df_get_string(dsmp
->dsm_name
, isv6
, DF_PARAM_REQUEST_LIST
);
253 dsmp
->dsm_prl
= parse_param_list(plist
, &dsmp
->dsm_prllen
, "request",
255 plist
= df_get_string(dsmp
->dsm_name
, isv6
, DF_PARAM_IGNORE_LIST
);
256 dsmp
->dsm_pil
= parse_param_list(plist
, &dsmp
->dsm_pillen
, "ignore",
259 dsmp
->dsm_offer_wait
= df_get_int(dsmp
->dsm_name
, isv6
,
263 * If there is no primary of this type, and there is one of the other,
264 * then make this one primary if it's on the same named PIF.
266 if (primary_smach(isv6
) == NULL
&&
267 (alt_primary
= primary_smach(!isv6
)) != NULL
) {
268 if (strcmp(lif
->lif_pif
->pif_name
,
269 alt_primary
->dsm_lif
->lif_pif
->pif_name
) == 0) {
271 "insert_smach: making %s primary for v%d",
272 dsmp
->dsm_name
, isv6
? 6 : 4);
273 dsmp
->dsm_dflags
|= DHCP_IF_PRIMARY
;
278 * We now have at least one state machine running, so cancel any
279 * running inactivity timer.
281 if (inactivity_id
!= -1 &&
282 iu_cancel_timer(tq
, inactivity_id
, NULL
) == 1)
285 dsmp
->dsm_dflags
&= ~DHCP_IF_REMOVED
;
286 insque(dsmp
, &lif
->lif_smachs
);
287 global_smach_count
++;
288 dhcpmsg(MSG_DEBUG2
, "insert_smach: inserted %s", dsmp
->dsm_name
);
294 * hold_smach(): acquires a hold on a state machine
296 * input: dhcp_smach_t *: the state machine to acquire a hold on
301 hold_smach(dhcp_smach_t
*dsmp
)
303 dsmp
->dsm_hold_count
++;
305 dhcpmsg(MSG_DEBUG2
, "hold_smach: hold count on %s: %d",
306 dsmp
->dsm_name
, dsmp
->dsm_hold_count
);
310 * free_smach(): frees the memory occupied by a state machine
312 * input: dhcp_smach_t *: the DHCP state machine to free
317 free_smach(dhcp_smach_t
*dsmp
)
319 dhcpmsg(MSG_DEBUG
, "free_smach: freeing state machine %s",
322 deprecate_leases(dsmp
);
323 remove_lif(dsmp
->dsm_lif
);
324 release_lif(dsmp
->dsm_lif
);
325 free_pkt_list(&dsmp
->dsm_recv_pkt_list
);
326 if (dsmp
->dsm_ack
!= dsmp
->dsm_orig_ack
)
327 free_pkt_entry(dsmp
->dsm_orig_ack
);
328 free_pkt_entry(dsmp
->dsm_ack
);
329 free(dsmp
->dsm_send_pkt
.pkt
);
333 free(dsmp
->dsm_routers
);
334 free(dsmp
->dsm_reqhost
);
337 /* no big deal if this fails */
338 if (global_smach_count
== 0 && inactivity_id
== -1) {
339 inactivity_id
= iu_schedule_timer(tq
, DHCP_INACTIVITY_WAIT
,
340 inactivity_shutdown
, NULL
);
345 * release_smach(): releases a hold previously acquired on a state machine.
346 * If the hold count reaches 0, the state machine is freed.
348 * input: dhcp_smach_t *: the state machine entry to release the hold on
353 release_smach(dhcp_smach_t
*dsmp
)
355 if (dsmp
->dsm_hold_count
== 0) {
356 dhcpmsg(MSG_CRIT
, "release_smach: extraneous release");
360 if (dsmp
->dsm_hold_count
== 1 &&
361 !(dsmp
->dsm_dflags
& DHCP_IF_REMOVED
)) {
362 dhcpmsg(MSG_CRIT
, "release_smach: missing removal");
366 if (--dsmp
->dsm_hold_count
== 0) {
369 dhcpmsg(MSG_DEBUG2
, "release_smach: hold count on %s: %d",
370 dsmp
->dsm_name
, dsmp
->dsm_hold_count
);
375 * next_smach(): state machine iterator function
377 * input: dhcp_smach_t *: current state machine (or NULL for list start)
378 * boolean_t: B_TRUE if DHCPv6, B_FALSE otherwise
379 * output: dhcp_smach_t *: next state machine in list
383 next_smach(dhcp_smach_t
*dsmp
, boolean_t isv6
)
389 if (dsmp
->dsm_next
!= NULL
)
390 return (dsmp
->dsm_next
);
392 if ((lif
= dsmp
->dsm_lif
) != NULL
)
394 for (; lif
!= NULL
; lif
= lif
->lif_next
) {
395 if (lif
->lif_smachs
!= NULL
)
396 return (lif
->lif_smachs
);
399 if ((pif
= dsmp
->dsm_lif
->lif_pif
) != NULL
)
402 pif
= isv6
? v6root
: v4root
;
404 for (; pif
!= NULL
; pif
= pif
->pif_next
) {
405 for (lif
= pif
->pif_lifs
; lif
!= NULL
; lif
= lif
->lif_next
) {
406 if (lif
->lif_smachs
!= NULL
)
407 return (lif
->lif_smachs
);
414 * primary_smach(): loop through all state machines of the given type (v4 or
415 * v6) in the system, and locate the one that's primary.
417 * input: boolean_t: B_TRUE for IPv6
418 * output: dhcp_smach_t *: the primary state machine
422 primary_smach(boolean_t isv6
)
426 for (dsmp
= next_smach(NULL
, isv6
); dsmp
!= NULL
;
427 dsmp
= next_smach(dsmp
, isv6
)) {
428 if (dsmp
->dsm_dflags
& DHCP_IF_PRIMARY
)
435 * info_primary_smach(): loop through all state machines of the given type (v4
436 * or v6) in the system, and locate the one that should
437 * be considered "primary" for dhcpinfo.
439 * input: boolean_t: B_TRUE for IPv6
440 * output: dhcp_smach_t *: the dhcpinfo primary state machine
444 info_primary_smach(boolean_t isv6
)
446 dhcp_smach_t
*bestdsm
= NULL
;
449 for (dsmp
= next_smach(NULL
, isv6
); dsmp
!= NULL
;
450 dsmp
= next_smach(dsmp
, isv6
)) {
452 * If there is a primary, then something previously went wrong
453 * with verification, because the caller uses primary_smach()
454 * before calling this routine. There's nothing else we can do
455 * but return failure, as the designated primary must be bad.
457 if (dsmp
->dsm_dflags
& DHCP_IF_PRIMARY
)
460 /* If we have no information, then we're not primary. */
461 if (dsmp
->dsm_ack
== NULL
)
465 * Among those interfaces that have DHCP information, the
466 * "primary" is the one that sorts lexically first.
468 if (bestdsm
== NULL
||
469 strcmp(dsmp
->dsm_name
, bestdsm
->dsm_name
) < 0)
476 * make_primary(): designate a given state machine as being the primary
477 * instance on the primary interface. Note that the user often
478 * thinks in terms of a primary "interface" (rather than just
479 * an instance), so we go to lengths here to keep v4 and v6 in
482 * input: dhcp_smach_t *: the primary state machine
487 make_primary(dhcp_smach_t
*dsmp
)
489 dhcp_smach_t
*old_primary
, *alt_primary
;
492 if ((old_primary
= primary_smach(dsmp
->dsm_isv6
)) != NULL
)
493 old_primary
->dsm_dflags
&= ~DHCP_IF_PRIMARY
;
494 dsmp
->dsm_dflags
|= DHCP_IF_PRIMARY
;
497 * Find the primary for the other protocol.
499 alt_primary
= primary_smach(!dsmp
->dsm_isv6
);
502 * If it's on a different interface, then cancel that. If it's on the
503 * same interface, then we're done.
505 if (alt_primary
!= NULL
) {
506 if (strcmp(alt_primary
->dsm_lif
->lif_pif
->pif_name
,
507 dsmp
->dsm_lif
->lif_pif
->pif_name
) == 0)
509 alt_primary
->dsm_dflags
&= ~DHCP_IF_PRIMARY
;
513 * We need a new primary for the other protocol. If the PIF exists,
514 * there must be at least one state machine. Just choose the first for
515 * consistency with insert_smach().
517 if ((pif
= lookup_pif_by_name(dsmp
->dsm_lif
->lif_pif
->pif_name
,
518 !dsmp
->dsm_isv6
)) != NULL
) {
519 pif
->pif_lifs
->lif_smachs
->dsm_dflags
|= DHCP_IF_PRIMARY
;
524 * lookup_smach(): finds a state machine by name and type; used for dispatching
527 * input: const char *: the name of the state machine
528 * boolean_t: B_TRUE if DHCPv6, B_FALSE otherwise
529 * output: dhcp_smach_t *: the state machine found
533 lookup_smach(const char *smname
, boolean_t isv6
)
537 for (dsmp
= next_smach(NULL
, isv6
); dsmp
!= NULL
;
538 dsmp
= next_smach(dsmp
, isv6
)) {
539 if (strcmp(dsmp
->dsm_name
, smname
) == 0)
546 * lookup_smach_by_uindex(): iterate through running state machines by
547 * truncated interface index.
549 * input: uint16_t: the interface index (truncated)
550 * dhcp_smach_t *: the previous state machine, or NULL for start
551 * boolean_t: B_TRUE for DHCPv6, B_FALSE for IPv4 DHCP
552 * output: dhcp_smach_t *: next state machine, or NULL at end of list
556 lookup_smach_by_uindex(uint16_t ifindex
, dhcp_smach_t
*dsmp
, boolean_t isv6
)
562 * If the user gives us a state machine, then check that the next one
563 * available is on the same physical interface. If so, then go ahead
567 pif
= dsmp
->dsm_lif
->lif_pif
;
568 if ((dsmp
= next_smach(dsmp
, isv6
)) == NULL
)
570 if (pif
== dsmp
->dsm_lif
->lif_pif
)
573 /* Otherwise, start at the beginning of the list */
578 * Find the next physical interface with the same truncated interface
579 * index, and return the first state machine on that. If there are no
580 * more physical interfaces that match, then we're done.
583 pif
= lookup_pif_by_uindex(ifindex
, pif
, isv6
);
586 for (lif
= pif
->pif_lifs
; lif
!= NULL
; lif
= lif
->lif_next
) {
587 if ((dsmp
= lif
->lif_smachs
) != NULL
)
590 } while (dsmp
== NULL
);
595 * lookup_smach_by_xid(): iterate through running state machines by transaction
596 * id. Transaction ID zero means "all state machines."
598 * input: uint32_t: the transaction id to look up
599 * dhcp_smach_t *: the previous state machine, or NULL for start
600 * boolean_t: B_TRUE if DHCPv6, B_FALSE otherwise
601 * output: dhcp_smach_t *: next state machine, or NULL at end of list
605 lookup_smach_by_xid(uint32_t xid
, dhcp_smach_t
*dsmp
, boolean_t isv6
)
607 for (dsmp
= next_smach(dsmp
, isv6
); dsmp
!= NULL
;
608 dsmp
= next_smach(dsmp
, isv6
)) {
610 pkt_get_xid(dsmp
->dsm_send_pkt
.pkt
, isv6
) == xid
)
618 * lookup_smach_by_event(): find a state machine busy with a particular event
619 * ID. This is used only for error handling.
621 * input: iu_event_id_t: the event id to look up
622 * output: dhcp_smach_t *: matching state machine, or NULL if none
626 lookup_smach_by_event(iu_event_id_t eid
)
629 boolean_t isv6
= B_FALSE
;
632 for (dsmp
= next_smach(NULL
, isv6
); dsmp
!= NULL
;
633 dsmp
= next_smach(dsmp
, isv6
)) {
634 if ((dsmp
->dsm_dflags
& DHCP_IF_BUSY
) &&
635 eid
== dsmp
->dsm_ia
.ia_eid
)
647 * cancel_offer_timer(): stop the offer polling timer on a given state machine
649 * input: dhcp_smach_t *: state machine on which to stop polling for offers
654 cancel_offer_timer(dhcp_smach_t
*dsmp
)
658 if (dsmp
->dsm_offer_timer
!= -1) {
659 retval
= iu_cancel_timer(tq
, dsmp
->dsm_offer_timer
, NULL
);
660 dsmp
->dsm_offer_timer
= -1;
667 * cancel_smach_timers(): stop all of the timers related to a given state
668 * machine, including lease and LIF expiry.
670 * input: dhcp_smach_t *: state machine to cancel
672 * note: this function assumes that the iu timer functions are synchronous
673 * and thus don't require any protection or ordering on cancellation.
677 cancel_smach_timers(dhcp_smach_t
*dsmp
)
683 for (dlp
= dsmp
->dsm_leases
; dlp
!= NULL
; dlp
= dlp
->dl_next
) {
684 cancel_lease_timers(dlp
);
686 nlifs
= dlp
->dl_nlifs
;
687 for (; nlifs
> 0; nlifs
--, lif
= lif
->lif_next
)
688 cancel_lif_timers(lif
);
691 cancel_offer_timer(dsmp
);
692 stop_pkt_retransmission(dsmp
);
693 if (dsmp
->dsm_start_timer
!= -1) {
694 (void) iu_cancel_timer(tq
, dsmp
->dsm_start_timer
, NULL
);
695 dsmp
->dsm_start_timer
= -1;
701 * remove_smach(): removes a given state machine from the system. marks it
702 * for being freed (but may not actually free it).
704 * input: dhcp_smach_t *: the state machine to remove
709 remove_smach(dhcp_smach_t
*dsmp
)
711 if (dsmp
->dsm_dflags
& DHCP_IF_REMOVED
)
714 dhcpmsg(MSG_DEBUG2
, "remove_smach: removing %s", dsmp
->dsm_name
);
715 dsmp
->dsm_dflags
|= DHCP_IF_REMOVED
;
717 global_smach_count
--;
720 * if we have long term timers, cancel them so that state machine
721 * resources can be reclaimed in a reasonable amount of time.
723 cancel_smach_timers(dsmp
);
725 /* Drop the hold that the LIF's state machine list had on us */
730 * finished_smach(): we're finished with a given state machine; remove it from
731 * the system and tell the user (who may have initiated the
732 * removal process). Note that we remove it from the system
733 * first to allow back-to-back drop and create invocations.
735 * input: dhcp_smach_t *: the state machine to remove
741 finished_smach(dhcp_smach_t
*dsmp
, int error
)
745 if (dsmp
->dsm_ia
.ia_fd
!= -1)
746 ipc_action_finish(dsmp
, error
);
748 (void) async_cancel(dsmp
);
753 * is_bound_state(): checks if a state indicates the client is bound
755 * input: DHCPSTATE: the state to check
756 * output: boolean_t: B_TRUE if the state is bound, B_FALSE if not
760 is_bound_state(DHCPSTATE state
)
762 return (state
== BOUND
|| state
== REBINDING
|| state
== INFORMATION
||
763 state
== RELEASING
|| state
== INFORM_SENT
|| state
== RENEWING
);
767 * set_smach_state(): changes state and updates I/O
769 * input: dhcp_smach_t *: the state machine to change
770 * DHCPSTATE: the new state
771 * output: boolean_t: B_TRUE on success, B_FALSE on failure
775 set_smach_state(dhcp_smach_t
*dsmp
, DHCPSTATE state
)
777 dhcp_lif_t
*lif
= dsmp
->dsm_lif
;
779 if (dsmp
->dsm_state
!= state
) {
781 "set_smach_state: changing from %s to %s on %s",
782 dhcp_state_to_string(dsmp
->dsm_state
),
783 dhcp_state_to_string(state
), dsmp
->dsm_name
);
786 * For IPv4, when we're in a bound state our socket must be
787 * bound to our address. Otherwise, our socket must be bound
788 * to INADDR_ANY. For IPv6, no such change is necessary.
790 if (!dsmp
->dsm_isv6
) {
791 if (is_bound_state(dsmp
->dsm_state
)) {
792 if (!is_bound_state(state
)) {
794 if (!open_ip_lif(lif
, INADDR_ANY
,
799 if (is_bound_state(state
)) {
801 if (!open_ip_lif(lif
,
802 ntohl(lif
->lif_addr
), B_FALSE
))
808 dsmp
->dsm_state
= state
;
814 * duid_retry(): attempt to write DUID again
816 * input: iu_tq_t *: ignored
823 duid_retry(iu_tq_t
*tqp
, void *arg
)
825 if (write_stable_duid(global_duid
, global_duidlen
) == -1) {
826 if (errno
!= EROFS
) {
828 "duid_retry: unable to write out DUID");
830 (void) iu_schedule_timer(tq
, 60, duid_retry
, NULL
);
836 * get_smach_cid(): gets the client ID for a given state machine.
838 * input: dhcp_smach_t *: the state machine to set up
839 * output: int: DHCP_IPC_SUCCESS or one of DHCP_IPC_E_* on failure.
843 get_smach_cid(dhcp_smach_t
*dsmp
)
846 uint_t client_id_len
;
847 dhcp_lif_t
*lif
= dsmp
->dsm_lif
;
848 dhcp_pif_t
*pif
= lif
->lif_pif
;
853 * Look in defaults file for the client-id. If present, this takes
854 * precedence over all other forms of ID.
857 dhcpmsg(MSG_DEBUG
, "get_smach_cid: getting default client-id "
858 "property on %s", dsmp
->dsm_name
);
859 value
= df_get_string(dsmp
->dsm_name
, pif
->pif_isv6
, DF_CLIENT_ID
);
862 * The Client ID string can have one of three basic forms:
863 * <decimal>,<data...>
867 * The first form is an RFC 3315 DUID. This is legal for both
868 * IPv4 DHCP and DHCPv6. For IPv4, an RFC 4361 Client ID is
869 * constructed from this value.
871 * The second and third forms are legal for IPv4 only. This is
872 * a raw Client ID, in hex or ASCII string format.
875 if (isdigit(*value
) &&
876 value
[strspn(value
, "0123456789")] == ',') {
882 duidtype
= strtoul(value
, &cp
, 0);
883 if (value
== cp
|| errno
!= 0 || *cp
!= ',' ||
885 dhcpmsg(MSG_ERR
, "get_smach_cid: cannot parse "
886 "DUID type in %s", value
);
887 goto no_specified_id
;
892 case DHCPV6_DUID_LLT
: {
897 subtype
= strtoul(value
, &cp
, 0);
898 if (value
== cp
|| errno
!= 0 || *cp
!= ',' ||
900 dhcpmsg(MSG_ERR
, "get_smach_cid: "
901 "cannot parse MAC type in %s",
903 goto no_specified_id
;
906 client_id_len
= pif
->pif_isv6
? 1 : 5;
907 for (; *cp
!= '\0'; cp
++) {
910 else if (!isxdigit(*cp
))
913 if (duidtype
== DHCPV6_DUID_LL
) {
917 client_id_len
+= sizeof (*dllt
);
918 dllt
= malloc(client_id_len
);
921 dsmp
->dsm_cid
= (uchar_t
*)dllt
;
922 dllt
->dllt_dutype
= htons(duidtype
);
923 dllt
->dllt_hwtype
= htons(subtype
);
924 now
= time(NULL
) - DUID_TIME_BASE
;
925 dllt
->dllt_time
= htonl(now
);
926 cp
= (char *)(dllt
+ 1);
930 client_id_len
+= sizeof (*dll
);
931 dll
= malloc(client_id_len
);
934 dsmp
->dsm_cid
= (uchar_t
*)dll
;
935 dll
->dll_dutype
= htons(duidtype
);
936 dll
->dll_hwtype
= htons(subtype
);
937 cp
= (char *)(dll
+ 1);
940 while ((chr
= *value
) != '\0') {
942 num
= (num
<< 4) + chr
- '0';
943 } else if (isxdigit(chr
)) {
944 num
= (num
<< 4) + 10 + chr
-
945 (isupper(chr
) ? 'A' : 'a');
946 } else if (chr
== ':') {
955 case DHCPV6_DUID_EN
: {
959 subtype
= strtoul(value
, &cp
, 0);
960 if (value
== cp
|| errno
!= 0 || *cp
!= ',') {
961 dhcpmsg(MSG_ERR
, "get_smach_cid: "
962 "cannot parse enterprise in %s",
964 goto no_specified_id
;
967 slen
= strlen(value
);
968 client_id_len
= (slen
+ 1) / 2;
969 den
= malloc(sizeof (*den
) + client_id_len
);
972 den
->den_dutype
= htons(duidtype
);
973 DHCPV6_SET_ENTNUM(den
, subtype
);
974 if (hexascii_to_octet(value
, slen
, den
+ 1,
975 &client_id_len
) != 0) {
976 dhcpmsg(MSG_ERROR
, "get_smach_cid: "
977 "cannot parse hex string in %s",
980 goto no_specified_id
;
982 dsmp
->dsm_cid
= (uchar_t
*)den
;
986 slen
= strlen(value
);
987 client_id_len
= (slen
+ 1) / 2;
988 cp
= malloc(client_id_len
);
991 if (hexascii_to_octet(value
, slen
, cp
,
992 &client_id_len
) != 0) {
993 dhcpmsg(MSG_ERROR
, "get_smach_cid: "
994 "cannot parse hex string in %s",
997 goto no_specified_id
;
999 dsmp
->dsm_cid
= (uchar_t
*)cp
;
1002 dsmp
->dsm_cidlen
= client_id_len
;
1003 if (!pif
->pif_isv6
) {
1004 (void) memmove(dsmp
->dsm_cid
+ 5,
1005 dsmp
->dsm_cid
, client_id_len
- 5);
1006 dsmp
->dsm_cid
[0] = 255;
1007 dsmp
->dsm_cid
[1] = lif
->lif_iaid
>> 24;
1008 dsmp
->dsm_cid
[2] = lif
->lif_iaid
>> 16;
1009 dsmp
->dsm_cid
[3] = lif
->lif_iaid
>> 8;
1010 dsmp
->dsm_cid
[4] = lif
->lif_iaid
;
1012 return (DHCP_IPC_SUCCESS
);
1015 if (pif
->pif_isv6
) {
1017 "get_smach_cid: client ID for %s invalid: %s",
1018 dsmp
->dsm_name
, value
);
1019 } else if (strncasecmp("0x", value
, 2) == 0 &&
1021 /* skip past the 0x and convert the value to binary */
1023 slen
= strlen(value
);
1024 client_id_len
= (slen
+ 1) / 2;
1025 dsmp
->dsm_cid
= malloc(client_id_len
);
1026 if (dsmp
->dsm_cid
== NULL
)
1028 if (hexascii_to_octet(value
, slen
, dsmp
->dsm_cid
,
1029 &client_id_len
) == 0) {
1030 dsmp
->dsm_cidlen
= client_id_len
;
1031 return (DHCP_IPC_SUCCESS
);
1033 dhcpmsg(MSG_WARNING
, "get_smach_cid: cannot convert "
1034 "hex value for Client ID on %s", dsmp
->dsm_name
);
1036 client_id_len
= strlen(value
);
1037 dsmp
->dsm_cid
= malloc(client_id_len
);
1038 if (dsmp
->dsm_cid
== NULL
)
1040 dsmp
->dsm_cidlen
= client_id_len
;
1041 (void) memcpy(dsmp
->dsm_cid
, value
, client_id_len
);
1042 return (DHCP_IPC_SUCCESS
);
1048 * There was either no user-specified Client ID value, or we were
1049 * unable to parse it. We need to determine if a Client ID is required
1050 * and, if so, generate one.
1052 * If it's IPv4, not in an IPMP group, and not a logical interface,
1053 * then we need to preserve backward-compatibility by avoiding
1054 * new-fangled DUID/IAID construction. (Note: even for IPMP test
1055 * addresses, we construct a DUID/IAID since we may renew a lease for
1056 * an IPMP test address on any functioning IP interface in the group.)
1058 if (!pif
->pif_isv6
&& pif
->pif_grifname
[0] == '\0' &&
1059 strchr(dsmp
->dsm_name
, ':') == NULL
) {
1060 if (pif
->pif_hwtype
== ARPHRD_IB
) {
1062 * This comes from the DHCP over IPoIB specification.
1063 * In the absence of an user specified client id, IPoIB
1064 * automatically uses the required format, with the
1065 * unique 4 octet value set to 0 (since IPoIB driver
1066 * allows only a single interface on a port with a
1067 * specific GID to belong to an IP subnet (PSARC
1068 * 2001/289, FWARC 2002/702).
1070 * Type Client-Identifier
1071 * +-----+-----+-----+-----+-----+----....----+
1072 * | 0 | 0 (4 octets) | GID (16 octets)|
1073 * +-----+-----+-----+-----+-----+----....----+
1075 dsmp
->dsm_cidlen
= 1 + 4 + 16;
1076 dsmp
->dsm_cid
= client_id
= malloc(dsmp
->dsm_cidlen
);
1077 if (dsmp
->dsm_cid
== NULL
)
1081 * Pick the GID from the mac address. The format
1082 * of the hardware address is:
1083 * +-----+-----+-----+-----+----....----+
1084 * | QPN (4 octets) | GID (16 octets)|
1085 * +-----+-----+-----+-----+----....----+
1087 (void) memcpy(client_id
+ 5, pif
->pif_hwaddr
+ 4,
1088 pif
->pif_hwlen
- 4);
1089 (void) memset(client_id
, 0, 5);
1091 return (DHCP_IPC_SUCCESS
);
1095 * Now check for a saved DUID. If there is one, then use it. If there
1096 * isn't, then generate a new one. For IPv4, we need to construct the
1097 * RFC 4361 Client ID with this value and the LIF's IAID.
1099 if (global_duid
== NULL
&&
1100 (global_duid
= read_stable_duid(&global_duidlen
)) == NULL
) {
1101 global_duid
= make_stable_duid(pif
->pif_name
, &global_duidlen
);
1102 if (global_duid
== NULL
)
1104 duid_retry(NULL
, NULL
);
1107 if (pif
->pif_isv6
) {
1108 dsmp
->dsm_cid
= malloc(global_duidlen
);
1109 if (dsmp
->dsm_cid
== NULL
)
1111 (void) memcpy(dsmp
->dsm_cid
, global_duid
, global_duidlen
);
1112 dsmp
->dsm_cidlen
= global_duidlen
;
1114 dsmp
->dsm_cid
= malloc(5 + global_duidlen
);
1115 if (dsmp
->dsm_cid
== NULL
)
1117 dsmp
->dsm_cid
[0] = 255;
1118 dsmp
->dsm_cid
[1] = lif
->lif_iaid
>> 24;
1119 dsmp
->dsm_cid
[2] = lif
->lif_iaid
>> 16;
1120 dsmp
->dsm_cid
[3] = lif
->lif_iaid
>> 8;
1121 dsmp
->dsm_cid
[4] = lif
->lif_iaid
;
1122 (void) memcpy(dsmp
->dsm_cid
+ 5, global_duid
, global_duidlen
);
1123 dsmp
->dsm_cidlen
= 5 + global_duidlen
;
1126 return (DHCP_IPC_SUCCESS
);
1129 dhcpmsg(MSG_ERR
, "get_smach_cid: cannot allocate Client Id for %s",
1131 return (DHCP_IPC_E_MEMORY
);
1135 * smach_count(): returns the number of state machines running
1138 * output: uint_t: the number of state machines
1144 return (global_smach_count
);
1148 * discard_default_routes(): removes a state machine's default routes alone.
1150 * input: dhcp_smach_t *: the state machine whose default routes need to be
1156 discard_default_routes(dhcp_smach_t
*dsmp
)
1158 free(dsmp
->dsm_routers
);
1159 dsmp
->dsm_routers
= NULL
;
1160 dsmp
->dsm_nrouters
= 0;
1164 * remove_default_routes(): removes a state machine's default routes from the
1165 * kernel and from the state machine.
1167 * input: dhcp_smach_t *: the state machine whose default routes need to be
1173 remove_default_routes(dhcp_smach_t
*dsmp
)
1178 if (dsmp
->dsm_routers
!= NULL
) {
1179 ifindex
= dsmp
->dsm_lif
->lif_pif
->pif_index
;
1180 for (idx
= dsmp
->dsm_nrouters
- 1; idx
>= 0; idx
--) {
1181 if (del_default_route(ifindex
,
1182 &dsmp
->dsm_routers
[idx
])) {
1183 dhcpmsg(MSG_DEBUG
, "remove_default_routes: "
1184 "removed %s from %s",
1185 inet_ntoa(dsmp
->dsm_routers
[idx
]),
1188 dhcpmsg(MSG_INFO
, "remove_default_routes: "
1189 "unable to remove %s from %s",
1190 inet_ntoa(dsmp
->dsm_routers
[idx
]),
1194 discard_default_routes(dsmp
);
1199 * reset_smach(): resets a state machine to its initial state
1201 * input: dhcp_smach_t *: the state machine to reset
1206 reset_smach(dhcp_smach_t
*dsmp
)
1208 dsmp
->dsm_dflags
&= ~DHCP_IF_FAILED
;
1210 remove_default_routes(dsmp
);
1212 free_pkt_list(&dsmp
->dsm_recv_pkt_list
);
1213 free_pkt_entry(dsmp
->dsm_ack
);
1214 if (dsmp
->dsm_orig_ack
!= dsmp
->dsm_ack
)
1215 free_pkt_entry(dsmp
->dsm_orig_ack
);
1216 dsmp
->dsm_ack
= dsmp
->dsm_orig_ack
= NULL
;
1218 free(dsmp
->dsm_reqhost
);
1219 dsmp
->dsm_reqhost
= NULL
;
1221 cancel_smach_timers(dsmp
);
1223 (void) set_smach_state(dsmp
, INIT
);
1224 if (dsmp
->dsm_isv6
) {
1225 dsmp
->dsm_server
= ipv6_all_dhcp_relay_and_servers
;
1227 IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST
),
1230 dsmp
->dsm_neg_hrtime
= gethrtime();
1232 * We must never get here with a script running, since it means we're
1233 * resetting an smach that is still in the middle of another state
1234 * transition with a pending dsm_script_callback.
1236 assert(dsmp
->dsm_script_pid
== -1);
1240 * refresh_smach(): refreshes a given state machine, as though awakened from
1241 * hibernation or by lower layer "link up."
1243 * input: dhcp_smach_t *: state machine to refresh
1248 refresh_smach(dhcp_smach_t
*dsmp
)
1250 if (dsmp
->dsm_state
== BOUND
|| dsmp
->dsm_state
== RENEWING
||
1251 dsmp
->dsm_state
== REBINDING
|| dsmp
->dsm_state
== INFORMATION
) {
1252 dhcpmsg(MSG_WARNING
, "refreshing state on %s", dsmp
->dsm_name
);
1253 cancel_smach_timers(dsmp
);
1254 if (dsmp
->dsm_state
== INFORMATION
)
1257 dhcp_init_reboot(dsmp
);
1262 * refresh_smachs(): refreshes all finite leases under DHCP control
1264 * input: iu_eh_t *: unused
1272 refresh_smachs(iu_eh_t
*eh
, int sig
, void *arg
)
1274 boolean_t isv6
= B_FALSE
;
1278 for (dsmp
= next_smach(NULL
, isv6
); dsmp
!= NULL
;
1279 dsmp
= next_smach(dsmp
, isv6
)) {
1280 refresh_smach(dsmp
);
1289 * nuke_smach_list(): delete the state machine list. For use when the
1290 * dhcpagent is exiting.
1297 nuke_smach_list(void)
1299 boolean_t isv6
= B_FALSE
;
1300 dhcp_smach_t
*dsmp
, *dsmp_next
;
1303 for (dsmp
= next_smach(NULL
, isv6
); dsmp
!= NULL
;
1307 dsmp_next
= next_smach(dsmp
, isv6
);
1309 /* If we're already dropping or releasing, skip */
1310 if (dsmp
->dsm_droprelease
)
1312 dsmp
->dsm_droprelease
= B_TRUE
;
1314 cancel_smach_timers(dsmp
);
1317 * If the script is started by script_start, dhcp_drop
1318 * and dhcp_release should and will only be called
1319 * after the script exits.
1321 if (df_get_bool(dsmp
->dsm_name
, isv6
,
1322 DF_RELEASE_ON_SIGTERM
) ||
1323 df_get_bool(dsmp
->dsm_name
, isv6
,
1324 DF_VERIFIED_LEASE_ONLY
)) {
1325 if (script_start(dsmp
, isv6
? EVENT_RELEASE6
:
1326 EVENT_RELEASE
, dhcp_release
,
1327 "DHCP agent is exiting", &status
)) {
1333 (void) script_start(dsmp
, isv6
? EVENT_DROP6
:
1334 EVENT_DROP
, dhcp_drop
, NULL
, NULL
);
1343 * insert_lease(): Create a lease structure on a given state machine. The
1344 * lease holds a reference to the state machine.
1346 * input: dhcp_smach_t *: state machine
1347 * output: dhcp_lease_t *: newly-created lease
1351 insert_lease(dhcp_smach_t
*dsmp
)
1355 if ((dlp
= calloc(1, sizeof (*dlp
))) == NULL
)
1357 dlp
->dl_smach
= dsmp
;
1358 dlp
->dl_hold_count
= 1;
1359 init_timer(&dlp
->dl_t1
, 0);
1360 init_timer(&dlp
->dl_t2
, 0);
1361 insque(dlp
, &dsmp
->dsm_leases
);
1362 dhcpmsg(MSG_DEBUG2
, "insert_lease: new lease for %s", dsmp
->dsm_name
);
1367 * hold_lease(): acquires a hold on a lease
1369 * input: dhcp_lease_t *: the lease to acquire a hold on
1374 hold_lease(dhcp_lease_t
*dlp
)
1376 dlp
->dl_hold_count
++;
1378 dhcpmsg(MSG_DEBUG2
, "hold_lease: hold count on lease for %s: %d",
1379 dlp
->dl_smach
->dsm_name
, dlp
->dl_hold_count
);
1383 * release_lease(): releases a hold previously acquired on a lease.
1384 * If the hold count reaches 0, the lease is freed.
1386 * input: dhcp_lease_t *: the lease to release the hold on
1391 release_lease(dhcp_lease_t
*dlp
)
1393 if (dlp
->dl_hold_count
== 0) {
1394 dhcpmsg(MSG_CRIT
, "release_lease: extraneous release");
1398 if (dlp
->dl_hold_count
== 1 && !dlp
->dl_removed
) {
1399 dhcpmsg(MSG_CRIT
, "release_lease: missing removal");
1403 if (--dlp
->dl_hold_count
== 0) {
1405 "release_lease: freeing lease on state machine %s",
1406 dlp
->dl_smach
->dsm_name
);
1410 "release_lease: hold count on lease for %s: %d",
1411 dlp
->dl_smach
->dsm_name
, dlp
->dl_hold_count
);
1416 * remove_lease(): removes a given lease from the state machine and drops the
1417 * state machine's hold on the lease.
1419 * input: dhcp_lease_t *: the lease to remove
1424 remove_lease(dhcp_lease_t
*dlp
)
1426 if (dlp
->dl_removed
) {
1427 dhcpmsg(MSG_CRIT
, "remove_lease: extraneous removal");
1429 dhcp_lif_t
*lif
, *lifnext
;
1433 "remove_lease: removed lease from state machine %s",
1434 dlp
->dl_smach
->dsm_name
);
1435 dlp
->dl_removed
= B_TRUE
;
1438 cancel_lease_timers(dlp
);
1441 nlifs
= dlp
->dl_nlifs
;
1442 for (; nlifs
> 0; nlifs
--, lif
= lifnext
) {
1443 lifnext
= lif
->lif_next
;
1452 * cancel_lease_timer(): cancels a lease-related timer
1454 * input: dhcp_lease_t *: the lease to operate on
1455 * dhcp_timer_t *: the timer to cancel
1460 cancel_lease_timer(dhcp_lease_t
*dlp
, dhcp_timer_t
*dt
)
1462 if (dt
->dt_id
== -1)
1464 if (cancel_timer(dt
)) {
1467 dhcpmsg(MSG_WARNING
,
1468 "cancel_lease_timer: cannot cancel timer");
1473 * cancel_lease_timers(): cancels an lease's pending timers
1475 * input: dhcp_lease_t *: the lease to operate on
1480 cancel_lease_timers(dhcp_lease_t
*dlp
)
1482 cancel_lease_timer(dlp
, &dlp
->dl_t1
);
1483 cancel_lease_timer(dlp
, &dlp
->dl_t2
);
1487 * schedule_lease_timer(): schedules a lease-related timer
1489 * input: dhcp_lease_t *: the lease to operate on
1490 * dhcp_timer_t *: the timer to schedule
1491 * iu_tq_callback_t *: the callback to call upon firing
1492 * output: boolean_t: B_TRUE if the timer was scheduled successfully
1496 schedule_lease_timer(dhcp_lease_t
*dlp
, dhcp_timer_t
*dt
,
1497 iu_tq_callback_t
*expire
)
1500 * If there's a timer running, cancel it and release its lease
1503 if (dt
->dt_id
!= -1) {
1504 if (!cancel_timer(dt
))
1509 if (schedule_timer(dt
, expire
, dlp
)) {
1513 dhcpmsg(MSG_WARNING
,
1514 "schedule_lease_timer: cannot schedule timer");
1520 * deprecate_leases(): remove all of the leases from a given state machine
1522 * input: dhcp_smach_t *: the state machine
1527 deprecate_leases(dhcp_smach_t
*dsmp
)
1532 * note that due to infelicities in the routing code, any default
1533 * routes must be removed prior to canonizing or deprecating the LIF.
1536 remove_default_routes(dsmp
);
1538 while ((dlp
= dsmp
->dsm_leases
) != NULL
)
1543 * verify_smach(): if the state machine is in a bound state, then verify the
1544 * standing of the configured interfaces. Abandon those that
1545 * the user has modified. If we end up with no valid leases,
1546 * then just terminate the state machine.
1548 * input: dhcp_smach_t *: the state machine
1549 * output: boolean_t: B_TRUE if the state machine is still valid.
1550 * note: assumes caller holds a state machine reference; as with most
1551 * callback functions.
1555 verify_smach(dhcp_smach_t
*dsmp
)
1557 dhcp_lease_t
*dlp
, *dlpn
;
1559 if (dsmp
->dsm_dflags
& DHCP_IF_REMOVED
) {
1560 release_smach(dsmp
);
1564 if (!dsmp
->dsm_isv6
) {
1566 * If this is DHCPv4, then verify the main LIF.
1568 if (!verify_lif(dsmp
->dsm_lif
))
1569 goto smach_terminate
;
1573 * If we're not in one of the bound states, then there are no LIFs to
1576 if (dsmp
->dsm_state
!= BOUND
&&
1577 dsmp
->dsm_state
!= RENEWING
&&
1578 dsmp
->dsm_state
!= REBINDING
) {
1579 release_smach(dsmp
);
1583 for (dlp
= dsmp
->dsm_leases
; dlp
!= NULL
; dlp
= dlpn
) {
1584 dhcp_lif_t
*lif
, *lifnext
;
1587 dlpn
= dlp
->dl_next
;
1589 nlifs
= dlp
->dl_nlifs
;
1590 for (; nlifs
> 0; lif
= lifnext
, nlifs
--) {
1591 lifnext
= lif
->lif_next
;
1592 if (!verify_lif(lif
)) {
1594 * User has manipulated the interface. Even
1595 * if we plumbed it, we must now disown it.
1597 lif
->lif_plumbed
= B_FALSE
;
1601 if (dlp
->dl_nlifs
== 0)
1606 * If there are leases left, then everything's ok.
1608 if (dsmp
->dsm_leases
!= NULL
) {
1609 release_smach(dsmp
);
1614 finished_smach(dsmp
, DHCP_IPC_E_INVIF
);
1615 release_smach(dsmp
);