xref: /titanic_51/usr/src/lib/libwanboot/common/bootinfo_aux.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <dhcp_impl.h>
32*7c478bd9Sstevel@tonic-gate #include <netinet/inetutil.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
34*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
35*7c478bd9Sstevel@tonic-gate #include <strings.h>
36*7c478bd9Sstevel@tonic-gate #include <net/if.h>
37*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
39*7c478bd9Sstevel@tonic-gate #include <unistd.h>
40*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
41*7c478bd9Sstevel@tonic-gate #include <netdb.h>
42*7c478bd9Sstevel@tonic-gate #include <alloca.h>
43*7c478bd9Sstevel@tonic-gate #include <stdio.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
47*7c478bd9Sstevel@tonic-gate #include <bootinfo.h>
48*7c478bd9Sstevel@tonic-gate #include <bootinfo_aux.h>
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #define	MAXIFS	256	/* default max number of interfaces */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * Callback structure used when walking the device tree.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate typedef struct {
56*7c478bd9Sstevel@tonic-gate 	char		*cb_path;	/* device path we want to match */
57*7c478bd9Sstevel@tonic-gate 	di_node_t	cb_node;	/* found leaf node of device path */
58*7c478bd9Sstevel@tonic-gate } cb_t;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * Handles on devinfo stuff.
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate static di_node_t	root_node = DI_NODE_NIL;
64*7c478bd9Sstevel@tonic-gate static di_prom_handle_t	phdl = DI_PROM_HANDLE_NIL;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /*
67*7c478bd9Sstevel@tonic-gate  * Root filesystem type string.
68*7c478bd9Sstevel@tonic-gate  */
69*7c478bd9Sstevel@tonic-gate static char *rootfs_type = NULL;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * Handles on DHCP's packet list and interface-name.
73*7c478bd9Sstevel@tonic-gate  */
74*7c478bd9Sstevel@tonic-gate static PKT_LIST	*dhcp_pl = NULL;
75*7c478bd9Sstevel@tonic-gate static char	dhcp_ifn[IFNAMSIZ + 1];
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate /*
78*7c478bd9Sstevel@tonic-gate  * Deallocate dhcp_pl.
79*7c478bd9Sstevel@tonic-gate  */
80*7c478bd9Sstevel@tonic-gate static void
81*7c478bd9Sstevel@tonic-gate dhcp_info_end(void)
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate 	if (dhcp_pl != NULL) {
84*7c478bd9Sstevel@tonic-gate 		free(dhcp_pl->pkt);
85*7c478bd9Sstevel@tonic-gate 		free(dhcp_pl);
86*7c478bd9Sstevel@tonic-gate 	}
87*7c478bd9Sstevel@tonic-gate 	dhcp_pl = NULL;
88*7c478bd9Sstevel@tonic-gate 	dhcp_ifn[0] = '\0';
89*7c478bd9Sstevel@tonic-gate }
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate /*
92*7c478bd9Sstevel@tonic-gate  * Determine whether the kernel has a cached DHCP ACK, and if so
93*7c478bd9Sstevel@tonic-gate  * initialize dhcp_pl and dhcp_ifn.
94*7c478bd9Sstevel@tonic-gate  */
95*7c478bd9Sstevel@tonic-gate static boolean_t
96*7c478bd9Sstevel@tonic-gate dhcp_info_init(void)
97*7c478bd9Sstevel@tonic-gate {
98*7c478bd9Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
99*7c478bd9Sstevel@tonic-gate 	char		dummy;
100*7c478bd9Sstevel@tonic-gate 	char		*dhcack = NULL;
101*7c478bd9Sstevel@tonic-gate 	long		dhcacksz;
102*7c478bd9Sstevel@tonic-gate 	char		*ackp;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	/*
105*7c478bd9Sstevel@tonic-gate 	 * See whether the kernel has a cached DHCP ACK, and if so get it.
106*7c478bd9Sstevel@tonic-gate 	 * If there is no DHCP ACK, then the returned length is equal to
107*7c478bd9Sstevel@tonic-gate 	 * the size of an empty string.
108*7c478bd9Sstevel@tonic-gate 	 */
109*7c478bd9Sstevel@tonic-gate 	if ((dhcacksz = sysinfo(SI_DHCP_CACHE, &dummy,
110*7c478bd9Sstevel@tonic-gate 	    sizeof (dummy))) == sizeof ("")) {
111*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 	if ((dhcack = malloc(dhcacksz)) == NULL) {
114*7c478bd9Sstevel@tonic-gate 		goto cleanup;
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 	if ((dhcp_pl = calloc(1, sizeof (PKT_LIST))) == NULL) {
117*7c478bd9Sstevel@tonic-gate 		goto cleanup;
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 	(void) sysinfo(SI_DHCP_CACHE, (caddr_t)dhcack, dhcacksz);
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	/*
122*7c478bd9Sstevel@tonic-gate 	 * The first IFNAMSIZ bytes are reserved for the interface name;
123*7c478bd9Sstevel@tonic-gate 	 * the ACK follows.
124*7c478bd9Sstevel@tonic-gate 	 */
125*7c478bd9Sstevel@tonic-gate 	ackp = &dhcack[IFNAMSIZ];
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	/*
128*7c478bd9Sstevel@tonic-gate 	 * Convert and scan the options.
129*7c478bd9Sstevel@tonic-gate 	 */
130*7c478bd9Sstevel@tonic-gate 	dhcp_pl->len = strlen(ackp) / 2;
131*7c478bd9Sstevel@tonic-gate 	if ((dhcp_pl->pkt = malloc(dhcp_pl->len)) == NULL) {
132*7c478bd9Sstevel@tonic-gate 		goto cleanup;
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate 	if (hexascii_to_octet(ackp, dhcp_pl->len * 2,
135*7c478bd9Sstevel@tonic-gate 	    dhcp_pl->pkt, &dhcp_pl->len) != 0) {
136*7c478bd9Sstevel@tonic-gate 		goto cleanup;
137*7c478bd9Sstevel@tonic-gate 	}
138*7c478bd9Sstevel@tonic-gate 	if (dhcp_options_scan(dhcp_pl, B_TRUE) != 0) {
139*7c478bd9Sstevel@tonic-gate 		goto cleanup;
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	/*
143*7c478bd9Sstevel@tonic-gate 	 * Set the interface-name.
144*7c478bd9Sstevel@tonic-gate 	 */
145*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(dhcp_ifn, dhcack, sizeof (dhcp_ifn));
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	ret = B_TRUE;
148*7c478bd9Sstevel@tonic-gate cleanup:
149*7c478bd9Sstevel@tonic-gate 	if (!ret) {
150*7c478bd9Sstevel@tonic-gate 		dhcp_info_end();
151*7c478bd9Sstevel@tonic-gate 	}
152*7c478bd9Sstevel@tonic-gate 	if (dhcack != NULL) {
153*7c478bd9Sstevel@tonic-gate 		free(dhcack);
154*7c478bd9Sstevel@tonic-gate 	}
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	return (ret);
157*7c478bd9Sstevel@tonic-gate }
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate /*
160*7c478bd9Sstevel@tonic-gate  * Deallocate devinfo stuff.
161*7c478bd9Sstevel@tonic-gate  */
162*7c478bd9Sstevel@tonic-gate static void
163*7c478bd9Sstevel@tonic-gate destroy_snapshot(void)
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	if (phdl != DI_PROM_HANDLE_NIL) {
166*7c478bd9Sstevel@tonic-gate 		di_prom_fini(phdl);
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 	phdl = DI_PROM_HANDLE_NIL;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	if (root_node != DI_NODE_NIL) {
171*7c478bd9Sstevel@tonic-gate 		di_fini(root_node);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 	root_node = DI_NODE_NIL;
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate /*
177*7c478bd9Sstevel@tonic-gate  * Take a snapshot of the device tree, i.e. get a devinfo handle and
178*7c478bd9Sstevel@tonic-gate  * a PROM handle.
179*7c478bd9Sstevel@tonic-gate  */
180*7c478bd9Sstevel@tonic-gate static boolean_t
181*7c478bd9Sstevel@tonic-gate snapshot_devtree(void)
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	/*
184*7c478bd9Sstevel@tonic-gate 	 * Deallocate any existing devinfo stuff first.
185*7c478bd9Sstevel@tonic-gate 	 */
186*7c478bd9Sstevel@tonic-gate 	destroy_snapshot();
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL ||
189*7c478bd9Sstevel@tonic-gate 	    (phdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
190*7c478bd9Sstevel@tonic-gate 		destroy_snapshot();
191*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
195*7c478bd9Sstevel@tonic-gate }
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate /*
198*7c478bd9Sstevel@tonic-gate  * Get the value of the named property on the named node in root.
199*7c478bd9Sstevel@tonic-gate  */
200*7c478bd9Sstevel@tonic-gate static char *
201*7c478bd9Sstevel@tonic-gate get_prop(const char *nodename, const char *propname, size_t *lenp)
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate 	di_node_t		node;
204*7c478bd9Sstevel@tonic-gate 	di_prom_prop_t		pp;
205*7c478bd9Sstevel@tonic-gate 	char			*val = NULL;
206*7c478bd9Sstevel@tonic-gate 	int			len;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	/*
209*7c478bd9Sstevel@tonic-gate 	 * Locate nodename within '/'.
210*7c478bd9Sstevel@tonic-gate 	 */
211*7c478bd9Sstevel@tonic-gate 	for (node = di_child_node(root_node);
212*7c478bd9Sstevel@tonic-gate 	    node != DI_NODE_NIL;
213*7c478bd9Sstevel@tonic-gate 	    node = di_sibling_node(node)) {
214*7c478bd9Sstevel@tonic-gate 		if (strcmp(di_node_name(node), nodename) == 0) {
215*7c478bd9Sstevel@tonic-gate 			break;
216*7c478bd9Sstevel@tonic-gate 		}
217*7c478bd9Sstevel@tonic-gate 	}
218*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
219*7c478bd9Sstevel@tonic-gate 		return (NULL);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	/*
223*7c478bd9Sstevel@tonic-gate 	 * Scan all properties of /nodename for the 'propname' property.
224*7c478bd9Sstevel@tonic-gate 	 */
225*7c478bd9Sstevel@tonic-gate 	for (pp = di_prom_prop_next(phdl, node, DI_PROM_PROP_NIL);
226*7c478bd9Sstevel@tonic-gate 	    pp != DI_PROM_PROP_NIL;
227*7c478bd9Sstevel@tonic-gate 	    pp = di_prom_prop_next(phdl, node, pp)) {
228*7c478bd9Sstevel@tonic-gate 		if (strcmp(propname, di_prom_prop_name(pp)) == 0) {
229*7c478bd9Sstevel@tonic-gate 			break;
230*7c478bd9Sstevel@tonic-gate 		}
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 	if (pp == DI_PROM_PROP_NIL) {
233*7c478bd9Sstevel@tonic-gate 		return (NULL);
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * Found the property; copy out its length and return its value.
238*7c478bd9Sstevel@tonic-gate 	 */
239*7c478bd9Sstevel@tonic-gate 	len = di_prom_prop_data(pp, (uchar_t **)&val);
240*7c478bd9Sstevel@tonic-gate 	if (lenp != NULL) {
241*7c478bd9Sstevel@tonic-gate 		*lenp = len;
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	return (val);
244*7c478bd9Sstevel@tonic-gate }
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate /*
247*7c478bd9Sstevel@tonic-gate  * Strip any trailing arguments from a device path.
248*7c478bd9Sstevel@tonic-gate  * Returned memory must be freed by caller.
249*7c478bd9Sstevel@tonic-gate  */
250*7c478bd9Sstevel@tonic-gate static char *
251*7c478bd9Sstevel@tonic-gate strip_args(char *path, size_t len)
252*7c478bd9Sstevel@tonic-gate {
253*7c478bd9Sstevel@tonic-gate 	char	*stripped_path = NULL;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	if (path != NULL && len != 0 &&
256*7c478bd9Sstevel@tonic-gate 	    (stripped_path = calloc(len + 1, sizeof (char))) != NULL) {
257*7c478bd9Sstevel@tonic-gate 		char	*p;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		(void) memcpy(stripped_path, path, len);
260*7c478bd9Sstevel@tonic-gate 		if ((p = strchr(stripped_path, ':')) != NULL) {
261*7c478bd9Sstevel@tonic-gate 			*p = '\0';
262*7c478bd9Sstevel@tonic-gate 		}
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 	return (stripped_path);
265*7c478bd9Sstevel@tonic-gate }
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate /*
268*7c478bd9Sstevel@tonic-gate  * Return the "bootpath" property (sans arguments) from /chosen.
269*7c478bd9Sstevel@tonic-gate  * Returned memory must be freed by caller.
270*7c478bd9Sstevel@tonic-gate  */
271*7c478bd9Sstevel@tonic-gate static char *
272*7c478bd9Sstevel@tonic-gate get_bootpath(void)
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	char	*path;
275*7c478bd9Sstevel@tonic-gate 	size_t	len;
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	path = get_prop("chosen", "bootpath", &len);
278*7c478bd9Sstevel@tonic-gate 	return (strip_args(path, len));
279*7c478bd9Sstevel@tonic-gate }
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate /*
282*7c478bd9Sstevel@tonic-gate  * Return the "net" property (sans arguments) from /aliases.
283*7c478bd9Sstevel@tonic-gate  * Returned memory must be freed by caller.
284*7c478bd9Sstevel@tonic-gate  */
285*7c478bd9Sstevel@tonic-gate static char *
286*7c478bd9Sstevel@tonic-gate get_netalias(void)
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate 	char	*path;
289*7c478bd9Sstevel@tonic-gate 	size_t	len;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	path = get_prop("aliases", "net", &len);
292*7c478bd9Sstevel@tonic-gate 	return (strip_args(path, len));
293*7c478bd9Sstevel@tonic-gate }
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate  * Callback used by path2node().
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate static int
299*7c478bd9Sstevel@tonic-gate p2n_cb(di_node_t node, void *arg)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	int	ret = DI_WALK_CONTINUE;
302*7c478bd9Sstevel@tonic-gate 	cb_t	*cbp = arg;
303*7c478bd9Sstevel@tonic-gate 	char	*phys_path = di_devfs_path(node);
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	if (strcmp(cbp->cb_path, phys_path) == 0) {
306*7c478bd9Sstevel@tonic-gate 		cbp->cb_node = node;
307*7c478bd9Sstevel@tonic-gate 		ret = DI_WALK_TERMINATE;
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 	di_devfs_path_free(phys_path);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	return (ret);
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate /*
315*7c478bd9Sstevel@tonic-gate  * Map a device path to its matching di_node_t.
316*7c478bd9Sstevel@tonic-gate  */
317*7c478bd9Sstevel@tonic-gate static di_node_t
318*7c478bd9Sstevel@tonic-gate path2node(char *path)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	cb_t	cb;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	cb.cb_path = path;
323*7c478bd9Sstevel@tonic-gate 	cb.cb_node = DI_NODE_NIL;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	(void) di_walk_node(root_node, DI_WALK_CLDFIRST, &cb, p2n_cb);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	return (cb.cb_node);
328*7c478bd9Sstevel@tonic-gate }
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate /*
331*7c478bd9Sstevel@tonic-gate  * Check whether node corresponds to a network device.
332*7c478bd9Sstevel@tonic-gate  */
333*7c478bd9Sstevel@tonic-gate static boolean_t
334*7c478bd9Sstevel@tonic-gate is_network_device(di_node_t node)
335*7c478bd9Sstevel@tonic-gate {
336*7c478bd9Sstevel@tonic-gate 	char		*type;
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	return (di_prom_prop_lookup_strings(phdl, node,
339*7c478bd9Sstevel@tonic-gate 	    "device_type", &type) > 0 && strcmp(type, "network") == 0);
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate /*
343*7c478bd9Sstevel@tonic-gate  * Initialise bootmisc with the rootfs-type.
344*7c478bd9Sstevel@tonic-gate  */
345*7c478bd9Sstevel@tonic-gate static boolean_t
346*7c478bd9Sstevel@tonic-gate rootfs_type_init(void)
347*7c478bd9Sstevel@tonic-gate {
348*7c478bd9Sstevel@tonic-gate 	static struct statvfs	vfs;
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	if (statvfs("/", &vfs) >= 0) {
351*7c478bd9Sstevel@tonic-gate 		if (strncmp(vfs.f_basetype, "nfs", sizeof ("nfs") - 1) == 0) {
352*7c478bd9Sstevel@tonic-gate 			vfs.f_basetype[sizeof ("nfs") - 1] = '\0';
353*7c478bd9Sstevel@tonic-gate 		}
354*7c478bd9Sstevel@tonic-gate 		rootfs_type = vfs.f_basetype;
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	return (rootfs_type != NULL && bi_put_bootmisc(BI_ROOTFS_TYPE,
358*7c478bd9Sstevel@tonic-gate 	    rootfs_type, strlen(rootfs_type) + 1));
359*7c478bd9Sstevel@tonic-gate }
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate /*
362*7c478bd9Sstevel@tonic-gate  * Initialise bootmisc with the interface-name of the primary network device,
363*7c478bd9Sstevel@tonic-gate  * and the net-config-strategy employed in configuring that device.
364*7c478bd9Sstevel@tonic-gate  */
365*7c478bd9Sstevel@tonic-gate static boolean_t
366*7c478bd9Sstevel@tonic-gate netif_init(char *ifn, char *ncs)
367*7c478bd9Sstevel@tonic-gate {
368*7c478bd9Sstevel@tonic-gate 	return (bi_put_bootmisc(BI_INTERFACE_NAME, ifn, strlen(ifn) + 1) &&
369*7c478bd9Sstevel@tonic-gate 	    bi_put_bootmisc(BI_NET_CONFIG_STRATEGY, ncs, strlen(ncs) + 1));
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate /*
373*7c478bd9Sstevel@tonic-gate  * Determine whether the interface was configured manually.
374*7c478bd9Sstevel@tonic-gate  */
375*7c478bd9Sstevel@tonic-gate static boolean_t
376*7c478bd9Sstevel@tonic-gate manual_if_init(void)
377*7c478bd9Sstevel@tonic-gate {
378*7c478bd9Sstevel@tonic-gate 	boolean_t	ret = B_FALSE;
379*7c478bd9Sstevel@tonic-gate 	char		*ncs;
380*7c478bd9Sstevel@tonic-gate 	char		*devpath;
381*7c478bd9Sstevel@tonic-gate 	di_node_t	node;
382*7c478bd9Sstevel@tonic-gate 	int		instance;
383*7c478bd9Sstevel@tonic-gate 	char		*drvname;
384*7c478bd9Sstevel@tonic-gate 	char		ifname[IFNAMSIZ + 1];
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	/*
387*7c478bd9Sstevel@tonic-gate 	 * If net-config-strategy isn't "manual", don't go any further.
388*7c478bd9Sstevel@tonic-gate 	 */
389*7c478bd9Sstevel@tonic-gate 	if ((ncs = get_prop("chosen", BI_NET_CONFIG_STRATEGY, NULL)) == NULL ||
390*7c478bd9Sstevel@tonic-gate 	    strcmp(ncs, "manual") != 0) {
391*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	/*
395*7c478bd9Sstevel@tonic-gate 	 * First check the 'bootpath' property of /chosen to see whether
396*7c478bd9Sstevel@tonic-gate 	 * it specifies the path of a network device; if so, use this.
397*7c478bd9Sstevel@tonic-gate 	 */
398*7c478bd9Sstevel@tonic-gate 	if ((devpath = get_bootpath()) == NULL ||
399*7c478bd9Sstevel@tonic-gate 	    (node = path2node(devpath)) == DI_NODE_NIL ||
400*7c478bd9Sstevel@tonic-gate 	    !is_network_device(node)) {
401*7c478bd9Sstevel@tonic-gate 		/*
402*7c478bd9Sstevel@tonic-gate 		 * Must have been booted from CD-ROM or disk; attempt to
403*7c478bd9Sstevel@tonic-gate 		 * use the path defined by the 'net' property of /aliases.
404*7c478bd9Sstevel@tonic-gate 		 */
405*7c478bd9Sstevel@tonic-gate 		free(devpath);
406*7c478bd9Sstevel@tonic-gate 		if ((devpath = get_netalias()) == NULL ||
407*7c478bd9Sstevel@tonic-gate 		    (node = path2node(devpath)) == DI_NODE_NIL ||
408*7c478bd9Sstevel@tonic-gate 		    !is_network_device(node)) {
409*7c478bd9Sstevel@tonic-gate 			goto cleanup;
410*7c478bd9Sstevel@tonic-gate 		}
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	/*
414*7c478bd9Sstevel@tonic-gate 	 * Get the driver name and instance number of this node.
415*7c478bd9Sstevel@tonic-gate 	 * We may have to load the driver.
416*7c478bd9Sstevel@tonic-gate 	 */
417*7c478bd9Sstevel@tonic-gate 	if ((drvname = di_driver_name(node)) == NULL) {
418*7c478bd9Sstevel@tonic-gate 		goto cleanup;
419*7c478bd9Sstevel@tonic-gate 	}
420*7c478bd9Sstevel@tonic-gate 	if ((instance = di_instance(node)) == -1) {
421*7c478bd9Sstevel@tonic-gate 		di_node_t	tmp;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 		/*
424*7c478bd9Sstevel@tonic-gate 		 * Attempt to load the driver, create a new snapshot of the
425*7c478bd9Sstevel@tonic-gate 		 * (possibly changed) device tree and re-compute our node.
426*7c478bd9Sstevel@tonic-gate 		 */
427*7c478bd9Sstevel@tonic-gate 		if ((tmp = di_init_driver(drvname, 0)) != DI_NODE_NIL) {
428*7c478bd9Sstevel@tonic-gate 			di_fini(tmp);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 			if (!snapshot_devtree() ||
431*7c478bd9Sstevel@tonic-gate 			    (node = path2node(devpath)) == DI_NODE_NIL) {
432*7c478bd9Sstevel@tonic-gate 				goto cleanup;
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 		}
435*7c478bd9Sstevel@tonic-gate 		instance = di_instance(node);
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	/*
439*7c478bd9Sstevel@tonic-gate 	 * Construct the interface name.
440*7c478bd9Sstevel@tonic-gate 	 */
441*7c478bd9Sstevel@tonic-gate 	if (instance == -1) {
442*7c478bd9Sstevel@tonic-gate 		(void) snprintf(ifname, sizeof (ifname),
443*7c478bd9Sstevel@tonic-gate 		    "%s", di_driver_name(node));
444*7c478bd9Sstevel@tonic-gate 	} else {
445*7c478bd9Sstevel@tonic-gate 		(void) snprintf(ifname, sizeof (ifname),
446*7c478bd9Sstevel@tonic-gate 		    "%s%d", di_driver_name(node), instance);
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	ret = netif_init(ifname, "manual");
450*7c478bd9Sstevel@tonic-gate cleanup:
451*7c478bd9Sstevel@tonic-gate 	free(devpath);
452*7c478bd9Sstevel@tonic-gate 	return (ret);
453*7c478bd9Sstevel@tonic-gate }
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate /*
456*7c478bd9Sstevel@tonic-gate  * Determine whether the interface was configured via DHCP.
457*7c478bd9Sstevel@tonic-gate  */
458*7c478bd9Sstevel@tonic-gate static boolean_t
459*7c478bd9Sstevel@tonic-gate dhcp_if_init(void)
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	return (strlen(dhcp_ifn) != 0 && netif_init(dhcp_ifn, "dhcp"));
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate static boolean_t
465*7c478bd9Sstevel@tonic-gate bootmisc_init(void)
466*7c478bd9Sstevel@tonic-gate {
467*7c478bd9Sstevel@tonic-gate 	return (rootfs_type_init() &&
468*7c478bd9Sstevel@tonic-gate 	    (manual_if_init() || dhcp_if_init()));
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate /*
473*7c478bd9Sstevel@tonic-gate  * Functions dealing with bootinfo initialization/cleanup.
474*7c478bd9Sstevel@tonic-gate  */
475*7c478bd9Sstevel@tonic-gate boolean_t
476*7c478bd9Sstevel@tonic-gate bi_init_bootinfo(void)
477*7c478bd9Sstevel@tonic-gate {
478*7c478bd9Sstevel@tonic-gate 	if (snapshot_devtree() && dhcp_info_init() && bootmisc_init()) {
479*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 	bi_end_bootinfo();
482*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate void
486*7c478bd9Sstevel@tonic-gate bi_end_bootinfo(void)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	destroy_snapshot();
489*7c478bd9Sstevel@tonic-gate 	dhcp_info_end();
490*7c478bd9Sstevel@tonic-gate }
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate /*
493*7c478bd9Sstevel@tonic-gate  * Function dealing with /chosen data.
494*7c478bd9Sstevel@tonic-gate  */
495*7c478bd9Sstevel@tonic-gate boolean_t
496*7c478bd9Sstevel@tonic-gate bi_get_chosen_prop(const char *name, void *valbuf, size_t *vallenp)
497*7c478bd9Sstevel@tonic-gate {
498*7c478bd9Sstevel@tonic-gate 	char		*val;
499*7c478bd9Sstevel@tonic-gate 	size_t		buflen = *vallenp;
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	if ((val = get_prop("chosen", name, vallenp)) == NULL) {
502*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
503*7c478bd9Sstevel@tonic-gate 	}
504*7c478bd9Sstevel@tonic-gate 	if (*vallenp <= buflen) {
505*7c478bd9Sstevel@tonic-gate 		(void) memcpy(valbuf, val, *vallenp);
506*7c478bd9Sstevel@tonic-gate 	}
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate /*
512*7c478bd9Sstevel@tonic-gate  * Function dealing with DHCP data.
513*7c478bd9Sstevel@tonic-gate  */
514*7c478bd9Sstevel@tonic-gate boolean_t
515*7c478bd9Sstevel@tonic-gate bi_get_dhcp_info(uchar_t optcat, uint16_t optcode, uint16_t optsize,
516*7c478bd9Sstevel@tonic-gate     void *valbuf, size_t *vallenp)
517*7c478bd9Sstevel@tonic-gate {
518*7c478bd9Sstevel@tonic-gate 	return (dhcp_getinfo_pl(dhcp_pl,
519*7c478bd9Sstevel@tonic-gate 	    optcat, optcode, optsize, valbuf, vallenp));
520*7c478bd9Sstevel@tonic-gate }
521