xref: /titanic_44/usr/src/cmd/cmd-inet/sbin/dhcpagent/adopt.c (revision dc918d99d74acfa24794f5fa3796e4f4c88eac23)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5dc041e83Scarlsonj  * Common Development and Distribution License (the "License").
6dc041e83Scarlsonj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*dc918d99Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  *
25d04ccbb3Scarlsonj  * ADOPTING state of the client state machine.  This is used only during
26d04ccbb3Scarlsonj  * diskless boot with IPv4.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
33dc041e83Scarlsonj #include <signal.h>
347c478bd9Sstevel@tonic-gate #include <sys/socket.h>
35d04ccbb3Scarlsonj #include <net/if_arp.h>
367c478bd9Sstevel@tonic-gate #include <netinet/in.h>
377c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
387c478bd9Sstevel@tonic-gate #include <netinet/inetutil.h>
397c478bd9Sstevel@tonic-gate #include <netinet/dhcp.h>
407c478bd9Sstevel@tonic-gate #include <dhcpmsg.h>
41d04ccbb3Scarlsonj #include <libdevinfo.h>
427c478bd9Sstevel@tonic-gate 
43d04ccbb3Scarlsonj #include "agent.h"
447c478bd9Sstevel@tonic-gate #include "async.h"
457c478bd9Sstevel@tonic-gate #include "util.h"
467c478bd9Sstevel@tonic-gate #include "packet.h"
477c478bd9Sstevel@tonic-gate #include "interface.h"
487c478bd9Sstevel@tonic-gate #include "states.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate typedef struct {
527c478bd9Sstevel@tonic-gate 	char		dk_if_name[IFNAMSIZ];
537c478bd9Sstevel@tonic-gate 	char		dk_ack[1];
547c478bd9Sstevel@tonic-gate } dhcp_kcache_t;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static int	get_dhcp_kcache(dhcp_kcache_t **, size_t *);
577c478bd9Sstevel@tonic-gate 
58d04ccbb3Scarlsonj static boolean_t	get_prom_prop(const char *, const char *, uchar_t **,
59d04ccbb3Scarlsonj 			    uint_t *);
60d04ccbb3Scarlsonj 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * dhcp_adopt(): adopts the interface managed by the kernel for diskless boot
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  *   input: void
65d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE success, B_FALSE on failure
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate 
68d04ccbb3Scarlsonj boolean_t
dhcp_adopt(void)697c478bd9Sstevel@tonic-gate dhcp_adopt(void)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	int		retval;
727c478bd9Sstevel@tonic-gate 	dhcp_kcache_t	*kcache = NULL;
737c478bd9Sstevel@tonic-gate 	size_t		kcache_size;
747c478bd9Sstevel@tonic-gate 	PKT_LIST	*plp = NULL;
75d04ccbb3Scarlsonj 	dhcp_lif_t	*lif;
76d04ccbb3Scarlsonj 	dhcp_smach_t	*dsmp = NULL;
77d04ccbb3Scarlsonj 	uint_t		client_id_len;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	retval = get_dhcp_kcache(&kcache, &kcache_size);
807c478bd9Sstevel@tonic-gate 	if (retval == 0 || kcache_size < sizeof (dhcp_kcache_t)) {
817c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot fetch kernel cache");
827c478bd9Sstevel@tonic-gate 		goto failure;
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG, "dhcp_adopt: fetched %s kcache", kcache->dk_if_name);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	/*
887c478bd9Sstevel@tonic-gate 	 * convert the kernel's ACK into binary
897c478bd9Sstevel@tonic-gate 	 */
907c478bd9Sstevel@tonic-gate 
91d04ccbb3Scarlsonj 	plp = alloc_pkt_entry(strlen(kcache->dk_ack) / 2, B_FALSE);
927c478bd9Sstevel@tonic-gate 	if (plp == NULL)
937c478bd9Sstevel@tonic-gate 		goto failure;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG, "dhcp_adopt: allocated ACK of %d bytes", plp->len);
967c478bd9Sstevel@tonic-gate 
97d04ccbb3Scarlsonj 	if (hexascii_to_octet(kcache->dk_ack, plp->len * 2, plp->pkt,
98d04ccbb3Scarlsonj 	    &plp->len) != 0) {
997c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot convert kernel ACK");
1007c478bd9Sstevel@tonic-gate 		goto failure;
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if (dhcp_options_scan(plp, B_TRUE) != 0) {
1047c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot parse kernel ACK");
1057c478bd9Sstevel@tonic-gate 		goto failure;
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/*
1097c478bd9Sstevel@tonic-gate 	 * make an interface to represent the "cached interface" in
1107c478bd9Sstevel@tonic-gate 	 * the kernel, hook up the ACK packet we made, and send out
1117c478bd9Sstevel@tonic-gate 	 * the extend request (to attempt to renew the lease).
1127c478bd9Sstevel@tonic-gate 	 *
1137c478bd9Sstevel@tonic-gate 	 * we do a send_extend() instead of doing a dhcp_init_reboot()
1147c478bd9Sstevel@tonic-gate 	 * because although dhcp_init_reboot() is more correct from a
1157c478bd9Sstevel@tonic-gate 	 * protocol perspective, it introduces a window where a
1167c478bd9Sstevel@tonic-gate 	 * diskless client has no IP address but may need to page in
1177c478bd9Sstevel@tonic-gate 	 * more of this program.  we could mlockall(), but that's
1187c478bd9Sstevel@tonic-gate 	 * going to be a mess, especially with handling malloc() and
1197c478bd9Sstevel@tonic-gate 	 * stack growth, so it's easier to just renew().  the only
1207c478bd9Sstevel@tonic-gate 	 * catch here is that if we are not granted a renewal, we're
1217c478bd9Sstevel@tonic-gate 	 * totally hosed and can only bail out.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 
124d04ccbb3Scarlsonj 	if ((lif = attach_lif(kcache->dk_if_name, B_FALSE, &retval)) == NULL) {
125d04ccbb3Scarlsonj 		dhcpmsg(MSG_ERROR, "dhcp_adopt: unable to attach %s: %d",
126d04ccbb3Scarlsonj 		    kcache->dk_if_name, retval);
127d04ccbb3Scarlsonj 		goto failure;
128d04ccbb3Scarlsonj 	}
129d04ccbb3Scarlsonj 
130d04ccbb3Scarlsonj 	if ((dsmp = insert_smach(lif, &retval)) == NULL) {
131d04ccbb3Scarlsonj 		dhcpmsg(MSG_ERROR, "dhcp_adopt: unable to create state "
132d04ccbb3Scarlsonj 		    "machine for %s: %d", kcache->dk_if_name, retval);
133d04ccbb3Scarlsonj 		goto failure;
134d04ccbb3Scarlsonj 	}
135d04ccbb3Scarlsonj 
136d04ccbb3Scarlsonj 	/*
137d04ccbb3Scarlsonj 	 * If the agent is adopting a lease, then OBP is initially
138d04ccbb3Scarlsonj 	 * searched for a client-id.
139d04ccbb3Scarlsonj 	 */
140d04ccbb3Scarlsonj 
141d04ccbb3Scarlsonj 	dhcpmsg(MSG_DEBUG, "dhcp_adopt: getting /chosen:clientid property");
142d04ccbb3Scarlsonj 
143d04ccbb3Scarlsonj 	client_id_len = 0;
144d04ccbb3Scarlsonj 	if (!get_prom_prop("chosen", "client-id", &dsmp->dsm_cid,
145d04ccbb3Scarlsonj 	    &client_id_len)) {
146d04ccbb3Scarlsonj 		/*
147d04ccbb3Scarlsonj 		 * a failure occurred trying to acquire the client-id
148d04ccbb3Scarlsonj 		 */
149d04ccbb3Scarlsonj 
150d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG,
151d04ccbb3Scarlsonj 		    "dhcp_adopt: cannot allocate client id for %s",
152d04ccbb3Scarlsonj 		    dsmp->dsm_name);
153d04ccbb3Scarlsonj 		goto failure;
154d04ccbb3Scarlsonj 	} else if (dsmp->dsm_hwtype == ARPHRD_IB && dsmp->dsm_cid == NULL) {
155d04ccbb3Scarlsonj 		/*
156d04ccbb3Scarlsonj 		 * when the interface is infiniband and the agent
157d04ccbb3Scarlsonj 		 * is adopting the lease there must be an OBP
158d04ccbb3Scarlsonj 		 * client-id.
159d04ccbb3Scarlsonj 		 */
160d04ccbb3Scarlsonj 
161d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "dhcp_adopt: no /chosen:clientid id for %s",
162d04ccbb3Scarlsonj 		    dsmp->dsm_name);
163d04ccbb3Scarlsonj 		goto failure;
164d04ccbb3Scarlsonj 	}
165d04ccbb3Scarlsonj 
166d04ccbb3Scarlsonj 	dsmp->dsm_cidlen = client_id_len;
167d04ccbb3Scarlsonj 
168*dc918d99Smeem 	if (set_lif_dhcp(lif) != DHCP_IPC_SUCCESS)
1697c478bd9Sstevel@tonic-gate 		goto failure;
1707c478bd9Sstevel@tonic-gate 
171d04ccbb3Scarlsonj 	if (!set_smach_state(dsmp, ADOPTING))
172d04ccbb3Scarlsonj 		goto failure;
173d04ccbb3Scarlsonj 	dsmp->dsm_dflags = DHCP_IF_PRIMARY;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	/*
176dc041e83Scarlsonj 	 * move to BOUND and use the information in our ACK packet.
177dc041e83Scarlsonj 	 * adoption will continue after DAD via dhcp_adopt_complete.
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 
180d04ccbb3Scarlsonj 	if (!dhcp_bound(dsmp, plp)) {
1817c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot use cached packet");
1827c478bd9Sstevel@tonic-gate 		goto failure;
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	free(kcache);
186d04ccbb3Scarlsonj 	return (B_TRUE);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate failure:
189d04ccbb3Scarlsonj 	/* Note: no need to free lif; dsmp holds reference */
190d04ccbb3Scarlsonj 	if (dsmp != NULL)
1913589885cScarlsonj 		remove_smach(dsmp);
1927c478bd9Sstevel@tonic-gate 	free(kcache);
193d04ccbb3Scarlsonj 	free_pkt_entry(plp);
194d04ccbb3Scarlsonj 	return (B_FALSE);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
198dc041e83Scarlsonj  * dhcp_adopt_complete(): completes interface adoption process after kernel
199dc041e83Scarlsonj  *			  duplicate address detection (DAD) is done.
200dc041e83Scarlsonj  *
201d04ccbb3Scarlsonj  *   input: dhcp_smach_t *: the state machine on which a lease is being adopted
202dc041e83Scarlsonj  *  output: none
203dc041e83Scarlsonj  */
204dc041e83Scarlsonj 
205dc041e83Scarlsonj void
dhcp_adopt_complete(dhcp_smach_t * dsmp)206d04ccbb3Scarlsonj dhcp_adopt_complete(dhcp_smach_t *dsmp)
207dc041e83Scarlsonj {
208dc041e83Scarlsonj 	dhcpmsg(MSG_DEBUG, "dhcp_adopt_complete: completing adoption");
209dc041e83Scarlsonj 
210d04ccbb3Scarlsonj 	if (async_start(dsmp, DHCP_EXTEND, B_FALSE) == 0) {
211dc041e83Scarlsonj 		dhcpmsg(MSG_CRIT, "dhcp_adopt_complete: async_start failed");
212dc041e83Scarlsonj 		return;
213dc041e83Scarlsonj 	}
214dc041e83Scarlsonj 
215d04ccbb3Scarlsonj 	if (dhcp_extending(dsmp) == 0) {
216dc041e83Scarlsonj 		dhcpmsg(MSG_CRIT,
217dc041e83Scarlsonj 		    "dhcp_adopt_complete: cannot send renew request");
218dc041e83Scarlsonj 		return;
219dc041e83Scarlsonj 	}
220dc041e83Scarlsonj 
221dc041e83Scarlsonj 	if (grandparent != (pid_t)0) {
222d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "adoption complete, signalling parent (%ld)"
223dc041e83Scarlsonj 		    " to exit.", grandparent);
224dc041e83Scarlsonj 		(void) kill(grandparent, SIGALRM);
225dc041e83Scarlsonj 	}
226dc041e83Scarlsonj }
227dc041e83Scarlsonj 
228dc041e83Scarlsonj /*
2297c478bd9Sstevel@tonic-gate  * get_dhcp_kcache(): fetches the DHCP ACK and interface name from the kernel
2307c478bd9Sstevel@tonic-gate  *
2317c478bd9Sstevel@tonic-gate  *   input: dhcp_kcache_t **: a dynamically-allocated cache packet
2327c478bd9Sstevel@tonic-gate  *	    size_t *: the length of that packet (on return)
2337c478bd9Sstevel@tonic-gate  *  output: int: nonzero on success, zero on failure
2347c478bd9Sstevel@tonic-gate  */
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate static int
get_dhcp_kcache(dhcp_kcache_t ** kernel_cachep,size_t * kcache_size)2377c478bd9Sstevel@tonic-gate get_dhcp_kcache(dhcp_kcache_t **kernel_cachep, size_t *kcache_size)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	char	dummy;
2407c478bd9Sstevel@tonic-gate 	long	size;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	size = sysinfo(SI_DHCP_CACHE, &dummy, sizeof (dummy));
2437c478bd9Sstevel@tonic-gate 	if (size == -1)
2447c478bd9Sstevel@tonic-gate 		return (0);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	*kcache_size   = size;
2477c478bd9Sstevel@tonic-gate 	*kernel_cachep = malloc(*kcache_size);
2487c478bd9Sstevel@tonic-gate 	if (*kernel_cachep == NULL)
2497c478bd9Sstevel@tonic-gate 		return (0);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	(void) sysinfo(SI_DHCP_CACHE, (caddr_t)*kernel_cachep, size);
2527c478bd9Sstevel@tonic-gate 	return (1);
2537c478bd9Sstevel@tonic-gate }
254d04ccbb3Scarlsonj 
255d04ccbb3Scarlsonj /*
256d04ccbb3Scarlsonj  * get_prom_prop(): get the value of the named property on the named node in
257d04ccbb3Scarlsonj  *		    devinfo root.
258d04ccbb3Scarlsonj  *
259d04ccbb3Scarlsonj  *   input: const char *: The name of the node containing the property.
260d04ccbb3Scarlsonj  *	    const char *: The name of the property.
261d04ccbb3Scarlsonj  *	    uchar_t **: The property value, modified iff B_TRUE is returned.
262d04ccbb3Scarlsonj  *                      If no value is found the value is set to NULL.
263d04ccbb3Scarlsonj  *	    uint_t *: The length of the property value
264d04ccbb3Scarlsonj  *  output: boolean_t: Returns B_TRUE if successful (no problems),
265d04ccbb3Scarlsonj  *                     otherwise B_FALSE.
266d04ccbb3Scarlsonj  *    note: The memory allocated by this function must be freed by
267d04ccbb3Scarlsonj  *          the caller. This code is derived from
268d04ccbb3Scarlsonj  *          usr/src/lib/libwanboot/common/bootinfo_aux.c.
269d04ccbb3Scarlsonj  */
270d04ccbb3Scarlsonj 
271d04ccbb3Scarlsonj static boolean_t
get_prom_prop(const char * nodename,const char * propname,uchar_t ** propvaluep,uint_t * lenp)272d04ccbb3Scarlsonj get_prom_prop(const char *nodename, const char *propname, uchar_t **propvaluep,
273d04ccbb3Scarlsonj     uint_t *lenp)
274d04ccbb3Scarlsonj {
275d04ccbb3Scarlsonj 	di_node_t		root_node;
276d04ccbb3Scarlsonj 	di_node_t		node;
277d04ccbb3Scarlsonj 	di_prom_handle_t	phdl = DI_PROM_HANDLE_NIL;
278d04ccbb3Scarlsonj 	di_prom_prop_t		pp;
279d04ccbb3Scarlsonj 	uchar_t			*value = NULL;
280d04ccbb3Scarlsonj 	unsigned int		len = 0;
281d04ccbb3Scarlsonj 	boolean_t		success = B_TRUE;
282d04ccbb3Scarlsonj 
283d04ccbb3Scarlsonj 	/*
284d04ccbb3Scarlsonj 	 * locate root node
285d04ccbb3Scarlsonj 	 */
286d04ccbb3Scarlsonj 
287d04ccbb3Scarlsonj 	if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL ||
288d04ccbb3Scarlsonj 	    (phdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
289d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property root node "
290d04ccbb3Scarlsonj 		    "not found");
291d04ccbb3Scarlsonj 		goto get_prom_prop_cleanup;
292d04ccbb3Scarlsonj 	}
293d04ccbb3Scarlsonj 
294d04ccbb3Scarlsonj 	/*
295d04ccbb3Scarlsonj 	 * locate nodename within '/'
296d04ccbb3Scarlsonj 	 */
297d04ccbb3Scarlsonj 
298d04ccbb3Scarlsonj 	for (node = di_child_node(root_node);
299d04ccbb3Scarlsonj 	    node != DI_NODE_NIL;
300d04ccbb3Scarlsonj 	    node = di_sibling_node(node)) {
301d04ccbb3Scarlsonj 		if (strcmp(di_node_name(node), nodename) == 0) {
302d04ccbb3Scarlsonj 			break;
303d04ccbb3Scarlsonj 		}
304d04ccbb3Scarlsonj 	}
305d04ccbb3Scarlsonj 
306d04ccbb3Scarlsonj 	if (node == DI_NODE_NIL) {
307d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "get_prom_prop: node not found");
308d04ccbb3Scarlsonj 		goto get_prom_prop_cleanup;
309d04ccbb3Scarlsonj 	}
310d04ccbb3Scarlsonj 
311d04ccbb3Scarlsonj 	/*
312d04ccbb3Scarlsonj 	 * scan all properties of /nodename for the 'propname' property
313d04ccbb3Scarlsonj 	 */
314d04ccbb3Scarlsonj 
315d04ccbb3Scarlsonj 	for (pp = di_prom_prop_next(phdl, node, DI_PROM_PROP_NIL);
316d04ccbb3Scarlsonj 	    pp != DI_PROM_PROP_NIL;
317d04ccbb3Scarlsonj 	    pp = di_prom_prop_next(phdl, node, pp)) {
318d04ccbb3Scarlsonj 
319d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property = %s",
320d04ccbb3Scarlsonj 		    di_prom_prop_name(pp));
321d04ccbb3Scarlsonj 
322d04ccbb3Scarlsonj 		if (strcmp(propname, di_prom_prop_name(pp)) == 0) {
323d04ccbb3Scarlsonj 			break;
324d04ccbb3Scarlsonj 		}
325d04ccbb3Scarlsonj 	}
326d04ccbb3Scarlsonj 
327d04ccbb3Scarlsonj 	if (pp == DI_PROM_PROP_NIL) {
328d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property not found");
329d04ccbb3Scarlsonj 		goto get_prom_prop_cleanup;
330d04ccbb3Scarlsonj 	}
331d04ccbb3Scarlsonj 
332d04ccbb3Scarlsonj 	/*
333d04ccbb3Scarlsonj 	 * get the property; allocate some memory copy it out
334d04ccbb3Scarlsonj 	 */
335d04ccbb3Scarlsonj 
336d04ccbb3Scarlsonj 	len = di_prom_prop_data(pp, (uchar_t **)&value);
337d04ccbb3Scarlsonj 
338d04ccbb3Scarlsonj 	if (value == NULL) {
339d04ccbb3Scarlsonj 		/*
340d04ccbb3Scarlsonj 		 * property data read problems
341d04ccbb3Scarlsonj 		 */
342d04ccbb3Scarlsonj 
343d04ccbb3Scarlsonj 		success = B_FALSE;
344d04ccbb3Scarlsonj 		dhcpmsg(MSG_ERR, "get_prom_prop: cannot read property data");
345d04ccbb3Scarlsonj 		goto get_prom_prop_cleanup;
346d04ccbb3Scarlsonj 	}
347d04ccbb3Scarlsonj 
348d04ccbb3Scarlsonj 	if (propvaluep != NULL) {
349d04ccbb3Scarlsonj 		/*
350d04ccbb3Scarlsonj 		 * allocate somewhere to copy the property value to
351d04ccbb3Scarlsonj 		 */
352d04ccbb3Scarlsonj 
353d04ccbb3Scarlsonj 		*propvaluep = calloc(len, sizeof (uchar_t));
354d04ccbb3Scarlsonj 
355d04ccbb3Scarlsonj 		if (*propvaluep == NULL) {
356d04ccbb3Scarlsonj 			/*
357d04ccbb3Scarlsonj 			 * allocation problems
358d04ccbb3Scarlsonj 			 */
359d04ccbb3Scarlsonj 
360d04ccbb3Scarlsonj 			success = B_FALSE;
361d04ccbb3Scarlsonj 			dhcpmsg(MSG_ERR, "get_prom_prop: cannot allocate "
362d04ccbb3Scarlsonj 			    "memory for property value");
363d04ccbb3Scarlsonj 			goto get_prom_prop_cleanup;
364d04ccbb3Scarlsonj 		}
365d04ccbb3Scarlsonj 
366d04ccbb3Scarlsonj 		/*
367d04ccbb3Scarlsonj 		 * copy data out
368d04ccbb3Scarlsonj 		 */
369d04ccbb3Scarlsonj 
370d04ccbb3Scarlsonj 		(void) memcpy(*propvaluep, value, len);
371d04ccbb3Scarlsonj 
372d04ccbb3Scarlsonj 		/*
373d04ccbb3Scarlsonj 		 * copy out the length if a suitable pointer has
374d04ccbb3Scarlsonj 		 * been supplied
375d04ccbb3Scarlsonj 		 */
376d04ccbb3Scarlsonj 
377d04ccbb3Scarlsonj 		if (lenp != NULL) {
378d04ccbb3Scarlsonj 			*lenp = len;
379d04ccbb3Scarlsonj 		}
380d04ccbb3Scarlsonj 
381d04ccbb3Scarlsonj 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property value "
382d04ccbb3Scarlsonj 		    "length = %d", len);
383d04ccbb3Scarlsonj 	}
384d04ccbb3Scarlsonj 
385d04ccbb3Scarlsonj get_prom_prop_cleanup:
386d04ccbb3Scarlsonj 
387d04ccbb3Scarlsonj 	if (phdl != DI_PROM_HANDLE_NIL) {
388d04ccbb3Scarlsonj 		di_prom_fini(phdl);
389d04ccbb3Scarlsonj 	}
390d04ccbb3Scarlsonj 
391d04ccbb3Scarlsonj 	if (root_node != DI_NODE_NIL) {
392d04ccbb3Scarlsonj 		di_fini(root_node);
393d04ccbb3Scarlsonj 	}
394d04ccbb3Scarlsonj 
395d04ccbb3Scarlsonj 	return (success);
396d04ccbb3Scarlsonj }
397