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 * DECLINE/RELEASE configuration functionality for the DHCP client.
27 #include <sys/types.h>
30 #include <netinet/in.h>
32 #include <netinet/dhcp.h>
33 #include <netinet/dhcp6.h>
35 #include <dhcp_hostconf.h>
36 #include <dhcpagent_util.h>
40 #include "interface.h"
43 static boolean_t
stop_release_decline(dhcp_smach_t
*, unsigned int);
46 * send_declines(): sends a DECLINE message (broadcasted for IPv4) to the
47 * server to indicate a problem with the offered addresses.
48 * The failing addresses are removed from the leases.
50 * input: dhcp_smach_t *: the state machine sending DECLINE
55 send_declines(dhcp_smach_t
*dsmp
)
58 dhcp_lease_t
*dlp
, *dlpn
;
60 dhcp_lif_t
*lif
, *lifn
;
64 * Create an empty DECLINE message. We'll stuff the information into
65 * this message as we find it.
68 if ((dpkt
= init_pkt(dsmp
, DHCPV6_MSG_DECLINE
)) == NULL
)
70 (void) add_pkt_opt(dpkt
, DHCPV6_OPT_SERVERID
,
71 dsmp
->dsm_serverid
, dsmp
->dsm_serveridlen
);
76 * If this ack is from BOOTP, then there's no way to send a
77 * decline. Note that since we haven't bound yet, we can't
78 * just check the BOOTP flag.
80 if (dsmp
->dsm_ack
->opts
[CD_DHCP_TYPE
] == NULL
)
83 if ((dpkt
= init_pkt(dsmp
, DECLINE
)) == NULL
)
85 IN6_V4MAPPED_TO_IPADDR(&dsmp
->dsm_server
, serverip
);
86 (void) add_pkt_opt32(dpkt
, CD_SERVER_ID
, serverip
);
90 * Loop over the leases, looking for ones with now-broken LIFs. Add
91 * each one found to the DECLINE message, and remove it from the list.
92 * Also remove any completely declined leases.
95 for (dlp
= dsmp
->dsm_leases
; dlp
!= NULL
; dlp
= dlpn
) {
98 for (nlifs
= dlp
->dl_nlifs
; nlifs
> 0; nlifs
--, lif
= lifn
) {
100 if (lif
->lif_declined
!= NULL
) {
101 (void) add_pkt_lif(dpkt
, lif
,
102 DHCPV6_STAT_UNSPECFAIL
, lif
->lif_declined
);
107 if (dlp
->dl_nlifs
== 0)
114 (void) set_smach_state(dsmp
, DECLINING
);
116 if (dsmp
->dsm_isv6
) {
117 (void) send_pkt_v6(dsmp
, dpkt
, dsmp
->dsm_server
,
118 stop_release_decline
, DHCPV6_DEC_TIMEOUT
, 0);
120 (void) add_pkt_opt(dpkt
, CD_END
, NULL
, 0);
122 (void) send_pkt(dsmp
, dpkt
, htonl(INADDR_BROADCAST
), NULL
);
127 * dhcp_release(): sends a RELEASE message to a DHCP server and removes
128 * the all interfaces for the given state machine from DHCP
129 * control. Called back by script handler.
131 * input: dhcp_smach_t *: the state machine to send the RELEASE on and remove
132 * void *: an optional text explanation to send with the message
133 * output: int: 1 on success, 0 on failure
137 dhcp_release(dhcp_smach_t
*dsmp
, void *arg
)
139 const char *msg
= arg
;
146 if ((dsmp
->dsm_dflags
& DHCP_IF_BOOTP
) ||
147 !check_cmd_allowed(dsmp
->dsm_state
, DHCP_RELEASE
)) {
148 ipc_action_finish(dsmp
, DHCP_IPC_E_INT
);
152 dhcpmsg(MSG_INFO
, "releasing leases for state machine %s",
154 (void) set_smach_state(dsmp
, RELEASING
);
156 (void) remove_hostconf(dsmp
->dsm_name
, dsmp
->dsm_isv6
);
158 if (dsmp
->dsm_isv6
) {
159 dpkt
= init_pkt(dsmp
, DHCPV6_MSG_RELEASE
);
160 (void) add_pkt_opt(dpkt
, DHCPV6_OPT_SERVERID
,
161 dsmp
->dsm_serverid
, dsmp
->dsm_serveridlen
);
163 for (dlp
= dsmp
->dsm_leases
; dlp
!= NULL
; dlp
= dlp
->dl_next
) {
165 for (nlifs
= dlp
->dl_nlifs
; nlifs
> 0;
166 nlifs
--, lif
= lif
->lif_next
) {
167 (void) add_pkt_lif(dpkt
, lif
,
168 DHCPV6_STAT_SUCCESS
, NULL
);
173 * Must kill off the leases before attempting to tell the
176 deprecate_leases(dsmp
);
179 * For DHCPv6, this is a transaction, rather than just a
180 * one-shot message. When this transaction is done, we'll
181 * finish the invoking async operation.
183 (void) send_pkt_v6(dsmp
, dpkt
, dsmp
->dsm_server
,
184 stop_release_decline
, DHCPV6_REL_TIMEOUT
, 0);
186 if ((dlp
= dsmp
->dsm_leases
) != NULL
&& dlp
->dl_nlifs
> 0) {
187 dpkt
= init_pkt(dsmp
, RELEASE
);
189 (void) add_pkt_opt(dpkt
, CD_MESSAGE
, msg
,
193 (void) add_pkt_lif(dpkt
, dlp
->dl_lifs
, 0, NULL
);
195 IN6_V4MAPPED_TO_IPADDR(&dsmp
->dsm_server
, serverip
);
196 (void) add_pkt_opt32(dpkt
, CD_SERVER_ID
, serverip
);
197 (void) add_pkt_opt(dpkt
, CD_END
, NULL
, 0);
198 (void) send_pkt(dsmp
, dpkt
, serverip
, NULL
);
202 * XXX this totally sucks, but since udp is best-effort,
203 * without this delay, there's a good chance that the packet
204 * that we just enqueued for sending will get pitched
205 * when we canonize the interface through remove_smach.
209 deprecate_leases(dsmp
);
211 finished_smach(dsmp
, DHCP_IPC_SUCCESS
);
217 * dhcp_drop(): drops the interface from DHCP control; callback from script
220 * input: dhcp_smach_t *: the state machine dropping leases
222 * output: int: always 1
227 dhcp_drop(dhcp_smach_t
*dsmp
, void *arg
)
229 dhcpmsg(MSG_INFO
, "dropping leases for state machine %s",
232 if (dsmp
->dsm_state
== PRE_BOUND
|| dsmp
->dsm_state
== BOUND
||
233 dsmp
->dsm_state
== RENEWING
|| dsmp
->dsm_state
== REBINDING
) {
234 if (dsmp
->dsm_dflags
& DHCP_IF_BOOTP
) {
236 "used bootp; not writing lease file for %s",
239 write_lease_to_hostconf(dsmp
);
242 dhcpmsg(MSG_DEBUG
, "%s in state %s; not saving lease",
243 dsmp
->dsm_name
, dhcp_state_to_string(dsmp
->dsm_state
));
245 deprecate_leases(dsmp
);
246 finished_smach(dsmp
, DHCP_IPC_SUCCESS
);
251 * stop_release_decline(): decides when to stop retransmitting RELEASE/DECLINE
252 * messages for DHCPv6. When we stop, if there are no
253 * more leases left, then restart the state machine.
255 * input: dhcp_smach_t *: the state machine messages are being sent from
256 * unsigned int: the number of messages sent so far
257 * output: boolean_t: B_TRUE if retransmissions should stop
261 stop_release_decline(dhcp_smach_t
*dsmp
, unsigned int n_requests
)
263 if (dsmp
->dsm_state
== RELEASING
) {
264 if (n_requests
>= DHCPV6_REL_MAX_RC
) {
265 dhcpmsg(MSG_INFO
, "no Reply to Release, finishing "
266 "transaction on %s", dsmp
->dsm_name
);
267 finished_smach(dsmp
, DHCP_IPC_SUCCESS
);
273 if (n_requests
>= DHCPV6_DEC_MAX_RC
) {
274 dhcpmsg(MSG_INFO
, "no Reply to Decline on %s",
277 if (dsmp
->dsm_leases
== NULL
) {
278 dhcpmsg(MSG_VERBOSE
, "stop_release_decline: "
279 "%s has no leases left", dsmp
->dsm_name
);