diff options
| author | carlsonj <none@none> | 2007-01-17 08:41:37 -0800 |
|---|---|---|
| committer | carlsonj <none@none> | 2007-01-17 08:41:37 -0800 |
| commit | d04ccbb3f3163ae5962a8b7465d9796bff6ca434 (patch) | |
| tree | ee9becc340fed8326cfa6bac8d30f7d4b18313ce /usr/src/lib | |
| parent | 1c25cdbd0f6ba3ec11a8ab1653c801027a1ffc61 (diff) | |
| download | illumos-joyent-d04ccbb3f3163ae5962a8b7465d9796bff6ca434.tar.gz | |
PSARC 2006/597 DHCPv6 Client
4863327 dhcp client causes drag
6369116 dhcpagent doesn't notice when logical interfaces disappear
6386331 dhcpagent should implement RFC 4361 client identifier
6450744 dhcpagent prevents aggrs from being deleted
6462355 impact of RELEASE_ON_SIGTERM should be clearer
6464136 Solaris should support the client side of DHCPv6
6482163 libxnet lint library lacks __EXTENSIONS__
6485164 dead rule_zone_specific() rule in ipif_select_source_v6()
6487534 snoop "dhcp" filtering keyword doesn't actually work
6487958 async internal timeout can trample on renew/rebind timer
Diffstat (limited to 'usr/src/lib')
20 files changed, 1545 insertions, 313 deletions
diff --git a/usr/src/lib/libdhcpagent/Makefile b/usr/src/lib/libdhcpagent/Makefile index dde31ea7b3..0232cfd534 100644 --- a/usr/src/lib/libdhcpagent/Makefile +++ b/usr/src/lib/libdhcpagent/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -27,7 +27,7 @@ include ../Makefile.lib -HDRS = dhcp_hostconf.h dhcpagent_ipc.h dhcpagent_util.h +HDRS = dhcp_hostconf.h dhcpagent_ipc.h dhcpagent_util.h dhcp_stable.h HDRDIR = common SUBDIRS = $(MACH) diff --git a/usr/src/lib/libdhcpagent/Makefile.com b/usr/src/lib/libdhcpagent/Makefile.com index ecd15a6496..53625b5eef 100644 --- a/usr/src/lib/libdhcpagent/Makefile.com +++ b/usr/src/lib/libdhcpagent/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -27,7 +27,7 @@ LIBRARY = libdhcpagent.a VERS = .1 -OBJECTS = dhcp_hostconf.o dhcpagent_ipc.o dhcpagent_util.o +OBJECTS = dhcp_hostconf.o dhcpagent_ipc.o dhcpagent_util.o dhcp_stable.o include ../../Makefile.lib @@ -36,7 +36,7 @@ include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -lsocket -ldhcputil +LDLIBS += -lc -lsocket -ldhcputil -luuid -ldlpi SRCDIR = ../common $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c b/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c index 49a8b09723..49fa6a8f38 100644 --- a/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c +++ b/usr/src/lib/libdhcpagent/common/dhcp_hostconf.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -43,23 +42,26 @@ #include "dhcp_hostconf.h" static void relativize_time(DHCP_OPT *, time_t, time_t); +static void relativize_v6(uint32_t *, time_t, time_t); /* * ifname_to_hostconf(): converts an interface name into a hostconf file for * that interface * * input: const char *: the interface name + * boolean_t: B_TRUE if using DHCPv6 * output: char *: the hostconf filename * note: uses an internal static buffer (not threadsafe) */ char * -ifname_to_hostconf(const char *ifname) +ifname_to_hostconf(const char *ifname, boolean_t isv6) { - static char filename[sizeof (DHCP_HOSTCONF_TMPL) + IFNAMSIZ]; + static char filename[sizeof (DHCP_HOSTCONF_TMPL6) + LIFNAMSIZ]; (void) snprintf(filename, sizeof (filename), "%s%s%s", - DHCP_HOSTCONF_PREFIX, ifname, DHCP_HOSTCONF_SUFFIX); + DHCP_HOSTCONF_PREFIX, ifname, + isv6 ? DHCP_HOSTCONF_SUFFIX6 : DHCP_HOSTCONF_SUFFIX); return (filename); } @@ -68,14 +70,15 @@ ifname_to_hostconf(const char *ifname) * remove_hostconf(): removes an interface.dhc file * * input: const char *: the interface name + * boolean_t: B_TRUE if using DHCPv6 * output: int: 0 if the file is removed, -1 if it can't be removed * (errno is set) */ int -remove_hostconf(const char *ifname) +remove_hostconf(const char *ifname, boolean_t isv6) { - return (unlink(ifname_to_hostconf(ifname))); + return (unlink(ifname_to_hostconf(ifname, isv6))); } /* @@ -84,13 +87,15 @@ remove_hostconf(const char *ifname) * input: const char *: the interface name * PKT_LIST **: a pointer to a PKT_LIST * to store the info in * uint_t: the length of the list of PKT_LISTs - * output: int: 0 if the file is read and loaded into the PKT_LIST * + * boolean_t: B_TRUE if using DHCPv6 + * output: int: >0 if the file is read and loaded into the PKT_LIST * * successfully, -1 otherwise (errno is set) * note: the PKT and PKT_LISTs are dynamically allocated here */ int -read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) +read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen, + boolean_t isv6) { PKT_LIST *plp = NULL; PKT *pkt = NULL; @@ -101,23 +106,23 @@ read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) int pcnt = 0; int retval; - fd = open(ifname_to_hostconf(ifname), O_RDONLY); + fd = open(ifname_to_hostconf(ifname, isv6), O_RDONLY); if (fd == -1) return (-1); if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) goto failure; - if (magic != DHCP_HOSTCONF_MAGIC) + if (magic != (isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC)) goto failure; if (read(fd, &orig_time, sizeof (orig_time)) != sizeof (orig_time)) goto failure; /* - * read the packet back in from disk, and run it through - * dhcp_options_scan(). note that we use calloc() since - * dhcp_options_scan() relies on the packet being zeroed. + * read the packet back in from disk, and for v4, run it through + * dhcp_options_scan(). note that we use calloc() because + * dhcp_options_scan() relies on the structure being zeroed. */ for (pcnt = 0; pcnt < plplen; pcnt++) { @@ -151,7 +156,7 @@ read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) plpp[pcnt] = plp; - if (dhcp_options_scan(plp, B_TRUE) != 0) + if (!isv6 && dhcp_options_scan(plp, B_TRUE) != 0) goto failure; /* @@ -162,26 +167,129 @@ read_hostconf(const char *ifname, PKT_LIST **plpp, uint_t plplen) if (pcnt == 0) continue; - /* - * make sure the lease is still valid. - */ + if (isv6) { + dhcpv6_option_t d6o; + dhcpv6_ia_na_t d6in; + dhcpv6_iaaddr_t d6ia; + uchar_t *opts, *optmax, *subomax; - if (plp->opts[CD_LEASE_TIME] != NULL && - plp->opts[CD_LEASE_TIME]->len == sizeof (lease_t)) { + /* + * Loop over contents of the packet to find the address + * options. + */ + opts = (uchar_t *)pkt + sizeof (dhcpv6_message_t); + optmax = (uchar_t *)pkt + plp->len; + while (opts + sizeof (d6o) <= optmax) { + + /* + * Extract option header and make sure option + * is intact. + */ + (void) memcpy(&d6o, opts, sizeof (d6o)); + d6o.d6o_code = ntohs(d6o.d6o_code); + d6o.d6o_len = ntohs(d6o.d6o_len); + subomax = opts + sizeof (d6o) + d6o.d6o_len; + if (subomax > optmax) + break; + + /* + * If this isn't an option that contains + * address or prefix leases, then skip over it. + */ + if (d6o.d6o_code != DHCPV6_OPT_IA_NA && + d6o.d6o_code != DHCPV6_OPT_IA_TA && + d6o.d6o_code != DHCPV6_OPT_IA_PD) { + opts = subomax; + continue; + } + + /* + * Handle the option first. + */ + if (d6o.d6o_code == DHCPV6_OPT_IA_TA) { + /* no timers in this structure */ + opts += sizeof (dhcpv6_ia_ta_t); + } else { + /* both na and pd */ + if (opts + sizeof (d6in) > subomax) { + opts = subomax; + continue; + } + (void) memcpy(&d6in, opts, + sizeof (d6in)); + relativize_v6(&d6in.d6in_t1, orig_time, + current_time); + relativize_v6(&d6in.d6in_t2, orig_time, + current_time); + (void) memcpy(opts, &d6in, + sizeof (d6in)); + opts += sizeof (d6in); + } + + /* + * Now handle each suboption (address) inside. + */ + while (opts + sizeof (d6o) <= subomax) { + /* + * Verify the suboption header first. + */ + (void) memcpy(&d6o, opts, + sizeof (d6o)); + d6o.d6o_code = ntohs(d6o.d6o_code); + d6o.d6o_len = ntohs(d6o.d6o_len); + if (opts + sizeof (d6o) + d6o.d6o_len > + subomax) + break; + if (d6o.d6o_code != DHCPV6_OPT_IAADDR) { + opts += sizeof (d6o) + + d6o.d6o_len; + continue; + } + + /* + * Now process the contents. + */ + if (opts + sizeof (d6ia) > subomax) + break; + (void) memcpy(&d6ia, opts, + sizeof (d6ia)); + relativize_v6(&d6ia.d6ia_preflife, + orig_time, current_time); + relativize_v6(&d6ia.d6ia_vallife, + orig_time, current_time); + (void) memcpy(opts, &d6ia, + sizeof (d6ia)); + opts += sizeof (d6o) + d6o.d6o_len; + } + opts = subomax; + } + } else { - (void) memcpy(&lease, plp->opts[CD_LEASE_TIME]->value, - sizeof (lease_t)); + /* + * make sure the IPv4 DHCP lease is still valid. + */ - lease = ntohl(lease); - if ((lease != DHCP_PERM) && - (orig_time + lease) <= current_time) - goto failure; + if (plp->opts[CD_LEASE_TIME] != NULL && + plp->opts[CD_LEASE_TIME]->len == + sizeof (lease_t)) { + + (void) memcpy(&lease, + plp->opts[CD_LEASE_TIME]->value, + sizeof (lease_t)); + + lease = ntohl(lease); + if ((lease != DHCP_PERM) && + (orig_time + lease) <= current_time) + goto failure; + } + + relativize_time(plp->opts[CD_T1_TIME], orig_time, + current_time); + relativize_time(plp->opts[CD_T2_TIME], orig_time, + current_time); + relativize_time(plp->opts[CD_LEASE_TIME], orig_time, + current_time); } - - relativize_time(plp->opts[CD_T1_TIME], orig_time, current_time); - relativize_time(plp->opts[CD_T2_TIME], orig_time, current_time); - relativize_time(plp->opts[CD_LEASE_TIME], orig_time, - current_time); } (void) close(fd); @@ -203,9 +311,10 @@ failure: * * input: const char *: the interface name * PKT_LIST **: a list of pointers to PKT_LIST to write - * int: length of the list of PKT_LIST pointers + * uint_t: length of the list of PKT_LIST pointers * time_t: a starting time to treat the relative lease times * in the first packet as relative to + * boolean_t: B_TRUE if using DHCPv6 * output: int: 0 if the file is written successfully, -1 otherwise * (errno is set) */ @@ -215,16 +324,18 @@ write_hostconf( const char *ifname, PKT_LIST *pl[], uint_t pllen, - time_t relative_to) + time_t relative_to, + boolean_t isv6) { int fd; struct iovec iov[IOV_MAX]; int retval; - uint32_t magic = DHCP_HOSTCONF_MAGIC; + uint32_t magic; ssize_t explen = 0; /* Expected length of write */ int i, iovlen = 0; - fd = open(ifname_to_hostconf(ifname), O_WRONLY|O_CREAT|O_TRUNC, 0600); + fd = open(ifname_to_hostconf(ifname, isv6), O_WRONLY|O_CREAT|O_TRUNC, + 0600); if (fd == -1) return (-1); @@ -235,6 +346,7 @@ write_hostconf( * read_hostconf() to recalculate the lease times for the first packet. */ + magic = isv6 ? DHCP_HOSTCONF_MAGIC6 : DHCP_HOSTCONF_MAGIC; iov[iovlen].iov_base = (caddr_t)&magic; explen += iov[iovlen++].iov_len = sizeof (magic); iov[iovlen].iov_base = (caddr_t)&relative_to; @@ -280,3 +392,27 @@ relativize_time(DHCP_OPT *option, time_t orig_time, time_t current_time) (void) memcpy(option->value, &pkt_time, option->len); } + +/* + * relativize_v6(): re-relativizes a time in a DHCPv6 option + * + * input: uint32_t *: the time value to convert + * time_t: the time the leases in the packet are currently relative to + * time_t: the current time which leases will become relative to + * output: void + */ + +static void +relativize_v6(uint32_t *val, time_t orig_time, time_t current_time) +{ + uint32_t hval; + time_t time_diff = current_time - orig_time; + + hval = ntohl(*val); + if (hval != DHCPV6_INFTIME) { + if (hval < time_diff) + *val = 0; + else + *val = htonl(hval - time_diff); + } +} diff --git a/usr/src/lib/libdhcpagent/common/dhcp_hostconf.h b/usr/src/lib/libdhcpagent/common/dhcp_hostconf.h index c7dadd8583..dc7852e5ce 100644 --- a/usr/src/lib/libdhcpagent/common/dhcp_hostconf.h +++ b/usr/src/lib/libdhcpagent/common/dhcp_hostconf.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +32,7 @@ #include <time.h> #include <netinet/in.h> #include <netinet/dhcp.h> +#include <netinet/dhcp6.h> #include <dhcp_impl.h> /* @@ -45,15 +45,19 @@ extern "C" { #endif -#define DHCP_HOSTCONF_MAGIC 0x44484301 /* hex "DHC1" */ +#define DHCP_HOSTCONF_MAGIC 0x44484301 /* hex "DHC\1" */ +#define DHCP_HOSTCONF_MAGIC6 0x44484302 /* hex "DHC\2" */ #define DHCP_HOSTCONF_PREFIX "/etc/dhcp/" #define DHCP_HOSTCONF_SUFFIX ".dhc" +#define DHCP_HOSTCONF_SUFFIX6 ".dh6" #define DHCP_HOSTCONF_TMPL DHCP_HOSTCONF_PREFIX DHCP_HOSTCONF_SUFFIX +#define DHCP_HOSTCONF_TMPL6 DHCP_HOSTCONF_PREFIX DHCP_HOSTCONF_SUFFIX6 -extern char *ifname_to_hostconf(const char *); -extern int remove_hostconf(const char *); -extern int read_hostconf(const char *, PKT_LIST **, uint_t); -extern int write_hostconf(const char *, PKT_LIST **, uint_t, time_t); +extern char *ifname_to_hostconf(const char *, boolean_t); +extern int remove_hostconf(const char *, boolean_t); +extern int read_hostconf(const char *, PKT_LIST **, uint_t, boolean_t); +extern int write_hostconf(const char *, PKT_LIST **, uint_t, time_t, + boolean_t); #ifdef __cplusplus } diff --git a/usr/src/lib/libdhcpagent/common/dhcp_stable.c b/usr/src/lib/libdhcpagent/common/dhcp_stable.c new file mode 100644 index 0000000000..7ae11346f6 --- /dev/null +++ b/usr/src/lib/libdhcpagent/common/dhcp_stable.c @@ -0,0 +1,308 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This module reads and writes the stable identifier values, DUID and IAID. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include <fcntl.h> +#include <errno.h> +#include <libdlpi.h> +#include <uuid/uuid.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <net/if.h> +#include <netinet/dhcp6.h> +#include <dhcp_inittab.h> + +#define DUID_FILE "/etc/dhcp/duid" +#define IAID_FILE "/etc/dhcp/iaid" + +struct iaid_ent { + uint32_t ie_iaid; + char ie_name[LIFNAMSIZ]; +}; + +/* + * read_stable_duid(): read the system's stable DUID, if any + * + * input: size_t *: pointer to a size_t to return the DUID length + * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set) + * note: memory returned is from malloc; caller must free. + */ + +uchar_t * +read_stable_duid(size_t *duidlen) +{ + int fd; + ssize_t retv; + struct stat sb; + uchar_t *duid = NULL; + + if ((fd = open(DUID_FILE, O_RDONLY)) == -1) + return (NULL); + if (fstat(fd, &sb) != -1 && S_ISREG(sb.st_mode) && + (duid = malloc(sb.st_size)) != NULL) { + retv = read(fd, duid, sb.st_size); + if (retv == sb.st_size) { + *duidlen = sb.st_size; + } else { + free(duid); + /* + * Make sure that errno always gets set when something + * goes wrong. + */ + if (retv >= 0) + errno = EINVAL; + duid = NULL; + } + } + (void) close(fd); + return (duid); +} + +/* + * write_stable_duid(): write the system's stable DUID. + * + * input: const uchar_t *: pointer to the DUID buffer + * size_t: length of the DUID + * output: int: 0 on success, -1 on error. errno is set on error. + */ + +int +write_stable_duid(const uchar_t *duid, size_t duidlen) +{ + int fd; + ssize_t retv; + + (void) unlink(DUID_FILE); + if ((fd = open(DUID_FILE, O_WRONLY | O_CREAT, 0644)) == -1) + return (-1); + retv = write(fd, duid, duidlen); + if (retv == duidlen) { + return (close(fd)); + } else { + (void) close(fd); + if (retv >= 0) + errno = ENOSPC; + return (-1); + } +} + +/* + * make_stable_duid(): create a new DUID + * + * input: const char *: name of physical interface for reference + * size_t *: pointer to a size_t to return the DUID length + * output: uchar_t *: the DUID buffer, or NULL on error (and errno is set) + * note: memory returned is from malloc; caller must free. + */ + +uchar_t * +make_stable_duid(const char *physintf, size_t *duidlen) +{ + int fd, len; + dl_info_ack_t dl_info; + dlpi_if_attr_t dia; + duid_en_t *den; + + /* + * Try to read the MAC layer address for the physical interface + * provided as a hint. If that works, we can use a DUID-LLT. + */ + + fd = dlpi_if_open(physintf, &dia, B_FALSE); + if (fd != -1 && + dlpi_info(fd, -1, &dl_info, NULL, NULL, NULL, NULL, NULL, + NULL) != -1 && + (len = dl_info.dl_addr_length - abs(dl_info.dl_sap_length)) > 0) { + duid_llt_t *dllt; + uint_t arptype; + + arptype = dlpi_to_arp(dl_info.dl_mac_type); + + if ((dllt = malloc(sizeof (*dllt) + len)) == NULL) { + (void) dlpi_close(fd); + return (NULL); + } + if (arptype != 0 && dlpi_phys_addr(fd, -1, DL_CURR_PHYS_ADDR, + (uint8_t *)(dllt + 1), NULL) == 0) { + time_t now; + + dllt->dllt_dutype = htons(DHCPV6_DUID_LLT); + dllt->dllt_hwtype = htons(arptype); + now = time(NULL) - DUID_TIME_BASE; + dllt->dllt_time = htonl(now); + *duidlen = sizeof (*dllt) + len; + return ((uchar_t *)dllt); + } + free(dllt); + } + if (fd != -1) + (void) dlpi_close(fd); + + /* + * If we weren't able to create a DUID based on the network interface + * in use, then generate one based on a UUID. + */ + den = malloc(sizeof (*den) + UUID_LEN); + if (den != NULL) { + uuid_t uuid; + + den->den_dutype = htons(DHCPV6_DUID_EN); + DHCPV6_SET_ENTNUM(den, DHCPV6_SUN_ENT); + uuid_generate(uuid); + (void) memcpy(den + 1, uuid, UUID_LEN); + *duidlen = sizeof (*den) + UUID_LEN; + } + return ((uchar_t *)den); +} + +/* + * read_stable_iaid(): read a link's stable IAID, if any + * + * input: const char *: interface name + * output: uint32_t: the IAID, or 0 if none + */ + +uint32_t +read_stable_iaid(const char *intf) +{ + int fd; + struct iaid_ent ie; + + if ((fd = open(IAID_FILE, O_RDONLY)) == -1) + return (0); + while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) { + if (strcmp(intf, ie.ie_name) == 0) { + (void) close(fd); + return (ie.ie_iaid); + } + } + (void) close(fd); + return (0); +} + +/* + * write_stable_iaid(): write out a link's stable IAID + * + * input: const char *: interface name + * output: uint32_t: the IAID, or 0 if none + */ + +int +write_stable_iaid(const char *intf, uint32_t iaid) +{ + int fd; + struct iaid_ent ie; + ssize_t retv; + + if ((fd = open(IAID_FILE, O_RDWR | O_CREAT, 0644)) == -1) + return (0); + while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) { + if (strcmp(intf, ie.ie_name) == 0) { + (void) close(fd); + if (iaid == ie.ie_iaid) { + return (0); + } else { + errno = EINVAL; + return (-1); + } + } + } + (void) memset(&ie, 0, sizeof (ie)); + ie.ie_iaid = iaid; + (void) strlcpy(ie.ie_name, intf, sizeof (ie.ie_name)); + retv = write(fd, &ie, sizeof (ie)); + (void) close(fd); + if (retv == sizeof (ie)) { + return (0); + } else { + if (retv >= 0) + errno = ENOSPC; + return (-1); + } +} + +/* + * make_stable_iaid(): create a stable IAID for a link + * + * input: const char *: interface name + * uint32_t: the ifIndex for this link (as a "hint") + * output: uint32_t: the new IAID, never zero + */ + +/* ARGSUSED */ +uint32_t +make_stable_iaid(const char *intf, uint32_t hint) +{ + int fd; + struct iaid_ent ie; + uint32_t maxid, minunused; + boolean_t recheck; + + if ((fd = open(IAID_FILE, O_RDONLY)) == -1) + return (hint); + maxid = 0; + minunused = 1; + /* + * This logic is deliberately unoptimized. The reason is that it runs + * essentially just once per interface for the life of the system. + * Once the IAID is established, there's no reason to generate it + * again, and all we care about here is correctness. Also, IAIDs tend + * to get added in a logical sequence order, so the outer loop should + * not normally run more than twice. + */ + do { + recheck = B_FALSE; + while (read(fd, &ie, sizeof (ie)) == sizeof (ie)) { + if (ie.ie_iaid > maxid) + maxid = ie.ie_iaid; + if (ie.ie_iaid == minunused) { + recheck = B_TRUE; + minunused++; + } + if (ie.ie_iaid == hint) + hint = 0; + } + if (recheck) + (void) lseek(fd, 0, SEEK_SET); + } while (recheck); + (void) close(fd); + if (hint != 0) + return (hint); + else if (maxid != UINT32_MAX) + return (maxid + 1); + else + return (minunused); +} diff --git a/usr/src/lib/libdhcpagent/common/dhcp_stable.h b/usr/src/lib/libdhcpagent/common/dhcp_stable.h new file mode 100644 index 0000000000..3352283eed --- /dev/null +++ b/usr/src/lib/libdhcpagent/common/dhcp_stable.h @@ -0,0 +1,54 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _DHCP_STABLE_H +#define _DHCP_STABLE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This module reads and writes the stable identifier values, DUID and IAID. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +extern uchar_t *read_stable_duid(size_t *); +extern int write_stable_duid(const uchar_t *, size_t); +extern uchar_t *make_stable_duid(const char *, size_t *); + +extern uint32_t read_stable_iaid(const char *); +extern int write_stable_iaid(const char *, uint32_t); +extern uint32_t make_stable_iaid(const char *, uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _DHCP_STABLE_H */ diff --git a/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.c b/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.c index 5f17cb458b..8a3ec18060 100644 --- a/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.c +++ b/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -35,9 +34,11 @@ #include <fcntl.h> #include <errno.h> #include <netinet/in.h> +#include <netinet/tcp.h> #include <net/if.h> #include <sys/sockio.h> #include <sys/fcntl.h> +#include <sys/time.h> #include <stdio.h> /* snprintf */ #include <arpa/inet.h> /* ntohl, ntohs, etc */ @@ -71,7 +72,6 @@ #define BUFMAX 256 -static int dhcp_ipc_rresvport(in_port_t *); static int dhcp_ipc_timed_read(int, void *, unsigned int, int *); static int getinfo_ifnames(const char *, dhcp_optnum_t *, DHCP_OPT **); static char *get_ifnames(int, int); @@ -82,15 +82,15 @@ static char *get_ifnames(int, int); * * input: dhcp_ipc_type_t: the type of ipc request to allocate * const char *: the interface to associate the request with - * void *: the payload to send with the message (NULL if none) + * const void *: the payload to send with the message (NULL if none) * uint32_t: the payload size (0 if none) * dhcp_data_type_t: the description of the type of payload * output: dhcp_ipc_request_t *: the request on success, NULL on failure */ dhcp_ipc_request_t * -dhcp_ipc_alloc_request(dhcp_ipc_type_t type, const char *ifname, void *buffer, - uint32_t buffer_size, dhcp_data_type_t data_type) +dhcp_ipc_alloc_request(dhcp_ipc_type_t type, const char *ifname, + const void *buffer, uint32_t buffer_size, dhcp_data_type_t data_type) { dhcp_ipc_request_t *request = calloc(1, DHCP_IPC_REQUEST_SIZE + buffer_size); @@ -116,15 +116,15 @@ dhcp_ipc_alloc_request(dhcp_ipc_type_t type, const char *ifname, void *buffer, * * input: dhcp_ipc_request_t *: the request the reply is for * int: the return code (0 for success, DHCP_IPC_E_* otherwise) - * void *: the payload to send with the message (NULL if none) + * const void *: the payload to send with the message (NULL if none) * uint32_t: the payload size (0 if none) * dhcp_data_type_t: the description of the type of payload * output: dhcp_ipc_reply_t *: the reply on success, NULL on failure */ dhcp_ipc_reply_t * -dhcp_ipc_alloc_reply(dhcp_ipc_request_t *request, int return_code, void *buffer, - uint32_t buffer_size, dhcp_data_type_t data_type) +dhcp_ipc_alloc_reply(dhcp_ipc_request_t *request, int return_code, + const void *buffer, uint32_t buffer_size, dhcp_data_type_t data_type) { dhcp_ipc_reply_t *reply = calloc(1, DHCP_IPC_REPLY_SIZE + buffer_size); @@ -175,33 +175,36 @@ dhcp_ipc_get_data(dhcp_ipc_reply_t *reply, size_t *size, dhcp_data_type_t *type) * (dynamically allocated) * uint32_t: the minimum length of the packet * int: the # of milliseconds to wait for the message (-1 is forever) - * output: int: 0 on success, DHCP_IPC_E_* otherwise + * output: int: DHCP_IPC_SUCCESS on success, DHCP_IPC_E_* otherwise */ static int dhcp_ipc_recv_msg(int fd, void **msg, uint32_t base_length, int msec) { - ssize_t retval; + int retval; dhcp_ipc_reply_t *ipc_msg; uint32_t length; retval = dhcp_ipc_timed_read(fd, &length, sizeof (uint32_t), &msec); - if (retval != sizeof (uint32_t)) - return (DHCP_IPC_E_READ); + if (retval != DHCP_IPC_SUCCESS) + return (retval); + + if (length == 0) + return (DHCP_IPC_E_PROTO); *msg = malloc(length); if (*msg == NULL) return (DHCP_IPC_E_MEMORY); retval = dhcp_ipc_timed_read(fd, *msg, length, &msec); - if (retval != length) { + if (retval != DHCP_IPC_SUCCESS) { free(*msg); - return (DHCP_IPC_E_READ); + return (retval); } if (length < base_length) { free(*msg); - return (DHCP_IPC_E_READ); + return (DHCP_IPC_E_PROTO); } /* @@ -211,10 +214,10 @@ dhcp_ipc_recv_msg(int fd, void **msg, uint32_t base_length, int msec) ipc_msg = (dhcp_ipc_reply_t *)(*msg); if (ipc_msg->data_length + base_length != length) { free(*msg); - return (DHCP_IPC_E_READ); + return (DHCP_IPC_E_PROTO); } - return (0); + return (DHCP_IPC_SUCCESS); } /* @@ -335,28 +338,30 @@ int dhcp_ipc_make_request(dhcp_ipc_request_t *request, dhcp_ipc_reply_t **reply, int32_t timeout) { - int fd, retval; - struct sockaddr_in sin_peer; - in_port_t source_port = IPPORT_RESERVED - 1; - - (void) memset(&sin_peer, 0, sizeof (sin_peer)); + int fd, on, retval; + struct sockaddr_in sinv; - sin_peer.sin_family = AF_INET; - sin_peer.sin_port = htons(IPPORT_DHCPAGENT); - sin_peer.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - if ((fd = dhcp_ipc_rresvport(&source_port)) == -1) { + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + return (DHCP_IPC_E_SOCKET); - /* - * user isn't privileged. just make a socket. - */ + /* + * Bind a privileged port if we have sufficient privilege to do so. + * Continue as non-privileged otherwise. + */ + on = 1; + (void) setsockopt(fd, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, sizeof (on)); - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - return (DHCP_IPC_E_SOCKET); + (void) memset(&sinv, 0, sizeof (sinv)); + sinv.sin_family = AF_INET; + if (bind(fd, (struct sockaddr *)&sinv, sizeof (sinv)) == -1) { + (void) dhcp_ipc_close(fd); + return (DHCP_IPC_E_BIND); } - retval = connect(fd, (struct sockaddr *)&sin_peer, sizeof (sin_peer)); + sinv.sin_port = htons(IPPORT_DHCPAGENT); + sinv.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + retval = connect(fd, (struct sockaddr *)&sinv, sizeof (sinv)); if (retval == -1) { (void) dhcp_ipc_close(fd); return (DHCP_IPC_E_CONNECT); @@ -504,7 +509,7 @@ dhcp_ipc_strerror(int error) /* note: this must be kept in sync with DHCP_IPC_E_* definitions */ const char *syscalls[] = { "<unknown>", "socket", "fcntl", "read", "accept", "close", - "bind", "listen", "malloc", "connect", "writev" + "bind", "listen", "malloc", "connect", "writev", "poll" }; const char *error_string; @@ -525,7 +530,8 @@ dhcp_ipc_strerror(int error) case DHCP_IPC_E_BIND: /* FALLTHRU */ case DHCP_IPC_E_LISTEN: /* FALLTHRU */ case DHCP_IPC_E_CONNECT: /* FALLTHRU */ - case DHCP_IPC_E_WRITEV: + case DHCP_IPC_E_WRITEV: /* FALLTHRU */ + case DHCP_IPC_E_POLL: error_string = strerror(errno); if (error_string == NULL) @@ -605,9 +611,16 @@ dhcp_ipc_strerror(int error) error_string = "no value was found for this option"; break; - case DHCP_IPC_E_NOIFCID: - error_string = "interface does not have a configured DHCP " - "client id"; + case DHCP_IPC_E_RUNNING: + error_string = "DHCP is already running"; + break; + + case DHCP_IPC_E_SRVFAILED: + error_string = "DHCP server refused request"; + break; + + case DHCP_IPC_E_EOF: + error_string = "ipc connection closed"; break; default: @@ -623,6 +636,28 @@ dhcp_ipc_strerror(int error) } /* + * dhcp_ipc_type_to_string(): maps an ipc command code into a human-readable + * string + * + * input: int: the ipc command code to map + * output: const char *: the corresponding human-readable string + */ + +const char * +dhcp_ipc_type_to_string(dhcp_ipc_type_t type) +{ + static const char *typestr[] = { + "drop", "extend", "ping", "release", "start", "status", + "inform", "get_tag" + }; + + if (type < 0 || type >= DHCP_NIPC) + return ("unknown"); + else + return (typestr[(int)type]); +} + +/* * getinfo_ifnames(): checks the value of a specified option on a list of * interface names. * input: const char *: a list of interface names to query (in order) for @@ -879,53 +914,14 @@ dhcp_ipc_getinfo(dhcp_optnum_t *optnum, DHCP_OPT **result, int32_t timeout) } /* - * NOTE: we provide our own version of this function because currently - * (sunos 5.7), if we link against the one in libnsl, we will - * increase the size of our binary by more than 482K due to - * perversions in linking. besides, this one is tighter :-) - */ - -static int -dhcp_ipc_rresvport(in_port_t *start_port) -{ - struct sockaddr_in sin; - int s, saved_errno; - - (void) memset(&sin, 0, sizeof (struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) - return (-1); - - errno = EAGAIN; - while (*start_port > IPPORT_RESERVED / 2) { - - sin.sin_port = htons((*start_port)--); - - if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) == 0) - return (s); - - if (errno != EADDRINUSE) { - saved_errno = errno; - break; - } - } - - (void) close(s); - errno = saved_errno; - return (-1); -} - -/* * dhcp_ipc_timed_read(): reads from a descriptor using a maximum timeout * * input: int: the file descriptor to read from * void *: the buffer to read into * unsigned int: the total length of data to read * int *: the number of milliseconds to wait; the number of - * milliseconds left are returned - * output: int: -1 on failure, otherwise the number of bytes read + * milliseconds left are returned (-1 is "forever") + * output: int: DHCP_IPC_SUCCESS on success, DHCP_IPC_E_* otherwise */ static int @@ -934,56 +930,63 @@ dhcp_ipc_timed_read(int fd, void *buffer, unsigned int length, int *msec) unsigned int n_total = 0; ssize_t n_read; struct pollfd pollfd; - struct timeval start, end, elapsed; - - /* make sure that any errors we return are ours */ - errno = 0; + hrtime_t start, end; + int retv; pollfd.fd = fd; pollfd.events = POLLIN; while (n_total < length) { - if (gettimeofday(&start, NULL) == -1) - return (-1); - - switch (poll(&pollfd, 1, *msec)) { + start = gethrtime(); - case 0: + retv = poll(&pollfd, 1, *msec); + if (retv == 0) { + /* This can happen only if *msec is not -1 */ *msec = 0; - return (n_total); - - case -1: - *msec = 0; - return (-1); + return (DHCP_IPC_E_TIMEOUT); + } - default: - if ((pollfd.revents & POLLIN) == 0) - return (-1); + if (*msec != -1) { + end = gethrtime(); + *msec -= (end - start) / (NANOSEC / MILLISEC); + if (*msec < 0) + *msec = 0; + } - if (gettimeofday(&end, NULL) == -1) - return (-1); + if (retv == -1) { + if (errno != EINTR) + return (DHCP_IPC_E_POLL); + else if (*msec == 0) + return (DHCP_IPC_E_TIMEOUT); + continue; + } - elapsed.tv_sec = end.tv_sec - start.tv_sec; - elapsed.tv_usec = end.tv_usec - start.tv_usec; - if (elapsed.tv_usec < 0) { - elapsed.tv_sec--; - elapsed.tv_usec += 1000000; /* one second */ - } + if (!(pollfd.revents & POLLIN)) { + errno = EINVAL; + return (DHCP_IPC_E_POLL); + } - n_read = read(fd, (caddr_t)buffer + n_total, - length - n_total); + n_read = read(fd, (caddr_t)buffer + n_total, length - n_total); - if (n_read == -1) - return (-1); + if (n_read == -1) { + if (errno != EINTR) + return (DHCP_IPC_E_READ); + else if (*msec == 0) + return (DHCP_IPC_E_TIMEOUT); + continue; + } - n_total += n_read; - *msec -= elapsed.tv_sec * 1000 + elapsed.tv_usec / 1000; - if (*msec <= 0 || n_read == 0) - return (n_total); - break; + if (n_read == 0) { + return (n_total == 0 ? DHCP_IPC_E_EOF : + DHCP_IPC_E_PROTO); } + + n_total += n_read; + + if (*msec == 0 && n_total < length) + return (DHCP_IPC_E_TIMEOUT); } - return (n_total); + return (DHCP_IPC_SUCCESS); } diff --git a/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.h b/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.h index b509917dff..91236a85bb 100644 --- a/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.h +++ b/usr/src/lib/libdhcpagent/common/dhcpagent_ipc.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -49,6 +49,7 @@ extern "C" { #define DHCP_AGENT_PATH "/sbin/dhcpagent" #define DHCP_IPC_LISTEN_BACKLOG 30 #define IPPORT_DHCPAGENT 4999 +#define DHCP_IPC_MAX_WAIT 15 /* max seconds to wait to start agent */ /* * return values which should be used by programs which talk to the @@ -83,21 +84,25 @@ typedef enum { * * code in dhcpagent relies on the numeric values of these * requests -- but there's no sane reason to change them anyway. + * + * If any commands are changed, added, or removed, see the typestr[] + * array in dhcpagent_ipc.c. */ typedef enum { DHCP_DROP, DHCP_EXTEND, DHCP_PING, DHCP_RELEASE, DHCP_START, DHCP_STATUS, DHCP_INFORM, DHCP_GET_TAG, DHCP_NIPC, /* number of supported requests */ - DHCP_PRIMARY = 0x100 + DHCP_PRIMARY = 0x100, + DHCP_V6 = 0x200 } dhcp_ipc_type_t; /* structure passed with the DHCP_GET_TAG request */ typedef struct { - uchar_t category; - uint16_t code; - uint16_t size; + uint_t category; + uint_t code; + uint_t size; } dhcp_optnum_t; #define DHCP_IPC_CMD(type) ((type) & 0x00ff) @@ -114,15 +119,19 @@ typedef struct { */ enum { + /* System call errors must be kept contiguous */ DHCP_IPC_SUCCESS, DHCP_IPC_E_SOCKET, DHCP_IPC_E_FCNTL, DHCP_IPC_E_READ, DHCP_IPC_E_ACCEPT, DHCP_IPC_E_CLOSE, DHCP_IPC_E_BIND, DHCP_IPC_E_LISTEN, DHCP_IPC_E_MEMORY, - DHCP_IPC_E_CONNECT, DHCP_IPC_E_WRITEV, DHCP_IPC_E_TIMEOUT, + DHCP_IPC_E_CONNECT, DHCP_IPC_E_WRITEV, DHCP_IPC_E_POLL, + + /* All others follow */ + DHCP_IPC_E_TIMEOUT, DHCP_IPC_E_SRVFAILED, DHCP_IPC_E_EOF, DHCP_IPC_E_INVIF, DHCP_IPC_E_INT, DHCP_IPC_E_PERM, DHCP_IPC_E_OUTSTATE, DHCP_IPC_E_PEND, DHCP_IPC_E_BOOTP, DHCP_IPC_E_CMD_UNKNOWN, DHCP_IPC_E_UNKIF, DHCP_IPC_E_PROTO, DHCP_IPC_E_FAILEDIF, DHCP_IPC_E_NOPRIMARY, DHCP_IPC_E_DOWNIF, - DHCP_IPC_E_NOIPIF, DHCP_IPC_E_NOVALUE, DHCP_IPC_E_NOIFCID + DHCP_IPC_E_NOIPIF, DHCP_IPC_E_NOVALUE, DHCP_IPC_E_RUNNING }; /* @@ -133,11 +142,12 @@ enum { extern const char *dhcp_ipc_strerror(int); extern dhcp_ipc_request_t *dhcp_ipc_alloc_request(dhcp_ipc_type_t, const char *, - void *, uint32_t, dhcp_data_type_t); + const void *, uint32_t, dhcp_data_type_t); extern void *dhcp_ipc_get_data(dhcp_ipc_reply_t *, size_t *, dhcp_data_type_t *); extern int dhcp_ipc_make_request(dhcp_ipc_request_t *, dhcp_ipc_reply_t **, int32_t); +extern const char *dhcp_ipc_type_to_string(dhcp_ipc_type_t); /* * high-level public dhcpagent ipc functions @@ -153,8 +163,8 @@ extern int dhcp_ipc_getinfo(dhcp_optnum_t *, DHCP_OPT **, int32_t); extern int dhcp_ipc_init(int *); extern int dhcp_ipc_accept(int, int *, int *); extern int dhcp_ipc_recv_request(int, dhcp_ipc_request_t **, int); -extern dhcp_ipc_reply_t *dhcp_ipc_alloc_reply(dhcp_ipc_request_t *, int, void *, - uint32_t, dhcp_data_type_t); +extern dhcp_ipc_reply_t *dhcp_ipc_alloc_reply(dhcp_ipc_request_t *, int, + const void *, uint32_t, dhcp_data_type_t); extern int dhcp_ipc_send_reply(int, dhcp_ipc_reply_t *); extern int dhcp_ipc_close(int); @@ -174,9 +184,11 @@ typedef enum { RENEWING, /* have lease, but trying to renew */ REBINDING, /* have lease, but trying to rebind */ INFORMATION, /* sent INFORM, received ACK */ - INIT_REBOOT, /* attempting to use cached ACK */ + INIT_REBOOT, /* attempt to use cached ACK/Reply */ ADOPTING, /* attempting to adopt */ INFORM_SENT, /* sent INFORM, awaiting ACK */ + DECLINING, /* sent v6 Decline, awaiting Reply */ + RELEASING, /* sent v6 Release, awaiting Reply */ DHCP_NSTATES /* total number of states */ } DHCPSTATE; @@ -187,6 +199,7 @@ typedef enum { #define DHCP_IF_BOOTP 0x0400 /* interface is using bootp */ #define DHCP_IF_REMOVED 0x0800 /* interface is going away */ #define DHCP_IF_FAILED 0x1000 /* interface configuration problem */ +#define DHCP_IF_V6 0x2000 /* DHCPv6 interface */ /* * structure passed with the DHCP_STATUS replies diff --git a/usr/src/lib/libdhcpagent/common/dhcpagent_util.c b/usr/src/lib/libdhcpagent/common/dhcpagent_util.c index eab4a98edb..61101bb66c 100644 --- a/usr/src/lib/libdhcpagent/common/dhcpagent_util.c +++ b/usr/src/lib/libdhcpagent/common/dhcpagent_util.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -67,7 +67,9 @@ dhcp_state_to_string(DHCPSTATE state) "INFORMATION", "INIT_REBOOT", "ADOPTING", - "INFORM_SENT" + "INFORM_SENT", + "DECLINING", + "RELEASING" }; if (state < 0 || state >= DHCP_NSTATES) @@ -242,6 +244,9 @@ dhcp_status_reply_to_string(dhcp_ipc_reply_t *reply) if (status->if_dflags & DHCP_IF_BUSY) (void) strlcat(str, "[BUSY] ", sizeof (str)); + if (status->if_dflags & DHCP_IF_V6) + (void) strlcat(str, "[V6] ", sizeof (str)); + (void) strlcat(str, "\n", sizeof (str)); switch (status->if_state) { diff --git a/usr/src/lib/libdhcpagent/common/llib-ldhcpagent b/usr/src/lib/libdhcpagent/common/llib-ldhcpagent index 7ad9e54848..168da5b06f 100644 --- a/usr/src/lib/libdhcpagent/common/llib-ldhcpagent +++ b/usr/src/lib/libdhcpagent/common/llib-ldhcpagent @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -30,5 +29,6 @@ /* PROTOLIB1 */ #include <dhcp_hostconf.h> +#include <dhcp_stable.h> #include <dhcpagent_ipc.h> #include <dhcpagent_util.h> diff --git a/usr/src/lib/libdhcpagent/common/mapfile-vers b/usr/src/lib/libdhcpagent/common/mapfile-vers index 589e76b4fb..ddd3a0dddf 100644 --- a/usr/src/lib/libdhcpagent/common/mapfile-vers +++ b/usr/src/lib/libdhcpagent/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -38,6 +38,7 @@ SUNWprivate_1.1 { dhcp_ipc_recv_request; dhcp_ipc_send_reply; dhcp_ipc_strerror; + dhcp_ipc_type_to_string; dhcp_start_agent; dhcp_state_to_string; dhcp_status_hdr_string; @@ -47,6 +48,12 @@ SUNWprivate_1.1 { read_hostconf; remove_hostconf; write_hostconf; + read_stable_duid; + write_stable_duid; + make_stable_duid; + read_stable_iaid; + write_stable_iaid; + make_stable_iaid; local: *; }; diff --git a/usr/src/lib/libdhcputil/Makefile.com b/usr/src/lib/libdhcputil/Makefile.com index e05af3bd3a..342f71f16d 100644 --- a/usr/src/lib/libdhcputil/Makefile.com +++ b/usr/src/lib/libdhcputil/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -39,7 +39,7 @@ include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -lnsl -lgen -linetutil +LDLIBS += -lc -lnsl -lgen -linetutil -ldlpi SRCDIR = ../common SRCS = $(LOCOBJS:%.o=$(SRCDIR)/%.c) $(COMOBJS:%.o=$(COMDIR)/%.c) diff --git a/usr/src/lib/libdhcputil/common/dhcp_inittab.c b/usr/src/lib/libdhcputil/common/dhcp_inittab.c index 4adca5a652..e16b241f23 100644 --- a/usr/src/lib/libdhcputil/common/dhcp_inittab.c +++ b/usr/src/lib/libdhcputil/common/dhcp_inittab.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,10 +36,13 @@ #include <libgen.h> #include <sys/isa_defs.h> #include <sys/socket.h> +#include <net/if_arp.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/sysmacros.h> #include <libinetutil.h> +#include <libdlpi.h> +#include <netinet/dhcp6.h> #include "dhcp_symbol.h" #include "dhcp_inittab.h" @@ -61,6 +63,10 @@ static boolean_t parse_entry(char *, char **); /* * forward declaration of our internal inittab_table[]. too bulky to put * up front -- check the end of this file for its definition. + * + * Note: we have only an IPv4 version here. The inittab_verify() function is + * used by the DHCP server and manager. We'll need a new function if the + * server is extended to DHCPv6. */ static dhcp_symbol_t inittab_table[]; @@ -95,6 +101,58 @@ static category_map_entry_t category_map[] = { }; /* + * dlpi_to_arp(): converts DLPI datalink types into ARP datalink types + * + * input: uint_t: the DLPI datalink type + * output: uint_t: the ARP datalink type (0 if no corresponding code) + * + * note: this function does not belong in this library, but it's here until + * dhcpagent is ported over to libdlpi. It should move to libdlpi + * instead. + */ + +uint_t +dlpi_to_arp(uint_t dlpi_type) +{ + switch (dlpi_type) { + + case DL_ETHER: + return (ARPHRD_ETHER); + + case DL_FRAME: + return (ARPHRD_FRAME); + + case DL_ATM: + return (ARPHRD_ATM); + + case DL_IPATM: + return (ARPHRD_IPATM); + + case DL_HDLC: + return (ARPHRD_HDLC); + + case DL_FC: + return (ARPHRD_FC); + + case DL_CSMACD: /* ieee 802 networks */ + case DL_TPB: + case DL_TPR: + case DL_METRO: + case DL_FDDI: + return (ARPHRD_IEEE802); + + case DL_IB: + return (ARPHRD_IB); + + case DL_IPV4: + case DL_IPV6: + return (ARPHRD_TUNNEL); + } + + return (0); +} + +/* * inittab_load(): returns all inittab entries with the specified criteria * * input: uchar_t: the categories the consumer is interested in @@ -103,6 +161,7 @@ static category_map_entry_t category_map[] = { * output: dhcp_symbol_t *: an array of dynamically allocated entries * on success, NULL upon failure */ + dhcp_symbol_t * inittab_load(uchar_t categories, char consumer, size_t *n_entries) { @@ -118,6 +177,7 @@ inittab_load(uchar_t categories, char consumer, size_t *n_entries) * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure * on success, NULL upon failure */ + dhcp_symbol_t * inittab_getbyname(uchar_t categories, char consumer, const char *name) { @@ -133,6 +193,7 @@ inittab_getbyname(uchar_t categories, char consumer, const char *name) * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure * on success, NULL upon failure */ + dhcp_symbol_t * inittab_getbycode(uchar_t categories, char consumer, uint16_t code) { @@ -152,6 +213,7 @@ inittab_getbycode(uchar_t categories, char consumer, uint16_t code) * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures * on success, NULL upon failure */ + static dhcp_symbol_t * inittab_lookup(uchar_t categories, char consumer, const char *name, int32_t code, size_t *n_entriesp) @@ -163,18 +225,24 @@ inittab_lookup(uchar_t categories, char consumer, const char *name, char *fields[ITAB_FIELDS]; unsigned long line = 0; size_t i, n_entries = 0; - char *inittab_path; + const char *inittab_path; uchar_t category_code; dsym_cdtype_t type; - inittab_path = getenv("DHCP_INITTAB_PATH"); - if (inittab_path == NULL) - inittab_path = ITAB_INITTAB_PATH; + if (categories & ITAB_CAT_V6) { + inittab_path = getenv("DHCP_INITTAB6_PATH"); + if (inittab_path == NULL) + inittab_path = ITAB_INITTAB6_PATH; + } else { + inittab_path = getenv("DHCP_INITTAB_PATH"); + if (inittab_path == NULL) + inittab_path = ITAB_INITTAB_PATH; + } inittab_fp = fopen(inittab_path, "r"); if (inittab_fp == NULL) { inittab_msg("inittab_lookup: fopen: %s: %s", - ITAB_INITTAB_PATH, strerror(errno)); + inittab_path, strerror(errno)); return (NULL); } @@ -275,6 +343,7 @@ inittab_lookup(uchar_t categories, char consumer, const char *name, entry.ds_classes.dc_names = NULL; (void) strlcpy(entry.ds_name, fields[ITAB_NAME], sizeof (entry.ds_name)); + entry.ds_dhcpv6 = (categories & ITAB_CAT_V6) ? 1 : 0; entries = new_entries; entries[n_entries++] = entry; @@ -301,6 +370,7 @@ inittab_lookup(uchar_t categories, char consumer, const char *name, * pointers into the entry on upon return * output: boolean_t: B_TRUE on success, B_FALSE on failure */ + static boolean_t parse_entry(char *entry, char **fields) { @@ -375,9 +445,12 @@ parse_entry(char *entry, char **fields) * dhcp_symbol_t *: if non-NULL, a place to store the internal * inittab entry upon return * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN + * + * notes: IPv4 only */ + int -inittab_verify(dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent) +inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent) { unsigned int i; @@ -403,29 +476,152 @@ inittab_verify(dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent) } /* + * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID. + * The hwtype string is optional, and must be 0-65535 if + * present. + * + * input: char **: pointer to string pointer + * int *: error return value + * output: int: hardware type, or -1 for empty, or -2 for error. + */ + +static int +get_hw_type(char **strp, int *ierrnop) +{ + char *str = *strp; + ulong_t hwtype; + + if (*str++ != ',') { + *ierrnop = ITAB_BAD_NUMBER; + return (-2); + } + if (*str == ',' || *str == '\0') { + *strp = str; + return (-1); + } + hwtype = strtoul(str, strp, 0); + if (errno != 0 || *strp == str || hwtype > 65535) { + *ierrnop = ITAB_BAD_NUMBER; + return (-2); + } else { + return ((int)hwtype); + } +} + +/* + * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID. + * The 'macaddr' may be a hex string (in any standard format), + * or the name of a physical interface. If an interface name + * is given, then the interface type is extracted as well. + * + * input: const char *: input string + * int *: error return value + * uint16_t *: hardware type output (network byte order) + * int: hardware type input; -1 for empty + * uchar_t *: output buffer for MAC address + * output: int: length of MAC address, or -1 for error + */ + +static int +get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype, + uchar_t *outbuf) +{ + int fd = -1; + int maclen; + int dig, val; + dlpi_if_attr_t dia; + dl_info_ack_t dl_info; + char chr; + + if (*str != '\0') { + if (*str++ != ',') + goto failed; + if ((fd = dlpi_if_open(str, &dia, B_FALSE)) == -1) { + maclen = 0; + dig = val = 0; + /* + * Allow MAC addresses with separators matching regexp + * (:|-| *). + */ + while ((chr = *str++) != '\0') { + if (isdigit(chr)) { + val = (val << 4) + chr - '0'; + } else if (isxdigit(chr)) { + val = (val << 4) + chr - + (isupper(chr) ? 'A' : 'a') + 10; + } else if (isspace(chr) && dig == 0) { + continue; + } else if (chr == ':' || chr == '-' || + isspace(chr)) { + dig = 1; + } else { + goto failed; + } + if (++dig == 2) { + *outbuf++ = val; + maclen++; + dig = val = 0; + } + } + } else { + if (dlpi_info(fd, -1, &dl_info, NULL, NULL, NULL, + NULL, NULL, NULL) == -1) + goto failed; + maclen = dl_info.dl_addr_length - + abs(dl_info.dl_sap_length); + if (maclen > MAXADDRLEN) + goto failed; + if (dlpi_phys_addr(fd, -1, DL_CURR_PHYS_ADDR, outbuf, + NULL) == -1) + goto failed; + (void) dlpi_close(fd); + if (hwtype == -1) + hwtype = dlpi_to_arp(dl_info.dl_mac_type); + } + } + if (hwtype == -1) + goto failed; + *hwret = htons(hwtype); + return (maclen); + +failed: + if (fd != -1) + (void) dlpi_close(fd); + *ierrnop = ITAB_BAD_NUMBER; + return (-1); +} + +/* * inittab_encode_e(): converts a string representation of a given datatype into * binary; used for encoding ascii values into a form that * can be put in DHCP packets to be sent on the wire. * - * input: dhcp_symbol_t *: the entry describing the value option + * input: const dhcp_symbol_t *: the entry describing the value option * const char *: the value to convert * uint16_t *: set to the length of the binary data returned * boolean_t: if false, return a full DHCP option + * int *: error return value * output: uchar_t *: a dynamically allocated byte array with converted data */ + uchar_t * -inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, +inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, boolean_t just_payload, int *ierrnop) { - uint16_t length = 0; + int hlen = 0; + uint16_t length; uchar_t n_entries = 0; const char *valuep; char *currp; uchar_t *result = NULL; + uchar_t *optstart; unsigned int i; uint8_t type_size = inittab_type_to_size(ie); boolean_t is_signed; uint_t vallen, reslen; + dhcpv6_option_t *d6o; + int type; + char *cp2; *ierrnop = 0; if (type_size == 0) { @@ -433,60 +629,319 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, return (NULL); } - if (ie->ds_type == DSYM_ASCII) + switch (ie->ds_type) { + case DSYM_ASCII: n_entries = strlen(value); /* no NUL */ - else if (ie->ds_type == DSYM_OCTET) { + break; + + case DSYM_OCTET: vallen = strlen(value); n_entries = vallen / 2; n_entries += vallen % 2; - } else { + break; + + case DSYM_DOMAIN: + /* + * Maximum (worst-case) encoded length is one byte more than + * the number of characters on input. + */ + n_entries = strlen(value) + 1; + break; + + case DSYM_DUID: + /* Worst case is ":::::" */ + n_entries = strlen(value); + if (n_entries < MAXADDRLEN) + n_entries = MAXADDRLEN; + n_entries += sizeof (duid_llt_t); + break; + + default: /* * figure out the number of entries by counting the spaces * in the value string */ for (valuep = value; valuep++ != NULL; n_entries++) valuep = strchr(valuep, ' '); + break; } /* * if we're gonna return a complete option, then include the * option length and code in the size of the packet we allocate */ - if (just_payload == B_FALSE) - length += 2; + if (!just_payload) + hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2; - length += n_entries * type_size; - if (length > 0) - result = malloc(length); + length = n_entries * type_size; + if (hlen + length > 0) + result = malloc(hlen + length); + + if ((optstart = result) != NULL && !just_payload) + optstart += hlen; switch (ie->ds_type) { case DSYM_ASCII: - if (result == NULL) { + if (optstart == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + + (void) memcpy(optstart, value, length); + break; + + case DSYM_DOMAIN: + if (optstart == NULL) { *ierrnop = ITAB_NOMEM; return (NULL); } - if (strlen(value) > length) { + /* + * Note that this encoder always presents the trailing 0-octet + * when dealing with a list. This means that you can't have + * non-fully-qualified members anywhere but at the end of a + * list (or as the only member of the list). + */ + valuep = value; + while (*valuep != '\0') { + int dig, val, inchr; + boolean_t escape; + uchar_t *flen; + + /* + * Skip over whitespace that delimits list members. + */ + if (isascii(*valuep) && isspace(*valuep)) { + valuep++; + continue; + } + dig = val = 0; + escape = B_FALSE; + flen = optstart++; + while ((inchr = *valuep) != '\0') { + valuep++; + /* + * Just copy non-ASCII text directly to the + * output string. This simplifies the use of + * other ctype macros below, as, unlike the + * special isascii function, they don't handle + * non-ASCII. + */ + if (!isascii(inchr)) { + escape = B_FALSE; + *optstart++ = inchr; + continue; + } + if (escape) { + /* + * Handle any of \D, \DD, or \DDD for + * a digit escape. + */ + if (isdigit(inchr)) { + val = val * 10 + inchr - '0'; + if (++dig == 3) { + *optstart++ = val; + dig = val = 0; + escape = B_FALSE; + } + continue; + } else if (dig > 0) { + /* + * User terminated \D or \DD + * with non-digit. An error, + * but we can assume he means + * to treat as \00D or \0DD. + */ + *optstart++ = val; + dig = val = 0; + } + /* Fall through and copy character */ + escape = B_FALSE; + } else if (inchr == '\\') { + escape = B_TRUE; + continue; + } else if (inchr == '.') { + /* + * End of component. Write the length + * prefix. If the component is zero + * length (i.e., ".."), the just omit + * it. + */ + *flen = (optstart - flen) - 1; + if (*flen > 0) + flen = optstart++; + continue; + } else if (isspace(inchr)) { + /* + * Unescaped space; end of domain name + * in list. + */ + break; + } + *optstart++ = inchr; + } + /* + * Handle trailing escape sequence. If string ends + * with \, then assume user wants \ at end of encoded + * string. If it ends with \D or \DD, assume \00D or + * \0DD. + */ + if (escape) + *optstart++ = dig > 0 ? val : '\\'; + *flen = (optstart - flen) - 1; + /* + * If user specified FQDN with trailing '.', then above + * will result in zero for the last component length. + * We're done, and optstart already points to the start + * of the next in list. Otherwise, we need to write a + * single zero byte to end the entry, if there are more + * entries that will be decoded. + */ + while (isascii(*valuep) && isspace(*valuep)) + valuep++; + if (*flen > 0 && *valuep != '\0') + *optstart++ = '\0'; + } + length = (optstart - result) - hlen; + break; + + case DSYM_DUID: + if (optstart == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + + errno = 0; + type = strtoul(value, &currp, 0); + if (errno != 0 || value == currp || type > 65535 || + (*currp != ',' && *currp != '\0')) { free(result); - *ierrnop = ITAB_BAD_STRING; + *ierrnop = ITAB_BAD_NUMBER; return (NULL); } + switch (type) { + case DHCPV6_DUID_LLT: { + duid_llt_t dllt; + int hwtype; + ulong_t tstamp; + int maclen; + + if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { + free(result); + return (NULL); + } + if (*currp++ != ',') { + free(result); + *ierrnop = ITAB_BAD_NUMBER; + return (NULL); + } + if (*currp == ',' || *currp == '\0') { + tstamp = time(NULL) - DUID_TIME_BASE; + } else { + tstamp = strtoul(currp, &cp2, 0); + if (errno != 0 || currp == cp2) { + free(result); + *ierrnop = ITAB_BAD_NUMBER; + return (NULL); + } + currp = cp2; + } + maclen = get_mac_addr(currp, ierrnop, + &dllt.dllt_hwtype, hwtype, + optstart + sizeof (dllt)); + if (maclen == -1) { + free(result); + return (NULL); + } + dllt.dllt_dutype = htons(type); + dllt.dllt_time = htonl(tstamp); + (void) memcpy(optstart, &dllt, sizeof (dllt)); + length = maclen + sizeof (dllt); + break; + } + case DHCPV6_DUID_EN: { + duid_en_t den; + ulong_t enterp; - (void) memcpy(result, value, length); + if (*currp++ != ',') { + free(result); + *ierrnop = ITAB_BAD_NUMBER; + return (NULL); + } + enterp = strtoul(currp, &cp2, 0); + DHCPV6_SET_ENTNUM(&den, enterp); + if (errno != 0 || currp == cp2 || + enterp != DHCPV6_GET_ENTNUM(&den) || + (*cp2 != ',' && *cp2 != '\0')) { + free(result); + *ierrnop = ITAB_BAD_NUMBER; + return (NULL); + } + if (*cp2 == ',') + cp2++; + vallen = strlen(cp2); + reslen = (vallen + 1) / 2; + if (hexascii_to_octet(cp2, vallen, + optstart + sizeof (den), &reslen) != 0) { + free(result); + *ierrnop = ITAB_BAD_NUMBER; + return (NULL); + } + den.den_dutype = htons(type); + (void) memcpy(optstart, &den, sizeof (den)); + length = reslen + sizeof (den); + break; + } + case DHCPV6_DUID_LL: { + duid_ll_t dll; + int hwtype; + int maclen; + + if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { + free(result); + return (NULL); + } + maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype, + hwtype, optstart + sizeof (dll)); + if (maclen == -1) { + free(result); + return (NULL); + } + dll.dll_dutype = htons(type); + (void) memcpy(optstart, &dll, sizeof (dll)); + length = maclen + sizeof (dll); + break; + } + default: + if (*currp == ',') + currp++; + vallen = strlen(currp); + reslen = (vallen + 1) / 2; + if (hexascii_to_octet(currp, vallen, optstart + 2, + &reslen) != 0) { + free(result); + *ierrnop = ITAB_BAD_NUMBER; + return (NULL); + } + optstart[0] = type >> 8; + optstart[1] = type; + length = reslen + 2; + break; + } break; case DSYM_OCTET: - if (result == NULL) { + if (optstart == NULL) { *ierrnop = ITAB_BAD_OCTET; return (NULL); } reslen = length; /* Call libinetutil function to decode */ - if (hexascii_to_octet(value, vallen, result, &reslen) != 0) { + if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) { free(result); *ierrnop = ITAB_BAD_OCTET; return (NULL); @@ -494,8 +949,9 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, break; case DSYM_IP: + case DSYM_IPV6: - if (result == NULL) { + if (optstart == NULL) { *ierrnop = ITAB_BAD_IPADDR; return (NULL); } @@ -512,8 +968,8 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, currp = strchr(valuep, ' '); if (currp != NULL) *currp = '\0'; - if (inet_pton(AF_INET, valuep, - &result[i * sizeof (ipaddr_t)]) != 1) { + if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET : + AF_INET6, valuep, optstart) != 1) { *ierrnop = ITAB_BAD_IPADDR; inittab_msg("inittab_encode: bogus ip address"); free(result); @@ -531,6 +987,7 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, } break; } + optstart += type_size; } break; @@ -539,12 +996,13 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, case DSYM_SNUMBER8: /* FALLTHRU */ case DSYM_UNUMBER16: /* FALLTHRU */ case DSYM_SNUMBER16: /* FALLTHRU */ + case DSYM_UNUMBER24: /* FALLTHRU */ case DSYM_UNUMBER32: /* FALLTHRU */ case DSYM_SNUMBER32: /* FALLTHRU */ case DSYM_UNUMBER64: /* FALLTHRU */ case DSYM_SNUMBER64: - if (result == NULL) { + if (optstart == NULL) { *ierrnop = ITAB_BAD_NUMBER; return (NULL); } @@ -555,7 +1013,7 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, ie->ds_type == DSYM_SNUMBER8); if (encode_number(n_entries, type_size, is_signed, 0, value, - result, ierrnop) == B_FALSE) { + optstart, ierrnop) == B_FALSE) { free(result); return (NULL); } @@ -575,18 +1033,23 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, } /* - * if just_payload is false, then we need to slide the option - * code and length fields in. (length includes them in its - * count, so we have to subtract 2) + * if just_payload is false, then we need to add the option + * code and length fields in. */ - if (just_payload == B_FALSE) { - (void) memmove(result + 2, result, length - 2); - result[0] = ie->ds_code; - result[1] = length - 2; + if (!just_payload) { + if (ie->ds_dhcpv6) { + /* LINTED: alignment */ + d6o = (dhcpv6_option_t *)result; + d6o->d6o_code = htons(ie->ds_code); + d6o->d6o_len = htons(length); + } else { + result[0] = ie->ds_code; + result[1] = length; + } } if (lengthp != NULL) - *lengthp = length; + *lengthp = length + hlen; return (result); } @@ -603,16 +1066,18 @@ inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, * int *: set to extended error code if error occurs. * output: char *: a dynamically allocated string containing the converted data */ + char * -inittab_decode_e(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, - boolean_t just_payload, int *ierrnop) +inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload, + uint16_t length, boolean_t just_payload, int *ierrnop) { - char *resultp, *end, *result = NULL; - char *currp; - uchar_t n_entries; + char *resultp, *result = NULL; + uint_t n_entries; struct in_addr in_addr; + in6_addr_t in6_addr; uint8_t type_size = inittab_type_to_size(ie); boolean_t is_signed; + int type; *ierrnop = 0; if (type_size == 0) { @@ -620,9 +1085,17 @@ inittab_decode_e(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, return (NULL); } - if (just_payload == B_FALSE) { - length = payload[1]; - payload += 2; + if (!just_payload) { + if (ie->ds_dhcpv6) { + dhcpv6_option_t d6o; + + (void) memcpy(&d6o, payload, sizeof (d6o)); + length = ntohs(d6o.d6o_len); + payload += sizeof (d6o); + } else { + length = payload[1]; + payload += 2; + } } /* @@ -659,6 +1132,167 @@ inittab_decode_e(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, result[n_entries] = '\0'; break; + case DSYM_DOMAIN: + + /* + * A valid, decoded RFC 1035 domain string or sequence of + * strings is always the same size as the encoded form, but we + * allow for RFC 1035 \DDD and \\ and \. escaping. + * + * Decoding stops at the end of the input or the first coding + * violation. Coding violations result in discarding the + * offending list entry entirely. Note that we ignore the 255 + * character overall limit on domain names. + */ + if ((result = malloc(4 * length + 1)) == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + resultp = result; + while (length > 0) { + char *dstart; + int slen; + + dstart = resultp; + while (length > 0) { + slen = *payload++; + length--; + /* Upper two bits of length must be zero */ + if ((slen & 0xc0) != 0 || slen > length) { + length = 0; + resultp = dstart; + break; + } + if (resultp != dstart) + *resultp++ = '.'; + if (slen == 0) + break; + length -= slen; + while (slen > 0) { + if (!isascii(*payload) || + !isgraph(*payload)) { + (void) snprintf(resultp, 5, + "\\%03d", + *(unsigned char *)payload); + resultp += 4; + payload++; + } else { + if (*payload == '.' || + *payload == '\\') + *resultp++ = '\\'; + *resultp++ = *payload++; + } + slen--; + } + } + if (resultp != dstart && length > 0) + *resultp++ = ' '; + } + *resultp = '\0'; + break; + + case DSYM_DUID: + + /* + * First, determine the type of DUID. We need at least two + * octets worth of data to grab the type code. Once we have + * that, the number of octets required for representation + * depends on the type. + */ + + if (length < 2) { + *ierrnop = ITAB_BAD_GRAN; + return (NULL); + } + type = (payload[0] << 8) + payload[1]; + switch (type) { + case DHCPV6_DUID_LLT: { + duid_llt_t dllt; + + if (length < sizeof (dllt)) { + *ierrnop = ITAB_BAD_GRAN; + return (NULL); + } + (void) memcpy(&dllt, payload, sizeof (dllt)); + payload += sizeof (dllt); + length -= sizeof (dllt); + n_entries = sizeof ("1,65535,4294967295,") + + length * 3; + if ((result = malloc(n_entries)) == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + (void) snprintf(result, n_entries, "%d,%u,%u,", type, + ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time)); + break; + } + case DHCPV6_DUID_EN: { + duid_en_t den; + + if (length < sizeof (den)) { + *ierrnop = ITAB_BAD_GRAN; + return (NULL); + } + (void) memcpy(&den, payload, sizeof (den)); + payload += sizeof (den); + length -= sizeof (den); + n_entries = sizeof ("2,4294967295,") + length * 2; + if ((result = malloc(n_entries)) == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + (void) snprintf(result, n_entries, "%d,%u,", type, + DHCPV6_GET_ENTNUM(&den)); + break; + } + case DHCPV6_DUID_LL: { + duid_ll_t dll; + + if (length < sizeof (dll)) { + *ierrnop = ITAB_BAD_GRAN; + return (NULL); + } + (void) memcpy(&dll, payload, sizeof (dll)); + payload += sizeof (dll); + length -= sizeof (dll); + n_entries = sizeof ("3,65535,") + length * 3; + if ((result = malloc(n_entries)) == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + (void) snprintf(result, n_entries, "%d,%u,", type, + ntohs(dll.dll_hwtype)); + break; + } + default: + n_entries = sizeof ("0,") + length * 2; + if ((result = malloc(n_entries)) == NULL) { + *ierrnop = ITAB_NOMEM; + return (NULL); + } + (void) snprintf(result, n_entries, "%d,", type); + break; + } + resultp = result + strlen(result); + n_entries -= strlen(result); + if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { + if (length > 0) { + resultp += snprintf(resultp, 3, "%02X", + *payload++); + length--; + } + while (length-- > 0) { + resultp += snprintf(resultp, 4, ":%02X", + *payload++); + } + } else { + while (length-- > 0) { + resultp += snprintf(resultp, 3, "%02X", + *payload++); + } + } + break; + case DSYM_OCTET: result = malloc(n_entries * (sizeof ("0xNN") + 1)); @@ -667,50 +1301,50 @@ inittab_decode_e(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, return (NULL); } - for (resultp = result; n_entries != 0; n_entries--) { - currp = resultp; - resultp += sprintf(resultp, "0x%02X ", *payload++); - if (currp == resultp) { - free(result); - *ierrnop = ITAB_BAD_OCTET; - return (NULL); - } + result[0] = '\0'; + resultp = result; + if (n_entries > 0) { + resultp += sprintf(resultp, "0x%02X", *payload++); + n_entries--; } + while (n_entries-- > 0) + resultp += sprintf(resultp, " 0x%02X", *payload++); - resultp[-1] = '\0'; break; case DSYM_IP: - - if ((length / sizeof (ipaddr_t)) % ie->ds_gran != 0) { + case DSYM_IPV6: + if ((length / type_size) % ie->ds_gran != 0) { *ierrnop = ITAB_BAD_GRAN; inittab_msg("inittab_decode: number of entries " "not compatible with option granularity"); return (NULL); } - result = malloc(n_entries * (sizeof ("aaa.bbb.ccc.ddd") + 1)); - end = &result[n_entries * (sizeof ("aaa.bbb.ccc.ddd") + 1)]; + result = malloc(n_entries * (ie->ds_type == DSYM_IP ? + INET_ADDRSTRLEN : INET6_ADDRSTRLEN)); if (result == NULL) { *ierrnop = ITAB_NOMEM; return (NULL); } for (resultp = result; n_entries != 0; n_entries--) { - (void) memcpy(&in_addr.s_addr, payload, - sizeof (ipaddr_t)); - currp = resultp; - resultp += snprintf(resultp, end - resultp, "%s ", - inet_ntoa(in_addr)); - if (currp == resultp) { - free(result); - *ierrnop = ITAB_BAD_IPADDR; - return (NULL); + if (ie->ds_type == DSYM_IP) { + (void) memcpy(&in_addr.s_addr, payload, + sizeof (ipaddr_t)); + (void) strcpy(resultp, inet_ntoa(in_addr)); + } else { + (void) memcpy(&in6_addr, payload, + sizeof (in6_addr)); + (void) inet_ntop(AF_INET6, &in6_addr, resultp, + INET6_ADDRSTRLEN); } - payload += sizeof (ipaddr_t); + resultp += strlen(resultp); + if (n_entries > 1) + *resultp++ = ' '; + payload += type_size; } - - resultp[-1] = '\0'; + *resultp = '\0'; break; case DSYM_NUMBER: /* FALLTHRU */ @@ -761,8 +1395,9 @@ inittab_decode_e(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, * boolean_t: if false, return a full DHCP option * output: uchar_t *: a dynamically allocated byte array with converted data */ + uchar_t * -inittab_encode(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, +inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, boolean_t just_payload) { int ierrno; @@ -781,8 +1416,9 @@ inittab_encode(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, * boolean_t: if false, payload is assumed to be a DHCP option * output: char *: a dynamically allocated string containing the converted data */ + char * -inittab_decode(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, +inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length, boolean_t just_payload) { int ierrno; @@ -797,6 +1433,7 @@ inittab_decode(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, * ...: arguments to the format string * output: void */ + /*PRINTFLIKE1*/ static void inittab_msg(const char *fmt, ...) @@ -852,6 +1489,7 @@ inittab_msg(const char *fmt, ...) * char *: where to decode the numbers to * output: boolean_t: true on successful conversion, false on failure */ + static boolean_t decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, uint8_t granularity, const uint8_t *from, char *to, int *ierrnop) @@ -874,24 +1512,31 @@ decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, switch (size) { case 1: - to += sprintf(to, is_signed ? "%d " : "%u ", *from); + to += sprintf(to, is_signed ? "%d" : "%u", *from); break; case 2: (void) memcpy(&uint16, from, 2); - to += sprintf(to, is_signed ? "%hd " : "%hu ", + to += sprintf(to, is_signed ? "%hd" : "%hu", ntohs(uint16)); break; + case 3: + uint32 = 0; + (void) memcpy((uchar_t *)&uint32 + 1, from, 3); + to += sprintf(to, is_signed ? "%ld" : "%lu", + ntohl(uint32)); + break; + case 4: (void) memcpy(&uint32, from, 4); - to += sprintf(to, is_signed ? "%ld " : "%lu ", + to += sprintf(to, is_signed ? "%ld" : "%lu", ntohl(uint32)); break; case 8: (void) memcpy(&uint64, from, 8); - to += sprintf(to, is_signed ? "%lld " : "%llu ", + to += sprintf(to, is_signed ? "%lld" : "%llu", dhcp_ntohll(uint64)); break; @@ -901,9 +1546,11 @@ decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, size); return (B_FALSE); } + if (n_entries > 0) + *to++ = ' '; } - to[-1] = '\0'; + *to = '\0'; return (B_TRUE); } @@ -920,6 +1567,7 @@ decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, * int *: set to extended error code if error occurs. * output: boolean_t: true on successful conversion, false on failure */ + static boolean_t /* ARGSUSED */ encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, uint8_t granularity, const char *from, uint8_t *to, int *ierrnop) @@ -939,7 +1587,7 @@ encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, } } - for (i = 0; i < n_entries; i++, from++) { + for (i = 0; i < n_entries; i++, from++, to += size) { /* * totally obscure c factoid: it is legal to pass a @@ -954,7 +1602,7 @@ encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, switch (size) { case 1: - to[i] = strtoul(from, &endptr, 0); + *to = strtoul(from, &endptr, 0); if (errno != 0 || from == endptr) { goto error; } @@ -965,7 +1613,15 @@ encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, if (errno != 0 || from == endptr) { goto error; } - (void) memcpy(to + (i * 2), &uint16, 2); + (void) memcpy(to, &uint16, 2); + break; + + case 3: + uint32 = htonl(strtoul(from, &endptr, 0)); + if (errno != 0 || from == endptr) { + goto error; + } + (void) memcpy(to, (uchar_t *)&uint32 + 1, 3); break; case 4: @@ -973,7 +1629,7 @@ encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, if (errno != 0 || from == endptr) { goto error; } - (void) memcpy(to + (i * 4), &uint32, 4); + (void) memcpy(to, &uint32, 4); break; case 8: @@ -981,7 +1637,7 @@ encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, if (errno != 0 || from == endptr) { goto error; } - (void) memcpy(to + (i * 8), &uint64, 8); + (void) memcpy(to, &uint64, 8); break; default: @@ -1010,11 +1666,14 @@ error: * input: dhcp_symbol_t *: an entry of the given type * output: uint8_t: the size in bytes of an entry of that type */ + uint8_t -inittab_type_to_size(dhcp_symbol_t *ie) +inittab_type_to_size(const dhcp_symbol_t *ie) { switch (ie->ds_type) { + case DSYM_DUID: + case DSYM_DOMAIN: case DSYM_ASCII: case DSYM_OCTET: case DSYM_SNUMBER8: @@ -1027,6 +1686,10 @@ inittab_type_to_size(dhcp_symbol_t *ie) return (2); + case DSYM_UNUMBER24: + + return (3); + case DSYM_SNUMBER32: case DSYM_UNUMBER32: case DSYM_IP: @@ -1041,6 +1704,10 @@ inittab_type_to_size(dhcp_symbol_t *ie) case DSYM_NUMBER: return (ie->ds_gran); + + case DSYM_IPV6: + + return (sizeof (in6_addr_t)); } return (0); @@ -1053,6 +1720,7 @@ inittab_type_to_size(dhcp_symbol_t *ie) * input: uchar_t: the inittab category code * output: dsym_category_t: the dsym category code */ + static dsym_category_t itabcode_to_dsymcode(uchar_t itabcode) { @@ -1072,6 +1740,7 @@ itabcode_to_dsymcode(uchar_t itabcode) * input: const char *: the category name * output: uchar_t: its internal code (numeric representation) */ + static uchar_t category_to_code(const char *category) { @@ -1090,6 +1759,7 @@ category_to_code(const char *category) * input: uint64_t: the number to convert * output: uint64_t: its value in network byte order */ + static uint64_t dhcp_htonll(uint64_t uint64_hbo) { @@ -1102,6 +1772,7 @@ dhcp_htonll(uint64_t uint64_hbo) * input: uint64_t: the number to convert * output: uint64_t: its value in host byte order */ + static uint64_t dhcp_ntohll(uint64_t uint64_nbo) { diff --git a/usr/src/lib/libdhcputil/common/dhcp_inittab.h b/usr/src/lib/libdhcputil/common/dhcp_inittab.h index ed70ad20b4..030d057667 100644 --- a/usr/src/lib/libdhcputil/common/dhcp_inittab.h +++ b/usr/src/lib/libdhcputil/common/dhcp_inittab.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _DHCP_INITTAB_H @@ -48,6 +47,7 @@ extern "C" { * On-disk inittab attributes and limits. */ #define ITAB_INITTAB_PATH "/etc/dhcp/inittab" +#define ITAB_INITTAB6_PATH "/etc/dhcp/inittab6" #define ITAB_MAX_LINE_LEN 8192 /* bytes */ #define ITAB_MAX_NUMBER_LEN 30 /* digits */ #define ITAB_COMMENT_CHAR '#' @@ -72,7 +72,8 @@ extern "C" { #define ITAB_CAT_INTERNAL 0x04 #define ITAB_CAT_VENDOR 0x08 #define ITAB_CAT_SITE 0x10 -#define ITAB_CAT_COUNT 5 +#define ITAB_CAT_V6 0x20 +#define ITAB_CAT_COUNT 6 /* * Consumer which is using the inittab functions. @@ -96,19 +97,22 @@ extern "C" { #define ITAB_BAD_GRAN (-8) #define ITAB_NOMEM (-9) -extern uint8_t inittab_type_to_size(dhcp_symbol_t *); -extern int inittab_verify(dhcp_symbol_t *, dhcp_symbol_t *); +extern uint8_t inittab_type_to_size(const dhcp_symbol_t *); +extern int inittab_verify(const dhcp_symbol_t *, dhcp_symbol_t *); extern dhcp_symbol_t *inittab_load(uchar_t, char, size_t *); extern dhcp_symbol_t *inittab_getbyname(uchar_t, char, const char *); extern dhcp_symbol_t *inittab_getbycode(uchar_t, char, uint16_t); -extern uchar_t *inittab_encode(dhcp_symbol_t *, const char *, +extern uchar_t *inittab_encode(const dhcp_symbol_t *, const char *, uint16_t *, boolean_t); -extern uchar_t *inittab_encode_e(dhcp_symbol_t *, const char *, +extern uchar_t *inittab_encode_e(const dhcp_symbol_t *, const char *, uint16_t *, boolean_t, int *); -extern char *inittab_decode(dhcp_symbol_t *, uchar_t *, +extern char *inittab_decode(const dhcp_symbol_t *, const uchar_t *, uint16_t, boolean_t); -extern char *inittab_decode_e(dhcp_symbol_t *, uchar_t *, - uint16_t, boolean_t, int *); +extern char *inittab_decode_e(const dhcp_symbol_t *, + const uchar_t *, uint16_t, boolean_t, int *); + +/* temporary; should be in libdlpi */ +extern uint_t dlpi_to_arp(uint_t); #ifdef __cplusplus } diff --git a/usr/src/lib/libdhcputil/common/dhcp_symbol.c b/usr/src/lib/libdhcputil/common/dhcp_symbol.c index d02d3461a7..793b038d41 100644 --- a/usr/src/lib/libdhcputil/common/dhcp_symbol.c +++ b/usr/src/lib/libdhcputil/common/dhcp_symbol.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,7 +47,7 @@ typedef struct dsym_cat { ushort_t dc_max; /* maximum valid code */ } dsym_cat_t; -static dsym_cat_t cats[DSYM_CATEGORY_NUM] = { +static dsym_cat_t cats[] = { { "Extend", 6, DSYM_EXTEND, B_TRUE, DHCP_LAST_STD + 1, DHCP_SITE_OPT - 1 }, { "Vendor=", 6, DSYM_VENDOR, B_TRUE, DHCP_FIRST_OPT, @@ -72,7 +71,7 @@ typedef struct dsym_type { boolean_t dt_dhcptab; /* valid for dhcptab use? */ } dsym_type_t; -static dsym_type_t types[DSYM_CDTYPE_NUM] = { +static dsym_type_t types[] = { { "ASCII", DSYM_ASCII, B_TRUE }, { "OCTET", DSYM_OCTET, B_TRUE }, { "IP", DSYM_IP, B_TRUE }, @@ -81,12 +80,16 @@ static dsym_type_t types[DSYM_CDTYPE_NUM] = { { "INCLUDE", DSYM_INCLUDE, B_FALSE }, { "UNUMBER8", DSYM_UNUMBER8, B_TRUE }, { "UNUMBER16", DSYM_UNUMBER16, B_TRUE }, + { "UNUMBER24", DSYM_UNUMBER24, B_TRUE }, { "UNUMBER32", DSYM_UNUMBER32, B_TRUE }, { "UNUMBER64", DSYM_UNUMBER64, B_TRUE }, { "SNUMBER8", DSYM_SNUMBER8, B_TRUE }, { "SNUMBER16", DSYM_SNUMBER16, B_TRUE }, { "SNUMBER32", DSYM_SNUMBER32, B_TRUE }, - { "SNUMBER64", DSYM_SNUMBER64, B_TRUE } + { "SNUMBER64", DSYM_SNUMBER64, B_TRUE }, + { "IPV6", DSYM_IPV6, B_TRUE }, + { "DUID", DSYM_DUID, B_TRUE }, + { "DOMAIN", DSYM_DOMAIN, B_TRUE } }; /* @@ -103,6 +106,7 @@ static dsym_type_t types[DSYM_CDTYPE_NUM] = { * input: char **: a pointer to a string to trim of whitespace. * output: none */ + static void dsym_trim(char **str) { @@ -153,6 +157,7 @@ dsym_trim(char **str) * boolean_t: should delimiters be ignored if within quoted string? * output: char *: token, or NULL if no more tokens */ + static char * dsym_get_token(char *str, char *dels, char **lasts, boolean_t quote_support) { @@ -214,6 +219,7 @@ dsym_get_token(char *str, char *dels, char **lasts, boolean_t quote_support) * long *: the return location for the long value * output: DSYM_SUCCESS, DSYM_VALUE_OUT_OF_RANGE or DSYM_SYNTAX_ERROR */ + static dsym_errcode_t dsym_get_long(const char *str, long *val) { @@ -242,6 +248,7 @@ dsym_get_long(const char *str, long *val) * input: dhcp_classes_t *: pointer to structure containing classes to free * output: none */ + void dsym_free_classes(dhcp_classes_t *classes) { @@ -270,6 +277,7 @@ dsym_free_classes(dhcp_classes_t *classes) * output: DSYM_SUCCESS, DSYM_INVALID_CAT, DSYM_EXCEEDS_MAX_CLASS_SIZE, * DSYM_EXCEEDS_CLASS_SIZE, DSYM_SYNTAX_ERROR, or DSYM_NO_MEMORY */ + static dsym_errcode_t dsym_parse_classes(char *ptr, dhcp_classes_t *classes_ret) { @@ -352,6 +360,7 @@ dsym_parse_classes(char *ptr, dhcp_classes_t *classes_ret) * boolean_t: case-sensitive name compare * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT */ + static dsym_errcode_t dsym_get_cat_by_name(const char *cat, dsym_cat_t **entry, boolean_t cs) { @@ -416,6 +425,7 @@ dsym_get_cat_by_name(const char *cat, dsym_cat_t **entry, boolean_t cs) * dsym_category_t *: the return location for the category value * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT */ + static dsym_errcode_t dsym_parse_cat(const char *field, dsym_category_t *cat) { @@ -449,6 +459,7 @@ dsym_parse_cat(const char *field, dsym_category_t *cat) * int: the maximum valid value * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, or DSYM_VALUE_OUT_OF_RANGE */ + static dsym_errcode_t dsym_parse_intrange(const char *field, int *intval, int min, int max) { @@ -475,6 +486,7 @@ dsym_parse_intrange(const char *field, int *intval, int min, int max) * uint16_t: the symbol code * output: DSYM_SUCCESS, DSYM_INVALID_CAT or DSYM_CODE_OUT_OF_RANGE */ + static dsym_errcode_t dsym_validate_code(dsym_category_t cat, ushort_t code) { @@ -507,6 +519,7 @@ dsym_validate_code(dsym_category_t cat, ushort_t code) * uchar_t: the symbol granularity * output: DSYM_SUCCESS or DSYM_VALUE_OUT_OF_RANGE */ + static dsym_errcode_t dsym_validate_granularity(dsym_cdtype_t type, uchar_t gran) { @@ -530,6 +543,7 @@ dsym_validate_granularity(dsym_cdtype_t type, uchar_t gran) * boolean_t: case-sensitive name compare * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE */ + static dsym_errcode_t dsym_get_type_by_name(const char *type, dsym_type_t **entry, boolean_t cs) { @@ -561,6 +575,7 @@ dsym_get_type_by_name(const char *type, dsym_type_t **entry, boolean_t cs) * dsym_cdtype_t *: the return location for the type id * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE */ + static dsym_errcode_t dsym_parse_type(char *field, dsym_cdtype_t *type) { @@ -592,6 +607,7 @@ dsym_parse_type(char *field, dsym_cdtype_t *type) * input: char **: array of fields to free * output: none */ + void dsym_free_fields(char **fields) { @@ -611,6 +627,7 @@ dsym_free_fields(char **fields) * dhcp_symbol_t *: the structure populated by dsym_init_parser() * output: none */ + void dsym_close_parser(char **fields, dhcp_symbol_t *sym) { @@ -630,6 +647,7 @@ dsym_close_parser(char **fields, dhcp_symbol_t *sym) * output: int: DSYM_SUCCESS, DYSM_NO_MEMORY, DSYM_NULL_FIELD or * DSYM_TOO_MANY_FIELDS */ + dsym_errcode_t dsym_init_parser(const char *name, const char *value, char ***fields_ret, dhcp_symbol_t *sym) @@ -710,6 +728,7 @@ dsym_init_parser(const char *name, const char *value, char ***fields_ret, * DSYM_EXCEEDS_MAX_CLASS_SIZE, DSYM_NO_MEMORY, * DSYM_INVALID_FIELD_NUM, DSYM_VALUE_OUT_OF_RANGE */ + dsym_errcode_t dsym_parse_field(int field_num, char **fields, dhcp_symbol_t *sym) { @@ -778,6 +797,7 @@ dsym_parse_field(int field_num, char **fields, dhcp_symbol_t *sym) * DSYM_EXCEEDS_MAX_CLASS_SIZE, DSYM_NO_MEMORY * DSYM_INVALID_FIELD_NUM, DSYM_VALUE_OUT_OF_RANGE */ + dsym_errcode_t dsym_parser(char **fields, dhcp_symbol_t *sym, int *lastField, boolean_t bestEffort) @@ -818,6 +838,7 @@ dsym_parser(char **fields, dhcp_symbol_t *sym, int *lastField, * boolean_t: case-sensitive name compare * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT */ + dsym_errcode_t dsym_get_cat_id(const char *cat, dsym_category_t *id, boolean_t cs) { @@ -843,6 +864,7 @@ dsym_get_cat_id(const char *cat, dsym_category_t *id, boolean_t cs) * boolean_t: case-sensitive name compare * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT */ + dsym_errcode_t dsym_get_code_ranges(const char *cat, ushort_t *min, ushort_t *max, boolean_t cs) @@ -868,6 +890,7 @@ dsym_get_code_ranges(const char *cat, ushort_t *min, ushort_t *max, * boolean_t: case-sensitive name compare * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE */ + dsym_errcode_t dsym_get_type_id(const char *type, dsym_cdtype_t *id, boolean_t cs) { diff --git a/usr/src/lib/libdhcputil/common/dhcp_symbol.h b/usr/src/lib/libdhcputil/common/dhcp_symbol.h index fcfd65c20f..0e153457e4 100644 --- a/usr/src/lib/libdhcputil/common/dhcp_symbol.h +++ b/usr/src/lib/libdhcputil/common/dhcp_symbol.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -99,6 +98,8 @@ typedef struct dhcp_classes { * This structure is used to define a DHCP symbol. The structure is * used by both the inittab parsing routines and by the dhcptab parsing * routines to define a symbol definition in either of those tables. + * Note that ds_dhcpv6 is defined last so that it needn't be initialized + * as part of the inittab_table[] definition. */ typedef struct dhcp_symbol { dsym_category_t ds_category; /* category */ @@ -108,6 +109,7 @@ typedef struct dhcp_symbol { uchar_t ds_gran; /* granularity */ uchar_t ds_max; /* maximum number */ dhcp_classes_t ds_classes; /* client classes */ + uchar_t ds_dhcpv6; /* dhcpv6 flag */ } dhcp_symbol_t; extern void dsym_free_fields(char **); diff --git a/usr/src/lib/libdhcputil/common/dhcpmsg.c b/usr/src/lib/libdhcputil/common/dhcpmsg.c index 5329af5fbf..9e4aec5ded 100644 --- a/usr/src/lib/libdhcputil/common/dhcpmsg.c +++ b/usr/src/lib/libdhcputil/common/dhcpmsg.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,7 +52,6 @@ static int err_to_syslog(int); * output: void */ -/*PRINTFLIKE2*/ void dhcpmsg(int errlevel, const char *fmt, ...) { diff --git a/usr/src/lib/libdhcputil/common/dhcpmsg.h b/usr/src/lib/libdhcputil/common/dhcpmsg.h index 822359cd46..2dad24040a 100644 --- a/usr/src/lib/libdhcputil/common/dhcpmsg.h +++ b/usr/src/lib/libdhcputil/common/dhcpmsg.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,14 +19,14 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _DHCPMSG_H #define _DHCPMSG_H -#pragma ident "%W% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" #include <sys/types.h> #include <stdarg.h> @@ -63,6 +62,7 @@ enum { MSG_CRIT /* LOG_CRIT */ }; +/* PRINTFLIKE2 */ extern void dhcpmsg(int, const char *, ...); extern void dhcpmsg_init(const char *, boolean_t, boolean_t, int); extern void dhcpmsg_fini(void); diff --git a/usr/src/lib/libdhcputil/common/mapfile-vers b/usr/src/lib/libdhcputil/common/mapfile-vers index 65d36e67d5..851b69b1b7 100644 --- a/usr/src/lib/libdhcputil/common/mapfile-vers +++ b/usr/src/lib/libdhcputil/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -31,6 +31,9 @@ SUNWprivate_1.2 { global: dhcp_options_scan; + dhcpv6_find_option; + dhcpv6_pkt_option; + dlpi_to_arp; } SUNWprivate_1.1; SUNWprivate_1.1 { diff --git a/usr/src/lib/libxnet/Makefile.com b/usr/src/lib/libxnet/Makefile.com index 93134f8b63..0e905e3ca3 100644 --- a/usr/src/lib/libxnet/Makefile.com +++ b/usr/src/lib/libxnet/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -41,6 +41,7 @@ LIBS= $(DYNLIB) $(LINTLIB) $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) +CPPFLAGS += -D__EXTENSIONS__ CFLAGS += $(CCVERBOSE) DYNFLAGS += $(ZLOADFLTR) |
