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 
  25 #include <sys/types.h>
  26 #include <stdlib.h>
  27 #include <assert.h>
  28 #include <errno.h>
  29 #include <locale.h>
  30 #include <string.h>
  31 #include <unistd.h>
  32 #include <signal.h>
  33 #include <stdio.h>
  34 #include <stdio_ext.h>
  35 #include <dhcp_hostconf.h>
  36 #include <dhcpagent_ipc.h>
  37 #include <dhcpagent_util.h>
  38 #include <dhcpmsg.h>


  39 #include <netinet/dhcp.h>
  40 #include <net/route.h>
  41 #include <sys/sockio.h>
  42 #include <sys/stat.h>
  43 #include <stropts.h>
  44 #include <fcntl.h>
  45 #include <sys/scsi/adapters/iscsi_if.h>
  46 
  47 #include "async.h"
  48 #include "agent.h"
  49 #include "script_handler.h"
  50 #include "util.h"
  51 #include "class_id.h"
  52 #include "states.h"
  53 #include "packet.h"
  54 #include "interface.h"
  55 #include "defaults.h"
  56 
  57 #ifndef TEXT_DOMAIN
  58 #define TEXT_DOMAIN     "SYS_TEST"
  59 #endif
  60 
  61 iu_timer_id_t           inactivity_id;
  62 int                     class_id_len = 0;
  63 char                    *class_id;
  64 iu_eh_t                 *eh;
  65 iu_tq_t                 *tq;
  66 pid_t                   grandparent;
  67 int                     rtsock_fd;
  68 
  69 static boolean_t        shutdown_started = B_FALSE;
  70 static boolean_t        do_adopt = B_FALSE;
  71 static unsigned int     debug_level = 0;
  72 static iu_eh_callback_t accept_event, ipc_event, rtsock_event;




  73 
  74 /*
  75  * The ipc_cmd_allowed[] table indicates which IPC commands are allowed in
  76  * which states; a non-zero value indicates the command is permitted.
  77  *
  78  * START is permitted if the state machine is fresh, or if we are in the
  79  * process of trying to obtain a lease (as a convenience to save the
  80  * administrator from having to do an explicit DROP).  EXTEND, RELEASE, and
  81  * GET_TAG require a lease to be obtained in order to make sense.  INFORM is
  82  * permitted if the interface is fresh or has an INFORM in progress or
  83  * previously done on it -- otherwise a DROP or RELEASE is first required.
  84  * PING and STATUS always make sense and thus are always permitted, as is DROP
  85  * in order to permit the administrator to always bail out.
  86  */
  87 static int ipc_cmd_allowed[DHCP_NSTATES][DHCP_NIPC] = {
  88         /*                        D  E  P  R  S  S  I  G */
  89         /*                        R  X  I  E  T  T  N  E */
  90         /*                        O  T  N  L  A  A  F  T */
  91         /*                        P  E  G  E  R  T  O  _ */
  92         /*                        .  N  .  A  T  U  R  T */


 737         switch (iap->ia_cmd) {
 738 
 739         case DHCP_DROP:
 740                 if (dsmp->dsm_droprelease)
 741                         break;
 742                 dsmp->dsm_droprelease = B_TRUE;
 743 
 744                 /*
 745                  * Ensure that a timer associated with the existing state
 746                  * doesn't pop while we're waiting for the script to complete.
 747                  * (If so, chaos can result -- e.g., a timer causes us to end
 748                  * up in dhcp_selecting() would start acquiring a new lease on
 749                  * dsmp while our DHCP_DROP dismantling is ongoing.)
 750                  */
 751                 cancel_smach_timers(dsmp);
 752                 (void) script_start(dsmp, isv6 ? EVENT_DROP6 : EVENT_DROP,
 753                     dhcp_drop, NULL, NULL);
 754                 break;          /* not an immediate function */
 755 
 756         case DHCP_EXTEND:

 757                 (void) dhcp_extending(dsmp);
 758                 break;
 759 
 760         case DHCP_GET_TAG: {
 761                 dhcp_optnum_t   optnum;
 762                 void            *opt = NULL;
 763                 uint_t          optlen;
 764                 boolean_t       did_alloc = B_FALSE;
 765                 PKT_LIST        *ack = dsmp->dsm_ack;
 766                 int             i;
 767 
 768                 /*
 769                  * verify the request makes sense.
 770                  */
 771 
 772                 if (iap->ia_request->data_type   != DHCP_TYPE_OPTNUM ||
 773                     iap->ia_request->data_length != sizeof (dhcp_optnum_t)) {
 774                         send_error_reply(iap, DHCP_IPC_E_PROTO);
 775                         break;
 776                 }
 777 
 778                 (void) memcpy(&optnum, iap->ia_request->buffer,
 779                     sizeof (dhcp_optnum_t));
 780 
 781 load_option:
 782                 switch (optnum.category) {
 783 
 784                 case DSYM_SITE:                 /* FALLTHRU */
 785                 case DSYM_STANDARD:
 786                         for (i = 0; i < dsmp->dsm_pillen; i++) {
 787                                 if (dsmp->dsm_pil[i] == optnum.code)
 788                                         break;
 789                         }
 790                         if (i < dsmp->dsm_pillen)
 791                                 break;
 792                         if (isv6) {
 793                                 opt = dhcpv6_pkt_option(ack, NULL, optnum.code,
 794                                     NULL);
 795                         } else {
 796                                 if (optnum.code <= DHCP_LAST_OPT)
 797                                         opt = ack->opts[optnum.code];
 798                         }
 799                         break;
 800 
 801                 case DSYM_VENDOR:
 802                         if (isv6) {
 803                                 dhcpv6_option_t *d6o;
 804                                 uint32_t ent;
 805 
 806                                 /*
 807                                  * Look through vendor options to find our
 808                                  * enterprise number.
 809                                  */
 810                                 d6o = NULL;
 811                                 for (;;) {
 812                                         d6o = dhcpv6_pkt_option(ack, d6o,
 813                                             DHCPV6_OPT_VENDOR_OPT, &optlen);
 814                                         if (d6o == NULL)
 815                                                 break;
 816                                         optlen -= sizeof (*d6o);
 817                                         if (optlen < sizeof (ent))


 859                                     DHCPV6_MSG_RELAY_REPL) {
 860                                         if (optlen > sizeof (dhcpv6_relay_t))
 861                                                 break;
 862                                 } else {
 863                                         if (optlen > sizeof (*d6m))
 864                                                 break;
 865                                 }
 866 
 867                                 opt = malloc(sizeof (*d6o) + optnum.size);
 868                                 if (opt != NULL) {
 869                                         d6o = opt;
 870                                         d6o->d6o_code = htons(optnum.code);
 871                                         d6o->d6o_len = htons(optnum.size);
 872                                         (void) memcpy(d6o + 1, (caddr_t)d6m +
 873                                             optnum.code, optnum.size);
 874                                 }
 875                         } else {
 876                                 if (optnum.code + optnum.size > sizeof (PKT))
 877                                         break;
 878 
 879                                 /*
 880                                  * + 2 to account for option code and length
 881                                  * byte
 882                                  */
 883                                 opt = malloc(optnum.size + 2);
 884                                 if (opt != NULL) {
 885                                         DHCP_OPT *v4opt = opt;
 886 
 887                                         v4opt->len  = optnum.size;
 888                                         v4opt->code = optnum.code;
 889                                         (void) memcpy(v4opt->value,
 890                                             (caddr_t)ack->pkt + optnum.code,
 891                                             optnum.size);
 892                                 }
 893                         }
 894 
 895                         if (opt == NULL) {
 896                                 send_error_reply(iap, DHCP_IPC_E_MEMORY);
 897                                 return;
 898                         }
 899                         did_alloc = B_TRUE;
 900                         break;
 901 
 902                 default:
 903                         send_error_reply(iap, DHCP_IPC_E_PROTO);
 904                         return;
 905                 }
 906 
 907                 /*
 908                  * return the option payload, if there was one.  the "+ 2"
 909                  * accounts for the option code number and length byte.
 910                  */
 911 
 912                 if (opt != NULL) {
 913                         if (isv6) {
 914                                 dhcpv6_option_t d6ov;
 915 
 916                                 (void) memcpy(&d6ov, opt, sizeof (d6ov));
 917                                 optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov);
 918                         } else {
 919                                 optlen = ((DHCP_OPT *)opt)->len + 2;
 920                         }
 921                         send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen);
 922 
 923                         if (did_alloc)
 924                                 free(opt);
 925                         break;
 926                 } else if (ack != dsmp->dsm_orig_ack) {
 927                         /*
 928                          * There wasn't any definition for the option in the
 929                          * current ack, so now retry with the original ack if
 930                          * the original ack is not the current ack.
 931                          */
 932                         ack = dsmp->dsm_orig_ack;
 933                         goto load_option;
 934                 }
 935 
 936                 /*
 937                  * note that an "okay" response is returned either in
 938                  * the case of an unknown option or a known option
 939                  * with no payload.  this is okay (for now) since


 954                 if (dsmp->dsm_dflags & DHCP_IF_FAILED)
 955                         send_error_reply(iap, DHCP_IPC_E_FAILEDIF);
 956                 else
 957                         send_ok_reply(iap);
 958                 break;
 959 
 960         case DHCP_RELEASE:
 961                 if (dsmp->dsm_droprelease)
 962                         break;
 963                 dsmp->dsm_droprelease = B_TRUE;
 964                 cancel_smach_timers(dsmp); /* see comment in DHCP_DROP above */
 965                 (void) script_start(dsmp, isv6 ? EVENT_RELEASE6 :
 966                     EVENT_RELEASE, dhcp_release, "Finished with lease.", NULL);
 967                 break;          /* not an immediate function */
 968 
 969         case DHCP_START: {
 970                 PKT_LIST *ack, *oack;
 971                 PKT_LIST *plp[2];
 972 
 973                 deprecate_leases(dsmp);

 974 
 975                 /*
 976                  * if we have a valid hostconf lying around, then jump
 977                  * into INIT_REBOOT.  if it fails, we'll end up going
 978                  * through the whole selecting() procedure again.
 979                  */
 980 
 981                 error = read_hostconf(dsmp->dsm_name, plp, 2, dsmp->dsm_isv6);
 982                 ack = error > 0 ? plp[0] : NULL;
 983                 oack = error > 1 ? plp[1] : NULL;
 984 
 985                 /*
 986                  * If the allocation of the old ack fails, that's fine;
 987                  * continue without it.
 988                  */
 989                 if (oack == NULL)
 990                         oack = ack;
 991 
 992                 /*
 993                  * As long as we've allocated something, start using it.


1041                         status.if_lease = status.if_began +
1042                             dlp->dl_lifs->lif_expire.dt_start;
1043                 }
1044 
1045                 status.version          = DHCP_STATUS_VER;
1046                 status.if_state         = dsmp->dsm_state;
1047                 status.if_dflags        = dsmp->dsm_dflags;
1048                 status.if_sent          = dsmp->dsm_sent;
1049                 status.if_recv          = dsmp->dsm_received;
1050                 status.if_bad_offers    = dsmp->dsm_bad_offers;
1051 
1052                 (void) strlcpy(status.if_name, dsmp->dsm_name, LIFNAMSIZ);
1053 
1054                 send_data_reply(iap, 0, DHCP_TYPE_STATUS, &status,
1055                     sizeof (dhcp_status_t));
1056                 break;
1057         }
1058         }
1059 }
1060 









































































































































1061 /*
1062  * check_rtm_addr(): determine if routing socket message matches interface
1063  *                   address
1064  *
1065  *   input: const struct if_msghdr *: pointer to routing socket message
1066  *          int: routing socket message length
1067  *          boolean_t: set to B_TRUE if IPv6
1068  *          const in6_addr_t *: pointer to IP address
1069  *  output: boolean_t: B_TRUE if address is a match
1070  */
1071 
1072 static boolean_t
1073 check_rtm_addr(const struct ifa_msghdr *ifam, int msglen, boolean_t isv6,
1074     const in6_addr_t *addr)
1075 {
1076         const char *cp, *lim;
1077         uint_t flag;
1078         const struct sockaddr *sa;
1079 
1080         if (!(ifam->ifam_addrs & RTA_IFA))




   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 
  26 #include <sys/types.h>
  27 #include <stdlib.h>
  28 #include <assert.h>
  29 #include <errno.h>
  30 #include <locale.h>
  31 #include <string.h>
  32 #include <unistd.h>
  33 #include <signal.h>
  34 #include <stdio.h>
  35 #include <stdio_ext.h>
  36 #include <dhcp_hostconf.h>
  37 #include <dhcpagent_ipc.h>
  38 #include <dhcpagent_util.h>
  39 #include <dhcpmsg.h>
  40 #include <dhcp_inittab.h>
  41 #include <dhcp_symbol.h>
  42 #include <netinet/dhcp.h>
  43 #include <net/route.h>
  44 #include <sys/sockio.h>
  45 #include <sys/stat.h>
  46 #include <stropts.h>
  47 #include <fcntl.h>
  48 #include <sys/scsi/adapters/iscsi_if.h>
  49 
  50 #include "async.h"
  51 #include "agent.h"
  52 #include "script_handler.h"
  53 #include "util.h"
  54 #include "class_id.h"
  55 #include "states.h"
  56 #include "packet.h"
  57 #include "interface.h"
  58 #include "defaults.h"
  59 
  60 #ifndef TEXT_DOMAIN
  61 #define TEXT_DOMAIN     "SYS_TEST"
  62 #endif
  63 
  64 iu_timer_id_t           inactivity_id;
  65 int                     class_id_len = 0;
  66 char                    *class_id;
  67 iu_eh_t                 *eh;
  68 iu_tq_t                 *tq;
  69 pid_t                   grandparent;
  70 int                     rtsock_fd;
  71 
  72 static boolean_t        shutdown_started = B_FALSE;
  73 static boolean_t        do_adopt = B_FALSE;
  74 static unsigned int     debug_level = 0;
  75 static iu_eh_callback_t accept_event, ipc_event, rtsock_event;
  76 static void dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp,
  77                 ipc_action_t *iap);
  78 static DHCP_OPT * dhcp_get_ack_or_state(const dhcp_smach_t *dsmp,
  79                 const PKT_LIST *plp, uint_t codenum, boolean_t *did_alloc);
  80 
  81 /*
  82  * The ipc_cmd_allowed[] table indicates which IPC commands are allowed in
  83  * which states; a non-zero value indicates the command is permitted.
  84  *
  85  * START is permitted if the state machine is fresh, or if we are in the
  86  * process of trying to obtain a lease (as a convenience to save the
  87  * administrator from having to do an explicit DROP).  EXTEND, RELEASE, and
  88  * GET_TAG require a lease to be obtained in order to make sense.  INFORM is
  89  * permitted if the interface is fresh or has an INFORM in progress or
  90  * previously done on it -- otherwise a DROP or RELEASE is first required.
  91  * PING and STATUS always make sense and thus are always permitted, as is DROP
  92  * in order to permit the administrator to always bail out.
  93  */
  94 static int ipc_cmd_allowed[DHCP_NSTATES][DHCP_NIPC] = {
  95         /*                        D  E  P  R  S  S  I  G */
  96         /*                        R  X  I  E  T  T  N  E */
  97         /*                        O  T  N  L  A  A  F  T */
  98         /*                        P  E  G  E  R  T  O  _ */
  99         /*                        .  N  .  A  T  U  R  T */


 744         switch (iap->ia_cmd) {
 745 
 746         case DHCP_DROP:
 747                 if (dsmp->dsm_droprelease)
 748                         break;
 749                 dsmp->dsm_droprelease = B_TRUE;
 750 
 751                 /*
 752                  * Ensure that a timer associated with the existing state
 753                  * doesn't pop while we're waiting for the script to complete.
 754                  * (If so, chaos can result -- e.g., a timer causes us to end
 755                  * up in dhcp_selecting() would start acquiring a new lease on
 756                  * dsmp while our DHCP_DROP dismantling is ongoing.)
 757                  */
 758                 cancel_smach_timers(dsmp);
 759                 (void) script_start(dsmp, isv6 ? EVENT_DROP6 : EVENT_DROP,
 760                     dhcp_drop, NULL, NULL);
 761                 break;          /* not an immediate function */
 762 
 763         case DHCP_EXTEND:
 764                 dhcp_smach_set_msg_reqhost(dsmp, iap);
 765                 (void) dhcp_extending(dsmp);
 766                 break;
 767 
 768         case DHCP_GET_TAG: {
 769                 dhcp_optnum_t   optnum;
 770                 void            *opt = NULL;
 771                 uint_t          optlen;
 772                 boolean_t       did_alloc = B_FALSE;
 773                 PKT_LIST        *ack = dsmp->dsm_ack;
 774                 int             i;
 775 
 776                 /*
 777                  * verify the request makes sense.
 778                  */
 779 
 780                 if (iap->ia_request->data_type   != DHCP_TYPE_OPTNUM ||
 781                     iap->ia_request->data_length != sizeof (dhcp_optnum_t)) {
 782                         send_error_reply(iap, DHCP_IPC_E_PROTO);
 783                         break;
 784                 }
 785 
 786                 (void) memcpy(&optnum, iap->ia_request->buffer,
 787                     sizeof (dhcp_optnum_t));
 788 
 789 load_option:
 790                 switch (optnum.category) {
 791 
 792                 case DSYM_SITE:                 /* FALLTHRU */
 793                 case DSYM_STANDARD:
 794                         for (i = 0; i < dsmp->dsm_pillen; i++) {
 795                                 if (dsmp->dsm_pil[i] == optnum.code)
 796                                         break;
 797                         }
 798                         if (i < dsmp->dsm_pillen)
 799                                 break;
 800                         if (isv6) {
 801                                 opt = dhcpv6_pkt_option(ack, NULL, optnum.code,
 802                                     NULL);
 803                         } else {
 804                                 opt = dhcp_get_ack_or_state(dsmp, ack, optnum.code,
 805                                     &did_alloc);
 806                         }
 807                         break;
 808 
 809                 case DSYM_VENDOR:
 810                         if (isv6) {
 811                                 dhcpv6_option_t *d6o;
 812                                 uint32_t ent;
 813 
 814                                 /*
 815                                  * Look through vendor options to find our
 816                                  * enterprise number.
 817                                  */
 818                                 d6o = NULL;
 819                                 for (;;) {
 820                                         d6o = dhcpv6_pkt_option(ack, d6o,
 821                                             DHCPV6_OPT_VENDOR_OPT, &optlen);
 822                                         if (d6o == NULL)
 823                                                 break;
 824                                         optlen -= sizeof (*d6o);
 825                                         if (optlen < sizeof (ent))


 867                                     DHCPV6_MSG_RELAY_REPL) {
 868                                         if (optlen > sizeof (dhcpv6_relay_t))
 869                                                 break;
 870                                 } else {
 871                                         if (optlen > sizeof (*d6m))
 872                                                 break;
 873                                 }
 874 
 875                                 opt = malloc(sizeof (*d6o) + optnum.size);
 876                                 if (opt != NULL) {
 877                                         d6o = opt;
 878                                         d6o->d6o_code = htons(optnum.code);
 879                                         d6o->d6o_len = htons(optnum.size);
 880                                         (void) memcpy(d6o + 1, (caddr_t)d6m +
 881                                             optnum.code, optnum.size);
 882                                 }
 883                         } else {
 884                                 if (optnum.code + optnum.size > sizeof (PKT))
 885                                         break;
 886 
 887                                 opt = malloc(optnum.size + DHCP_OPT_META_LEN);




 888                                 if (opt != NULL) {
 889                                         DHCP_OPT *v4opt = opt;
 890 
 891                                         v4opt->len  = optnum.size;
 892                                         v4opt->code = optnum.code;
 893                                         (void) memcpy(v4opt->value,
 894                                             (caddr_t)ack->pkt + optnum.code,
 895                                             optnum.size);
 896                                 }
 897                         }
 898 
 899                         if (opt == NULL) {
 900                                 send_error_reply(iap, DHCP_IPC_E_MEMORY);
 901                                 return;
 902                         }
 903                         did_alloc = B_TRUE;
 904                         break;
 905 
 906                 default:
 907                         send_error_reply(iap, DHCP_IPC_E_PROTO);
 908                         return;
 909                 }
 910 
 911                 /*
 912                  * return the option payload, if there was one.

 913                  */
 914 
 915                 if (opt != NULL) {
 916                         if (isv6) {
 917                                 dhcpv6_option_t d6ov;
 918 
 919                                 (void) memcpy(&d6ov, opt, sizeof (d6ov));
 920                                 optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov);
 921                         } else {
 922                                 optlen = ((DHCP_OPT *)opt)->len + DHCP_OPT_META_LEN;
 923                         }
 924                         send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen);
 925 
 926                         if (did_alloc)
 927                                 free(opt);
 928                         break;
 929                 } else if (ack != dsmp->dsm_orig_ack) {
 930                         /*
 931                          * There wasn't any definition for the option in the
 932                          * current ack, so now retry with the original ack if
 933                          * the original ack is not the current ack.
 934                          */
 935                         ack = dsmp->dsm_orig_ack;
 936                         goto load_option;
 937                 }
 938 
 939                 /*
 940                  * note that an "okay" response is returned either in
 941                  * the case of an unknown option or a known option
 942                  * with no payload.  this is okay (for now) since


 957                 if (dsmp->dsm_dflags & DHCP_IF_FAILED)
 958                         send_error_reply(iap, DHCP_IPC_E_FAILEDIF);
 959                 else
 960                         send_ok_reply(iap);
 961                 break;
 962 
 963         case DHCP_RELEASE:
 964                 if (dsmp->dsm_droprelease)
 965                         break;
 966                 dsmp->dsm_droprelease = B_TRUE;
 967                 cancel_smach_timers(dsmp); /* see comment in DHCP_DROP above */
 968                 (void) script_start(dsmp, isv6 ? EVENT_RELEASE6 :
 969                     EVENT_RELEASE, dhcp_release, "Finished with lease.", NULL);
 970                 break;          /* not an immediate function */
 971 
 972         case DHCP_START: {
 973                 PKT_LIST *ack, *oack;
 974                 PKT_LIST *plp[2];
 975 
 976                 deprecate_leases(dsmp);
 977                 dhcp_smach_set_msg_reqhost(dsmp, iap);
 978 
 979                 /*
 980                  * if we have a valid hostconf lying around, then jump
 981                  * into INIT_REBOOT.  if it fails, we'll end up going
 982                  * through the whole selecting() procedure again.
 983                  */
 984 
 985                 error = read_hostconf(dsmp->dsm_name, plp, 2, dsmp->dsm_isv6);
 986                 ack = error > 0 ? plp[0] : NULL;
 987                 oack = error > 1 ? plp[1] : NULL;
 988 
 989                 /*
 990                  * If the allocation of the old ack fails, that's fine;
 991                  * continue without it.
 992                  */
 993                 if (oack == NULL)
 994                         oack = ack;
 995 
 996                 /*
 997                  * As long as we've allocated something, start using it.


1045                         status.if_lease = status.if_began +
1046                             dlp->dl_lifs->lif_expire.dt_start;
1047                 }
1048 
1049                 status.version          = DHCP_STATUS_VER;
1050                 status.if_state         = dsmp->dsm_state;
1051                 status.if_dflags        = dsmp->dsm_dflags;
1052                 status.if_sent          = dsmp->dsm_sent;
1053                 status.if_recv          = dsmp->dsm_received;
1054                 status.if_bad_offers    = dsmp->dsm_bad_offers;
1055 
1056                 (void) strlcpy(status.if_name, dsmp->dsm_name, LIFNAMSIZ);
1057 
1058                 send_data_reply(iap, 0, DHCP_TYPE_STATUS, &status,
1059                     sizeof (dhcp_status_t));
1060                 break;
1061         }
1062         }
1063 }
1064 
1065 /*
1066  * dhcp_smach_set_msg_reqhost(): set dsm_msg_reqhost based on the message
1067  * content of a DHCP IPC message
1068  *
1069  *   input: dhcp_smach_t *: the state machine instance;
1070  *          ipc_action_t *: the decoded DHCP IPC message;
1071  *  output: void
1072  */
1073 
1074 static void
1075 dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp, ipc_action_t *iap)
1076 {
1077         if (dsmp->dsm_msg_reqhost != NULL) {
1078                 dhcpmsg(MSG_DEBUG,
1079                     "dhcp_smach_set_msg_reqhost: nullify former value, %s",
1080                     dsmp->dsm_msg_reqhost);
1081                 free(dsmp->dsm_msg_reqhost);
1082                 dsmp->dsm_msg_reqhost = NULL;
1083         }
1084         free(dsmp->dsm_reqfqdn);
1085         dsmp->dsm_reqfqdn = NULL;
1086 
1087         /*
1088          * if a STANDARD/HOSTNAME was sent in the IPC request, then copy that
1089          * value into the state machine data if decoding succeeds. Otherwise,
1090          * log to indicate at what step the decoding stopped.
1091          */
1092 
1093         if (dsmp->dsm_isv6) {
1094                 dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: ipv6 is not"
1095                     " handled");
1096         } else if (iap->ia_request->data_type != DHCP_TYPE_OPTION) {
1097                 dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: request type %d is"
1098                     " not DHCP_TYPE_OPTION", iap->ia_request->data_type);
1099         } else {
1100                 if (iap->ia_request->buffer == NULL
1101                     || iap->ia_request->data_length <= DHCP_OPT_META_LEN) {
1102                         dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:"
1103                             " DHCP_TYPE_OPTION ia_request buffer is NULL (0) or"
1104                             " short (1): %d",
1105                             iap->ia_request->buffer == NULL ? 0 : 1);
1106                 } else {
1107                         DHCP_OPT *d4o = (DHCP_OPT *)iap->ia_request->buffer;
1108 
1109                         if (d4o->code != CD_HOSTNAME)
1110                         {
1111                                 dhcpmsg(MSG_DEBUG,
1112                                     "dhcp_smach_set_msg_reqhost: ignoring DHCPv4"
1113                                     " option %u", d4o->code);
1114                         } else if (iap->ia_request->data_length - DHCP_OPT_META_LEN
1115                             != d4o->len) {
1116                                 dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:"
1117                                     " unexpected DHCP_OPT buffer length %u for CD_HOSTNAME"
1118                                     " option length %u", iap->ia_request->data_length,
1119                                     d4o->len);
1120                         } else {
1121 
1122                                 dhcp_symbol_t *entry = inittab_getbycode(ITAB_CAT_STANDARD,
1123                                     ITAB_CONS_INFO, CD_HOSTNAME);
1124                                 if (entry == NULL) {
1125                                         dhcpmsg(MSG_WARNING,
1126                                             "dhcp_smach_set_msg_reqhost: error getting"
1127                                             " ITAB_CAT_STANDARD ITAB_CONS_INFO"
1128                                             " CD_HOSTNAME entry");
1129                                 } else {
1130                                         char *value = inittab_decode(entry, d4o->value,
1131                                             d4o->len, /* just_payload */ B_TRUE);
1132                                         if (value == NULL) {
1133                                                 dhcpmsg(MSG_WARNING,
1134                                                     "dhcp_smach_set_msg_reqhost: error decoding"
1135                                                     " CD_HOSTNAME value from DHCP_OPT");
1136                                         } else {
1137                                                 dhcpmsg(MSG_DEBUG,
1138                                                     "dhcp_smach_set_msg_reqhost: host %s", value);
1139                                                 free(dsmp->dsm_msg_reqhost);
1140                                                 dsmp->dsm_msg_reqhost = value;
1141                                         }
1142                                         free(entry);
1143                                         entry = NULL;
1144                                 }
1145                         }
1146                 }
1147         }
1148 }
1149 
1150 /*
1151  * dhcp_get_ack_or_state(): get a v4 option from the ACK or from the state
1152  * machine state for certain codes that are not ACKed (e.g., CD_CLIENT_ID)
1153  *
1154  *   input: dhcp_smach_t *: the state machine instance;
1155  *          PKT_LIST *: the decoded DHCP IPC message;
1156  *          uint_t: the DHCP client option code;
1157  *          boolean_t *: a pointer to a value that will be set to B_TRUE if
1158  *              the return value must be freed (or else set to B_FALSE);
1159  *  output: the option if found or else NULL.
1160  */
1161 
1162 /* ARGSUSED */
1163 static DHCP_OPT *
1164 dhcp_get_ack_or_state(const dhcp_smach_t *dsmp, const PKT_LIST *plp,
1165         uint_t codenum, boolean_t *did_alloc)
1166 {
1167         DHCP_OPT *opt;
1168 
1169         *did_alloc = B_FALSE;
1170 
1171         if (codenum > DHCP_LAST_OPT)
1172                 return NULL;
1173 
1174         /* check the ACK first for all codes */
1175         opt = plp->opts[codenum];
1176         if (opt != NULL)
1177                 return opt;
1178 
1179         /* check the machine state also for certain codes */
1180         switch (codenum) {
1181         case CD_CLIENT_ID:
1182                 /*
1183                  * CD_CLIENT_ID is not sent in an ACK, but it's possibly available
1184                  * from the state machine data
1185                  */
1186 
1187                 if (dsmp->dsm_cidlen > 0) {
1188                         if ((opt = malloc(dsmp->dsm_cidlen + DHCP_OPT_META_LEN))
1189                             != NULL) {
1190                                 *did_alloc = B_TRUE;
1191                                 (void) encode_dhcp_opt(opt, B_FALSE /* is IPv6 */,
1192                                     CD_CLIENT_ID, dsmp->dsm_cid, dsmp->dsm_cidlen);
1193                         }
1194                 }
1195                 break;
1196         default:
1197                 break;
1198         }
1199         return (opt);
1200 }
1201 
1202 /*
1203  * check_rtm_addr(): determine if routing socket message matches interface
1204  *                   address
1205  *
1206  *   input: const struct if_msghdr *: pointer to routing socket message
1207  *          int: routing socket message length
1208  *          boolean_t: set to B_TRUE if IPv6
1209  *          const in6_addr_t *: pointer to IP address
1210  *  output: boolean_t: B_TRUE if address is a match
1211  */
1212 
1213 static boolean_t
1214 check_rtm_addr(const struct ifa_msghdr *ifam, int msglen, boolean_t isv6,
1215     const in6_addr_t *addr)
1216 {
1217         const char *cp, *lim;
1218         uint_t flag;
1219         const struct sockaddr *sa;
1220 
1221         if (!(ifam->ifam_addrs & RTA_IFA))