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))
|