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/init_reboot.c
+++ new/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.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 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
24 25 *
25 26 * INIT_REBOOT state of the DHCP client state machine.
26 27 */
27 28
28 29 #include <sys/types.h>
29 30 #include <stdio.h>
30 -#include <limits.h>
31 31 #include <sys/socket.h>
32 32 #include <netinet/in.h>
33 33 #include <netinet/dhcp.h>
34 34 #include <netinet/udp.h>
35 35 #include <netinet/ip_var.h>
36 36 #include <netinet/udp_var.h>
37 37 #include <dhcpmsg.h>
38 38 #include <string.h>
39 39
40 40 #include "agent.h"
41 41 #include "packet.h"
42 42 #include "states.h"
43 43 #include "util.h"
44 44 #include "interface.h"
45 45 #include "defaults.h"
46 46
47 47 static stop_func_t stop_init_reboot;
48 48
49 49 /*
50 50 * dhcp_init_reboot_v4(): attempts to reuse a cached configuration for a state
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
51 51 * machine.
52 52 *
53 53 * input: dhcp_smach_t *: the state machine to examine for reuse
54 54 * output: void
55 55 */
56 56
57 57 static void
58 58 dhcp_init_reboot_v4(dhcp_smach_t *dsmp)
59 59 {
60 60 dhcp_pkt_t *dpkt;
61 - const char *reqhost;
62 - char hostfile[PATH_MAX + 1];
63 61
64 62 /*
65 63 * assemble DHCPREQUEST message. The max dhcp message size
66 64 * option is set to the interface max, minus the size of the udp and
67 65 * ip headers.
68 66 */
69 67
70 68 dpkt = init_pkt(dsmp, REQUEST);
71 69 (void) add_pkt_opt32(dpkt, CD_REQUESTED_IP_ADDR,
72 70 dsmp->dsm_ack->pkt->yiaddr.s_addr);
73 71
74 72 (void) add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));
75 73 (void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
76 74 htons(dsmp->dsm_lif->lif_pif->pif_max - sizeof (struct udpiphdr)));
77 75
78 76 if (class_id_len != 0)
79 77 (void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
80 78 (void) add_pkt_prl(dpkt, dsmp);
81 79
82 - /*
83 - * Set CD_HOSTNAME option if REQUEST_HOSTNAME is set and a hostname
84 - * is found in /etc/hostname.<ifname>
85 - */
86 - if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6, DF_REQUEST_HOSTNAME)) {
87 - (void) snprintf(hostfile, sizeof (hostfile), "/etc/hostname.%s",
88 - dsmp->dsm_name);
80 + if (dhcp_add_fqdn_opt(dpkt, dsmp) != 0)
81 + (void) dhcp_add_hostname_opt(dpkt, dsmp);
89 82
90 - if ((reqhost = iffile_to_hostname(hostfile)) != NULL) {
91 - dhcpmsg(MSG_DEBUG, "dhcp_selecting: host %s", reqhost);
92 - if ((dsmp->dsm_reqhost = strdup(reqhost)) != NULL)
93 - (void) add_pkt_opt(dpkt, CD_HOSTNAME,
94 - dsmp->dsm_reqhost,
95 - strlen(dsmp->dsm_reqhost));
96 - else
97 - dhcpmsg(MSG_WARNING, "dhcp_selecting: cannot"
98 - " allocate memory for host name option");
99 - } else {
100 - dhcpmsg(MSG_DEBUG,
101 - "dhcp_selecting: no hostname for %s",
102 - dsmp->dsm_name);
103 - }
104 - }
105 -
106 83 (void) add_pkt_opt(dpkt, CD_END, NULL, 0);
107 84
108 85 (void) send_pkt(dsmp, dpkt, htonl(INADDR_BROADCAST), stop_init_reboot);
109 86 }
110 87
111 88
112 89 /*
113 90 * dhcp_init_reboot_v6(): attempts to reuse a cached configuration for a state
114 91 * machine. Create a Confirm message and multicast it
115 92 * out.
116 93 *
117 94 * input: dhcp_smach_t *: the state machine to examine for reuse
118 95 * output: void
119 96 */
120 97
121 98 static void
122 99 dhcp_init_reboot_v6(dhcp_smach_t *dsmp)
123 100 {
124 101 dhcp_pkt_t *dpkt;
125 102 dhcpv6_option_t *d6o, *d6so, *popt;
126 103 uint_t olen, solen;
127 104 dhcpv6_ia_na_t d6in;
128 105 dhcpv6_iaaddr_t d6ia;
129 106 char *obase;
130 107
131 108 /*
132 109 * Assemble a Confirm message based on the current ack.
133 110 */
134 111
135 112 dpkt = init_pkt(dsmp, DHCPV6_MSG_CONFIRM);
136 113
137 114 /*
138 115 * Loop over and copy IA_NAs and IAADDRs we have in our last ack. This
139 116 * is what we'll be requesting.
140 117 */
141 118 d6o = NULL;
142 119 while ((d6o = dhcpv6_pkt_option(dsmp->dsm_ack, d6o, DHCPV6_OPT_IA_NA,
143 120 &olen)) != NULL) {
144 121
145 122 /*
146 123 * Copy in IA_NA option from the ack. Note that we use zero
147 124 * for all timers in accordance with RFC 3315. (It would make
148 125 * some sense to say what we think the current timers are as
149 126 * a hint to the server, but the RFC doesn't agree.)
150 127 */
151 128 if (olen < sizeof (dhcpv6_ia_na_t))
152 129 continue;
153 130 (void) memcpy(&d6in, d6o, sizeof (d6in));
154 131 d6in.d6in_t1 = 0;
155 132 d6in.d6in_t2 = 0;
156 133 popt = add_pkt_opt(dpkt, DHCPV6_OPT_IA_NA,
157 134 (char *)&d6in + sizeof (*d6o),
158 135 sizeof (d6in) - sizeof (*d6o));
159 136 if (popt == NULL)
160 137 goto failure;
161 138
162 139 /*
163 140 * Now loop over the IAADDR suboptions and add those.
164 141 */
165 142 obase = (char *)d6o + sizeof (dhcpv6_ia_na_t);
166 143 olen -= sizeof (dhcpv6_ia_na_t);
167 144 d6so = NULL;
168 145 while ((d6so = dhcpv6_find_option(obase, olen, d6so,
169 146 DHCPV6_OPT_IAADDR, &solen)) != NULL) {
170 147 if (solen < sizeof (dhcpv6_iaaddr_t))
171 148 continue;
172 149 (void) memcpy(&d6ia, d6so, sizeof (d6ia));
173 150 d6ia.d6ia_preflife = 0;
174 151 d6ia.d6ia_vallife = 0;
|
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
175 152 if (add_pkt_subopt(dpkt, popt, DHCPV6_OPT_IAADDR,
176 153 (char *)&d6ia + sizeof (*d6so),
177 154 sizeof (d6ia) - sizeof (*d6so)) == NULL)
178 155 goto failure;
179 156 }
180 157 }
181 158
182 159 /* Add required Option Request option */
183 160 (void) add_pkt_prl(dpkt, dsmp);
184 161
162 + /* Add FQDN if configured */
163 + (void) dhcp_add_fqdn_opt(dpkt, dsmp);
164 +
185 165 (void) send_pkt_v6(dsmp, dpkt, ipv6_all_dhcp_relay_and_servers,
186 166 stop_init_reboot, DHCPV6_CNF_TIMEOUT, DHCPV6_CNF_MAX_RT);
187 167
188 168 return;
189 169
190 170 failure:
191 171 if (!set_start_timer(dsmp))
192 172 dhcp_selecting(dsmp);
193 173 }
194 174
195 175 /*
196 176 * dhcp_init_reboot(): attempts to reuse a cached configuration for a state
197 177 * machine.
198 178 *
199 179 * input: dhcp_smach_t *: the state machine to examine for reuse
200 180 * output: void
201 181 */
202 182
203 183 void
204 184 dhcp_init_reboot(dhcp_smach_t *dsmp)
205 185 {
206 186 dhcpmsg(MSG_VERBOSE, "%s has cached configuration - entering "
207 187 "INIT_REBOOT", dsmp->dsm_name);
208 188
209 189 if (!set_smach_state(dsmp, INIT_REBOOT)) {
210 190 dhcpmsg(MSG_ERROR, "dhcp_init_reboot: cannot register to "
211 191 "collect ACK/NAK packets, reverting to INIT on %s",
212 192 dsmp->dsm_name);
213 193
214 194 dsmp->dsm_dflags |= DHCP_IF_FAILED;
215 195 (void) set_smach_state(dsmp, INIT);
216 196 ipc_action_finish(dsmp, DHCP_IPC_E_MEMORY);
217 197 return;
218 198 }
219 199
220 200 if (dsmp->dsm_isv6)
221 201 dhcp_init_reboot_v6(dsmp);
222 202 else
223 203 dhcp_init_reboot_v4(dsmp);
224 204 }
225 205
226 206 /*
227 207 * stop_init_reboot(): decides when to stop retransmitting REQUESTs
228 208 *
229 209 * input: dhcp_smach_t *: the state machine sending the REQUESTs
230 210 * unsigned int: the number of REQUESTs sent so far
231 211 * output: boolean_t: B_TRUE if retransmissions should stop
232 212 */
233 213
234 214 static boolean_t
235 215 stop_init_reboot(dhcp_smach_t *dsmp, unsigned int n_requests)
236 216 {
237 217 if (dsmp->dsm_isv6) {
238 218 uint_t nowabs, maxabs;
239 219
240 220 nowabs = NSEC2MSEC(gethrtime());
241 221 maxabs = NSEC2MSEC(dsmp->dsm_neg_hrtime) + DHCPV6_CNF_MAX_RD;
242 222 if (nowabs < maxabs) {
243 223 /* Cap the timer based on the maximum */
244 224 if (nowabs + dsmp->dsm_send_timeout > maxabs)
245 225 dsmp->dsm_send_timeout = maxabs - nowabs;
246 226 return (B_FALSE);
247 227 }
248 228 } else {
249 229 if (n_requests < DHCP_MAX_REQUESTS)
250 230 return (B_FALSE);
251 231 }
252 232
253 233 if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6,
254 234 DF_VERIFIED_LEASE_ONLY)) {
255 235 dhcpmsg(MSG_INFO,
256 236 "unable to verify existing lease on %s; restarting",
257 237 dsmp->dsm_name);
258 238 dhcp_selecting(dsmp);
259 239 return (B_TRUE);
260 240 }
261 241
262 242 if (dsmp->dsm_isv6) {
263 243 dhcpmsg(MSG_INFO, "no Reply to Confirm, using remainder of "
264 244 "existing lease on %s", dsmp->dsm_name);
265 245 } else {
266 246 dhcpmsg(MSG_INFO, "no ACK/NAK to INIT_REBOOT REQUEST, "
267 247 "using remainder of existing lease on %s", dsmp->dsm_name);
268 248 }
269 249
270 250 /*
271 251 * We already stuck our old ack in dsmp->dsm_ack and relativized the
272 252 * packet times, so we can just pretend that the server sent it to us
273 253 * and move to bound. If that fails, fall back to selecting.
274 254 */
275 255
276 256 if (dhcp_bound(dsmp, NULL)) {
277 257 if (dsmp->dsm_isv6) {
278 258 if (!save_server_id(dsmp, dsmp->dsm_ack))
279 259 goto failure;
280 260 server_unicast_option(dsmp, dsmp->dsm_ack);
281 261 }
282 262 } else {
283 263 failure:
284 264 dhcpmsg(MSG_INFO, "unable to use saved lease on %s; restarting",
285 265 dsmp->dsm_name);
286 266 dhcp_selecting(dsmp);
287 267 }
288 268
289 269 return (B_TRUE);
290 270 }
|
↓ open down ↓ |
96 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX