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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 *
24 * SELECTING state of the client state machine.
25 */
26
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <time.h>
32 #include <limits.h>
33 #include <netinet/in.h>
34 #include <net/route.h>
35 #include <net/if.h>
36 #include <netinet/dhcp.h>
37 #include <netinet/udp.h>
38 #include <netinet/ip_var.h>
39 #include <netinet/udp_var.h>
40 #include <dhcpmsg.h>
41 #include <dhcp_hostconf.h>
42
43 #include "states.h"
44 #include "agent.h"
45 #include "util.h"
46 #include "interface.h"
47 #include "packet.h"
48 #include "defaults.h"
49
50 static stop_func_t stop_selecting;
51
52 /*
89 if (dsmp->dsm_start_timer == -1)
90 return (B_FALSE);
91
92 hold_smach(dsmp);
93 return (B_TRUE);
94 }
95
96 /*
97 * dhcp_selecting(): sends a DISCOVER and sets up reception of OFFERs for
98 * IPv4, or sends a Solicit and sets up reception of
99 * Advertisements for DHCPv6.
100 *
101 * input: dhcp_smach_t *: the state machine on which to send the DISCOVER
102 * output: void
103 */
104
105 void
106 dhcp_selecting(dhcp_smach_t *dsmp)
107 {
108 dhcp_pkt_t *dpkt;
109 const char *reqhost;
110 char hostfile[PATH_MAX + 1];
111
112 /*
113 * We first set up to collect OFFER/Advertise packets as they arrive.
114 * We then send out DISCOVER/Solicit probes. Then we wait a
115 * user-tunable number of seconds before seeing if OFFERs/
116 * Advertisements have come in response to our DISCOVER/Solicit. If
117 * none have come in, we continue to wait, sending out our DISCOVER/
118 * Solicit probes with exponential backoff. If no OFFER/Advertisement
119 * is ever received, we will wait forever (note that since we're
120 * event-driven though, we're still able to service other state
121 * machines).
122 *
123 * Note that we do an reset_smach() here because we may be landing in
124 * dhcp_selecting() as a result of restarting DHCP, so the state
125 * machine may not be fresh.
126 */
127
128 reset_smach(dsmp);
129 if (!set_smach_state(dsmp, SELECTING)) {
130 dhcpmsg(MSG_ERROR,
161 "Solicit packet");
162 return;
163 }
164
165 /* Add an IA_NA option for our controlling LIF */
166 d6in.d6in_iaid = htonl(dsmp->dsm_lif->lif_iaid);
167 d6in.d6in_t1 = htonl(0);
168 d6in.d6in_t2 = htonl(0);
169 (void) add_pkt_opt(dpkt, DHCPV6_OPT_IA_NA,
170 (dhcpv6_option_t *)&d6in + 1,
171 sizeof (d6in) - sizeof (dhcpv6_option_t));
172
173 /* Option Request option for desired information */
174 (void) add_pkt_prl(dpkt, dsmp);
175
176 /* Enable Rapid-Commit */
177 (void) add_pkt_opt(dpkt, DHCPV6_OPT_RAPID_COMMIT, NULL, 0);
178
179 /* xxx add Reconfigure Accept */
180
181 (void) send_pkt_v6(dsmp, dpkt, ipv6_all_dhcp_relay_and_servers,
182 stop_selecting, DHCPV6_SOL_TIMEOUT, DHCPV6_SOL_MAX_RT);
183 } else {
184 if ((dpkt = init_pkt(dsmp, DISCOVER)) == NULL) {
185 dhcpmsg(MSG_ERROR, "dhcp_selecting: unable to set up "
186 "DISCOVER packet");
187 return;
188 }
189
190 /*
191 * The max DHCP message size option is set to the interface
192 * MTU, minus the size of the UDP and IP headers.
193 */
194 (void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
195 htons(dsmp->dsm_lif->lif_max - sizeof (struct udpiphdr)));
196 (void) add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));
197
198 if (class_id_len != 0) {
199 (void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
200 class_id_len);
201 }
202 (void) add_pkt_prl(dpkt, dsmp);
203
204 if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6,
205 DF_REQUEST_HOSTNAME)) {
206 dhcpmsg(MSG_DEBUG,
207 "dhcp_selecting: DF_REQUEST_HOSTNAME");
208 (void) snprintf(hostfile, sizeof (hostfile),
209 "/etc/hostname.%s", dsmp->dsm_name);
210
211 if ((reqhost = iffile_to_hostname(hostfile)) != NULL) {
212 dhcpmsg(MSG_DEBUG, "dhcp_selecting: host %s",
213 reqhost);
214 dsmp->dsm_reqhost = strdup(reqhost);
215 if (dsmp->dsm_reqhost != NULL)
216 (void) add_pkt_opt(dpkt, CD_HOSTNAME,
217 dsmp->dsm_reqhost,
218 strlen(dsmp->dsm_reqhost));
219 else
220 dhcpmsg(MSG_WARNING,
221 "dhcp_selecting: cannot allocate "
222 "memory for host name option");
223 }
224 }
225 (void) add_pkt_opt(dpkt, CD_END, NULL, 0);
226
227 (void) send_pkt(dsmp, dpkt, htonl(INADDR_BROADCAST),
228 stop_selecting);
229 }
230 return;
231
232 failed:
233 (void) set_smach_state(dsmp, INIT);
234 dsmp->dsm_dflags |= DHCP_IF_FAILED;
235 ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
236 }
237
238 /*
239 * stop_selecting(): decides when to stop retransmitting DISCOVERs -- only when
240 * abandoning the state machine. For DHCPv6, this timer may
241 * go off before the offer wait timer. If so, then this is a
242 * good time to check for valid Advertisements, so cancel the
243 * timer and go check.
244 *
|
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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
24 *
25 * SELECTING state of the client state machine.
26 */
27
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <strings.h>
32 #include <time.h>
33 #include <netinet/in.h>
34 #include <net/route.h>
35 #include <net/if.h>
36 #include <netinet/dhcp.h>
37 #include <netinet/udp.h>
38 #include <netinet/ip_var.h>
39 #include <netinet/udp_var.h>
40 #include <dhcpmsg.h>
41 #include <dhcp_hostconf.h>
42
43 #include "states.h"
44 #include "agent.h"
45 #include "util.h"
46 #include "interface.h"
47 #include "packet.h"
48 #include "defaults.h"
49
50 static stop_func_t stop_selecting;
51
52 /*
89 if (dsmp->dsm_start_timer == -1)
90 return (B_FALSE);
91
92 hold_smach(dsmp);
93 return (B_TRUE);
94 }
95
96 /*
97 * dhcp_selecting(): sends a DISCOVER and sets up reception of OFFERs for
98 * IPv4, or sends a Solicit and sets up reception of
99 * Advertisements for DHCPv6.
100 *
101 * input: dhcp_smach_t *: the state machine on which to send the DISCOVER
102 * output: void
103 */
104
105 void
106 dhcp_selecting(dhcp_smach_t *dsmp)
107 {
108 dhcp_pkt_t *dpkt;
109
110 /*
111 * We first set up to collect OFFER/Advertise packets as they arrive.
112 * We then send out DISCOVER/Solicit probes. Then we wait a
113 * user-tunable number of seconds before seeing if OFFERs/
114 * Advertisements have come in response to our DISCOVER/Solicit. If
115 * none have come in, we continue to wait, sending out our DISCOVER/
116 * Solicit probes with exponential backoff. If no OFFER/Advertisement
117 * is ever received, we will wait forever (note that since we're
118 * event-driven though, we're still able to service other state
119 * machines).
120 *
121 * Note that we do an reset_smach() here because we may be landing in
122 * dhcp_selecting() as a result of restarting DHCP, so the state
123 * machine may not be fresh.
124 */
125
126 reset_smach(dsmp);
127 if (!set_smach_state(dsmp, SELECTING)) {
128 dhcpmsg(MSG_ERROR,
159 "Solicit packet");
160 return;
161 }
162
163 /* Add an IA_NA option for our controlling LIF */
164 d6in.d6in_iaid = htonl(dsmp->dsm_lif->lif_iaid);
165 d6in.d6in_t1 = htonl(0);
166 d6in.d6in_t2 = htonl(0);
167 (void) add_pkt_opt(dpkt, DHCPV6_OPT_IA_NA,
168 (dhcpv6_option_t *)&d6in + 1,
169 sizeof (d6in) - sizeof (dhcpv6_option_t));
170
171 /* Option Request option for desired information */
172 (void) add_pkt_prl(dpkt, dsmp);
173
174 /* Enable Rapid-Commit */
175 (void) add_pkt_opt(dpkt, DHCPV6_OPT_RAPID_COMMIT, NULL, 0);
176
177 /* xxx add Reconfigure Accept */
178
179 /* Add FQDN if configured */
180 (void) dhcp_add_fqdn_opt(dpkt, dsmp);
181
182 (void) send_pkt_v6(dsmp, dpkt, ipv6_all_dhcp_relay_and_servers,
183 stop_selecting, DHCPV6_SOL_TIMEOUT, DHCPV6_SOL_MAX_RT);
184 } else {
185 if ((dpkt = init_pkt(dsmp, DISCOVER)) == NULL) {
186 dhcpmsg(MSG_ERROR, "dhcp_selecting: unable to set up "
187 "DISCOVER packet");
188 return;
189 }
190
191 /*
192 * The max DHCP message size option is set to the interface
193 * MTU, minus the size of the UDP and IP headers.
194 */
195 (void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
196 htons(dsmp->dsm_lif->lif_max - sizeof (struct udpiphdr)));
197 (void) add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));
198
199 if (class_id_len != 0) {
200 (void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
201 class_id_len);
202 }
203 (void) add_pkt_prl(dpkt, dsmp);
204
205 if (dhcp_add_fqdn_opt(dpkt, dsmp) != 0)
206 (void) dhcp_add_hostname_opt(dpkt, dsmp);
207
208 (void) add_pkt_opt(dpkt, CD_END, NULL, 0);
209
210 (void) send_pkt(dsmp, dpkt, htonl(INADDR_BROADCAST),
211 stop_selecting);
212 }
213 return;
214
215 failed:
216 (void) set_smach_state(dsmp, INIT);
217 dsmp->dsm_dflags |= DHCP_IF_FAILED;
218 ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
219 }
220
221 /*
222 * stop_selecting(): decides when to stop retransmitting DISCOVERs -- only when
223 * abandoning the state machine. For DHCPv6, this timer may
224 * go off before the offer wait timer. If so, then this is a
225 * good time to check for valid Advertisements, so cancel the
226 * timer and go check.
227 *
|