Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.


   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