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 * This module contains core functions for managing DHCP state machine
25 * instances.
26 */
27
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <search.h>
31 #include <string.h>
32 #include <ctype.h>
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>
38 #include <dhcpmsg.h>
39 #include <dhcpagent_util.h>
40 #include <dhcp_stable.h>
41 #include <dhcp_inittab.h>
42
315
316 static void
317 free_smach(dhcp_smach_t *dsmp)
318 {
319 dhcpmsg(MSG_DEBUG, "free_smach: freeing state machine %s",
320 dsmp->dsm_name);
321
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);
330 free(dsmp->dsm_cid);
331 free(dsmp->dsm_prl);
332 free(dsmp->dsm_pil);
333 free(dsmp->dsm_routers);
334 free(dsmp->dsm_reqhost);
335 free(dsmp);
336
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);
341 }
342 }
343
344 /*
345 * release_smach(): releases a hold previously acquired on a state machine.
346 * If the hold count reaches 0, the state machine is freed.
347 *
348 * input: dhcp_smach_t *: the state machine entry to release the hold on
349 * output: void
350 */
351
352 void
353 release_smach(dhcp_smach_t *dsmp)
354 {
1032 }
1033 dhcpmsg(MSG_WARNING, "get_smach_cid: cannot convert "
1034 "hex value for Client ID on %s", dsmp->dsm_name);
1035 } else {
1036 client_id_len = strlen(value);
1037 dsmp->dsm_cid = malloc(client_id_len);
1038 if (dsmp->dsm_cid == NULL)
1039 goto alloc_failure;
1040 dsmp->dsm_cidlen = client_id_len;
1041 (void) memcpy(dsmp->dsm_cid, value, client_id_len);
1042 return (DHCP_IPC_SUCCESS);
1043 }
1044 }
1045 no_specified_id:
1046
1047 /*
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.
1051 *
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.)
1057 */
1058 if (!pif->pif_isv6 && pif->pif_grifname[0] == '\0' &&
1059 strchr(dsmp->dsm_name, ':') == NULL) {
1060 if (pif->pif_hwtype == ARPHRD_IB) {
1061 /*
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).
1069 *
1070 * Type Client-Identifier
1071 * +-----+-----+-----+-----+-----+----....----+
1072 * | 0 | 0 (4 octets) | GID (16 octets)|
1073 * +-----+-----+-----+-----+-----+----....----+
1074 */
1075 dsmp->dsm_cidlen = 1 + 4 + 16;
1076 dsmp->dsm_cid = client_id = malloc(dsmp->dsm_cidlen);
1077 if (dsmp->dsm_cid == NULL)
1078 goto alloc_failure;
1079
1201 * input: dhcp_smach_t *: the state machine to reset
1202 * output: void
1203 */
1204
1205 void
1206 reset_smach(dhcp_smach_t *dsmp)
1207 {
1208 dsmp->dsm_dflags &= ~DHCP_IF_FAILED;
1209
1210 remove_default_routes(dsmp);
1211
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;
1217
1218 free(dsmp->dsm_reqhost);
1219 dsmp->dsm_reqhost = NULL;
1220
1221 cancel_smach_timers(dsmp);
1222
1223 (void) set_smach_state(dsmp, INIT);
1224 if (dsmp->dsm_isv6) {
1225 dsmp->dsm_server = ipv6_all_dhcp_relay_and_servers;
1226 } else {
1227 IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST),
1228 &dsmp->dsm_server);
1229 }
1230 dsmp->dsm_neg_hrtime = gethrtime();
1231 /*
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.
1235 */
1236 assert(dsmp->dsm_script_pid == -1);
1237 }
1238
1239 /*
1240 * refresh_smach(): refreshes a given state machine, as though awakened from
|
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 * This module contains core functions for managing DHCP state machine
26 * instances.
27 */
28
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <search.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netinet/arp.h>
38 #include <arpa/inet.h>
39 #include <dhcpmsg.h>
40 #include <dhcpagent_util.h>
41 #include <dhcp_stable.h>
42 #include <dhcp_inittab.h>
43
316
317 static void
318 free_smach(dhcp_smach_t *dsmp)
319 {
320 dhcpmsg(MSG_DEBUG, "free_smach: freeing state machine %s",
321 dsmp->dsm_name);
322
323 deprecate_leases(dsmp);
324 remove_lif(dsmp->dsm_lif);
325 release_lif(dsmp->dsm_lif);
326 free_pkt_list(&dsmp->dsm_recv_pkt_list);
327 if (dsmp->dsm_ack != dsmp->dsm_orig_ack)
328 free_pkt_entry(dsmp->dsm_orig_ack);
329 free_pkt_entry(dsmp->dsm_ack);
330 free(dsmp->dsm_send_pkt.pkt);
331 free(dsmp->dsm_cid);
332 free(dsmp->dsm_prl);
333 free(dsmp->dsm_pil);
334 free(dsmp->dsm_routers);
335 free(dsmp->dsm_reqhost);
336 free(dsmp->dsm_msg_reqhost);
337 free(dsmp->dsm_reqfqdn);
338 free(dsmp);
339
340 /* no big deal if this fails */
341 if (global_smach_count == 0 && inactivity_id == -1) {
342 inactivity_id = iu_schedule_timer(tq, DHCP_INACTIVITY_WAIT,
343 inactivity_shutdown, NULL);
344 }
345 }
346
347 /*
348 * release_smach(): releases a hold previously acquired on a state machine.
349 * If the hold count reaches 0, the state machine is freed.
350 *
351 * input: dhcp_smach_t *: the state machine entry to release the hold on
352 * output: void
353 */
354
355 void
356 release_smach(dhcp_smach_t *dsmp)
357 {
1035 }
1036 dhcpmsg(MSG_WARNING, "get_smach_cid: cannot convert "
1037 "hex value for Client ID on %s", dsmp->dsm_name);
1038 } else {
1039 client_id_len = strlen(value);
1040 dsmp->dsm_cid = malloc(client_id_len);
1041 if (dsmp->dsm_cid == NULL)
1042 goto alloc_failure;
1043 dsmp->dsm_cidlen = client_id_len;
1044 (void) memcpy(dsmp->dsm_cid, value, client_id_len);
1045 return (DHCP_IPC_SUCCESS);
1046 }
1047 }
1048 no_specified_id:
1049
1050 /*
1051 * There was either no user-specified Client ID value, or we were
1052 * unable to parse it. We need to determine if a Client ID is required
1053 * and, if so, generate one.
1054 *
1055 * If it's IPv4, not in an IPMP group, not a logical interface,
1056 * and a DHCP default for DF_V4_DEFAULT_IAID_DUID is not affirmative,
1057 * then we need to preserve backward-compatibility by avoiding
1058 * new-fangled DUID/IAID construction. (Note: even for IPMP test
1059 * addresses, we construct a DUID/IAID since we may renew a lease for
1060 * an IPMP test address on any functioning IP interface in the group.)
1061 */
1062 if (!pif->pif_isv6 && pif->pif_grifname[0] == '\0' &&
1063 strchr(dsmp->dsm_name, ':') == NULL &&
1064 !df_get_bool(dsmp->dsm_name, pif->pif_isv6,
1065 DF_V4_DEFAULT_IAID_DUID)) {
1066 if (pif->pif_hwtype == ARPHRD_IB) {
1067 /*
1068 * This comes from the DHCP over IPoIB specification.
1069 * In the absence of an user specified client id, IPoIB
1070 * automatically uses the required format, with the
1071 * unique 4 octet value set to 0 (since IPoIB driver
1072 * allows only a single interface on a port with a
1073 * specific GID to belong to an IP subnet (PSARC
1074 * 2001/289, FWARC 2002/702).
1075 *
1076 * Type Client-Identifier
1077 * +-----+-----+-----+-----+-----+----....----+
1078 * | 0 | 0 (4 octets) | GID (16 octets)|
1079 * +-----+-----+-----+-----+-----+----....----+
1080 */
1081 dsmp->dsm_cidlen = 1 + 4 + 16;
1082 dsmp->dsm_cid = client_id = malloc(dsmp->dsm_cidlen);
1083 if (dsmp->dsm_cid == NULL)
1084 goto alloc_failure;
1085
1207 * input: dhcp_smach_t *: the state machine to reset
1208 * output: void
1209 */
1210
1211 void
1212 reset_smach(dhcp_smach_t *dsmp)
1213 {
1214 dsmp->dsm_dflags &= ~DHCP_IF_FAILED;
1215
1216 remove_default_routes(dsmp);
1217
1218 free_pkt_list(&dsmp->dsm_recv_pkt_list);
1219 free_pkt_entry(dsmp->dsm_ack);
1220 if (dsmp->dsm_orig_ack != dsmp->dsm_ack)
1221 free_pkt_entry(dsmp->dsm_orig_ack);
1222 dsmp->dsm_ack = dsmp->dsm_orig_ack = NULL;
1223
1224 free(dsmp->dsm_reqhost);
1225 dsmp->dsm_reqhost = NULL;
1226
1227 /*
1228 * Do not reset dsm_msg_reqhost here. Unlike dsm_reqhost coming from
1229 * /etc/host.*, dsm_msg_reqhost comes externally, and it survives until
1230 * it is reset from another external message.
1231 */
1232
1233 free(dsmp->dsm_reqfqdn);
1234 dsmp->dsm_reqfqdn = NULL;
1235
1236 cancel_smach_timers(dsmp);
1237
1238 (void) set_smach_state(dsmp, INIT);
1239 if (dsmp->dsm_isv6) {
1240 dsmp->dsm_server = ipv6_all_dhcp_relay_and_servers;
1241 } else {
1242 IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST),
1243 &dsmp->dsm_server);
1244 }
1245 dsmp->dsm_neg_hrtime = gethrtime();
1246 /*
1247 * We must never get here with a script running, since it means we're
1248 * resetting an smach that is still in the middle of another state
1249 * transition with a pending dsm_script_callback.
1250 */
1251 assert(dsmp->dsm_script_pid == -1);
1252 }
1253
1254 /*
1255 * refresh_smach(): refreshes a given state machine, as though awakened from
|