Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
+++ new/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
23 24 *
24 25 * SELECTING state of the client state machine.
25 26 */
26 27
27 28 #include <sys/types.h>
28 29 #include <stdio.h>
29 30 #include <stdlib.h>
30 31 #include <strings.h>
31 32 #include <time.h>
32 -#include <limits.h>
33 33 #include <netinet/in.h>
34 34 #include <net/route.h>
35 35 #include <net/if.h>
36 36 #include <netinet/dhcp.h>
37 37 #include <netinet/udp.h>
38 38 #include <netinet/ip_var.h>
39 39 #include <netinet/udp_var.h>
40 40 #include <dhcpmsg.h>
41 41 #include <dhcp_hostconf.h>
42 42
43 43 #include "states.h"
44 44 #include "agent.h"
45 45 #include "util.h"
46 46 #include "interface.h"
47 47 #include "packet.h"
48 48 #include "defaults.h"
49 49
50 50 static stop_func_t stop_selecting;
51 51
52 52 /*
53 53 * dhcp_start(): starts DHCP on a state machine
54 54 *
55 55 * input: iu_tq_t *: unused
56 56 * void *: the state machine on which to start DHCP
57 57 * output: void
58 58 */
59 59
60 60 /* ARGSUSED */
61 61 static void
62 62 dhcp_start(iu_tq_t *tqp, void *arg)
63 63 {
64 64 dhcp_smach_t *dsmp = arg;
65 65
66 66 dsmp->dsm_start_timer = -1;
67 67 (void) set_smach_state(dsmp, INIT);
68 68 if (verify_smach(dsmp)) {
69 69 dhcpmsg(MSG_VERBOSE, "starting DHCP on %s", dsmp->dsm_name);
70 70 dhcp_selecting(dsmp);
71 71 }
72 72 }
73 73
74 74 /*
75 75 * set_start_timer(): sets a random timer to start a DHCP state machine
76 76 *
77 77 * input: dhcp_smach_t *: the state machine on which to start DHCP
78 78 * output: boolean_t: B_TRUE if a timer is now running
79 79 */
80 80
81 81 boolean_t
82 82 set_start_timer(dhcp_smach_t *dsmp)
83 83 {
84 84 if (dsmp->dsm_start_timer != -1)
85 85 return (B_TRUE);
86 86
87 87 dsmp->dsm_start_timer = iu_schedule_timer_ms(tq,
88 88 lrand48() % DHCP_SELECT_WAIT, dhcp_start, dsmp);
89 89 if (dsmp->dsm_start_timer == -1)
90 90 return (B_FALSE);
91 91
92 92 hold_smach(dsmp);
93 93 return (B_TRUE);
94 94 }
95 95
96 96 /*
97 97 * dhcp_selecting(): sends a DISCOVER and sets up reception of OFFERs for
98 98 * IPv4, or sends a Solicit and sets up reception of
|
↓ open down ↓ |
56 lines elided |
↑ open up ↑ |
99 99 * Advertisements for DHCPv6.
100 100 *
101 101 * input: dhcp_smach_t *: the state machine on which to send the DISCOVER
102 102 * output: void
103 103 */
104 104
105 105 void
106 106 dhcp_selecting(dhcp_smach_t *dsmp)
107 107 {
108 108 dhcp_pkt_t *dpkt;
109 - const char *reqhost;
110 - char hostfile[PATH_MAX + 1];
111 109
112 110 /*
113 111 * We first set up to collect OFFER/Advertise packets as they arrive.
114 112 * We then send out DISCOVER/Solicit probes. Then we wait a
115 113 * user-tunable number of seconds before seeing if OFFERs/
116 114 * Advertisements have come in response to our DISCOVER/Solicit. If
117 115 * none have come in, we continue to wait, sending out our DISCOVER/
118 116 * Solicit probes with exponential backoff. If no OFFER/Advertisement
119 117 * is ever received, we will wait forever (note that since we're
120 118 * event-driven though, we're still able to service other state
121 119 * machines).
122 120 *
123 121 * Note that we do an reset_smach() here because we may be landing in
124 122 * dhcp_selecting() as a result of restarting DHCP, so the state
125 123 * machine may not be fresh.
126 124 */
127 125
128 126 reset_smach(dsmp);
129 127 if (!set_smach_state(dsmp, SELECTING)) {
130 128 dhcpmsg(MSG_ERROR,
131 129 "dhcp_selecting: cannot switch to SELECTING state; "
132 130 "reverting to INIT on %s", dsmp->dsm_name);
133 131 goto failed;
134 132
135 133 }
136 134
137 135 /* Remove the stale hostconf file, if there is any */
138 136 (void) remove_hostconf(dsmp->dsm_name, dsmp->dsm_isv6);
139 137
140 138 dsmp->dsm_offer_timer = iu_schedule_timer(tq,
141 139 dsmp->dsm_offer_wait, dhcp_requesting, dsmp);
142 140 if (dsmp->dsm_offer_timer == -1) {
143 141 dhcpmsg(MSG_ERROR, "dhcp_selecting: cannot schedule to read "
144 142 "%s packets", dsmp->dsm_isv6 ? "Advertise" : "OFFER");
145 143 goto failed;
146 144 }
147 145
148 146 hold_smach(dsmp);
149 147
150 148 /*
151 149 * Assemble and send the DHCPDISCOVER or Solicit message.
152 150 *
153 151 * If this fails, we'll wait for the select timer to go off
154 152 * before trying again.
155 153 */
156 154 if (dsmp->dsm_isv6) {
157 155 dhcpv6_ia_na_t d6in;
158 156
159 157 if ((dpkt = init_pkt(dsmp, DHCPV6_MSG_SOLICIT)) == NULL) {
160 158 dhcpmsg(MSG_ERROR, "dhcp_selecting: unable to set up "
161 159 "Solicit packet");
162 160 return;
163 161 }
164 162
165 163 /* Add an IA_NA option for our controlling LIF */
166 164 d6in.d6in_iaid = htonl(dsmp->dsm_lif->lif_iaid);
167 165 d6in.d6in_t1 = htonl(0);
168 166 d6in.d6in_t2 = htonl(0);
169 167 (void) add_pkt_opt(dpkt, DHCPV6_OPT_IA_NA,
170 168 (dhcpv6_option_t *)&d6in + 1,
|
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
171 169 sizeof (d6in) - sizeof (dhcpv6_option_t));
172 170
173 171 /* Option Request option for desired information */
174 172 (void) add_pkt_prl(dpkt, dsmp);
175 173
176 174 /* Enable Rapid-Commit */
177 175 (void) add_pkt_opt(dpkt, DHCPV6_OPT_RAPID_COMMIT, NULL, 0);
178 176
179 177 /* xxx add Reconfigure Accept */
180 178
179 + /* Add FQDN if configured */
180 + (void) dhcp_add_fqdn_opt(dpkt, dsmp);
181 +
181 182 (void) send_pkt_v6(dsmp, dpkt, ipv6_all_dhcp_relay_and_servers,
182 183 stop_selecting, DHCPV6_SOL_TIMEOUT, DHCPV6_SOL_MAX_RT);
183 184 } else {
184 185 if ((dpkt = init_pkt(dsmp, DISCOVER)) == NULL) {
185 186 dhcpmsg(MSG_ERROR, "dhcp_selecting: unable to set up "
186 187 "DISCOVER packet");
187 188 return;
188 189 }
189 190
190 191 /*
191 192 * The max DHCP message size option is set to the interface
192 193 * MTU, minus the size of the UDP and IP headers.
193 194 */
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
194 195 (void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
195 196 htons(dsmp->dsm_lif->lif_max - sizeof (struct udpiphdr)));
196 197 (void) add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));
197 198
198 199 if (class_id_len != 0) {
199 200 (void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
200 201 class_id_len);
201 202 }
202 203 (void) add_pkt_prl(dpkt, dsmp);
203 204
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);
205 + if (dhcp_add_fqdn_opt(dpkt, dsmp) != 0)
206 + (void) dhcp_add_hostname_opt(dpkt, dsmp);
210 207
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 208 (void) add_pkt_opt(dpkt, CD_END, NULL, 0);
226 209
227 210 (void) send_pkt(dsmp, dpkt, htonl(INADDR_BROADCAST),
228 211 stop_selecting);
229 212 }
230 213 return;
231 214
232 215 failed:
233 216 (void) set_smach_state(dsmp, INIT);
234 217 dsmp->dsm_dflags |= DHCP_IF_FAILED;
235 218 ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
236 219 }
237 220
238 221 /*
239 222 * stop_selecting(): decides when to stop retransmitting DISCOVERs -- only when
240 223 * abandoning the state machine. For DHCPv6, this timer may
241 224 * go off before the offer wait timer. If so, then this is a
242 225 * good time to check for valid Advertisements, so cancel the
243 226 * timer and go check.
244 227 *
245 228 * input: dhcp_smach_t *: the state machine DISCOVERs are being sent on
246 229 * unsigned int: the number of DISCOVERs sent so far
247 230 * output: boolean_t: B_TRUE if retransmissions should stop
248 231 */
249 232
250 233 /* ARGSUSED1 */
251 234 static boolean_t
252 235 stop_selecting(dhcp_smach_t *dsmp, unsigned int n_discovers)
253 236 {
254 237 /*
255 238 * If we're using v4 and the underlying LIF we're trying to configure
256 239 * has been touched by the user, then bail out.
257 240 */
258 241 if (!dsmp->dsm_isv6 && !verify_lif(dsmp->dsm_lif)) {
259 242 finished_smach(dsmp, DHCP_IPC_E_UNKIF);
260 243 return (B_TRUE);
261 244 }
262 245
263 246 if (dsmp->dsm_recv_pkt_list != NULL) {
264 247 dhcp_requesting(NULL, dsmp);
265 248 if (dsmp->dsm_state != SELECTING)
266 249 return (B_TRUE);
267 250 }
268 251 return (B_FALSE);
269 252 }
|
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX