1a192e900Samaguire /*
2a192e900Samaguire  * CDDL HEADER START
3a192e900Samaguire  *
4a192e900Samaguire  * The contents of this file are subject to the terms of the
5a192e900Samaguire  * Common Development and Distribution License (the "License").
6a192e900Samaguire  * You may not use this file except in compliance with the License.
7a192e900Samaguire  *
8a192e900Samaguire  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a192e900Samaguire  * or http://www.opensolaris.org/os/licensing.
10a192e900Samaguire  * See the License for the specific language governing permissions
11a192e900Samaguire  * and limitations under the License.
12a192e900Samaguire  *
13a192e900Samaguire  * When distributing Covered Code, include this CDDL HEADER in each
14a192e900Samaguire  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a192e900Samaguire  * If applicable, add the following below this CDDL HEADER, with the
16a192e900Samaguire  * fields enclosed by brackets "[]" replaced with your own identifying
17a192e900Samaguire  * information: Portions Copyright [yyyy] [name of copyright owner]
18a192e900Samaguire  *
19a192e900Samaguire  * CDDL HEADER END
20a192e900Samaguire  */
21a192e900Samaguire /*
22a192e900Samaguire  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23a192e900Samaguire  * Use is subject to license terms.
24a192e900Samaguire  */
25a192e900Samaguire 
26a192e900Samaguire #include <stdio.h>
27a192e900Samaguire #include <string.h>
28a192e900Samaguire #include <stdlib.h>
29a192e900Samaguire #include <unistd.h>
30a192e900Samaguire #include <limits.h>
31a192e900Samaguire #include <ctype.h>
32a192e900Samaguire #include <stropts.h>
33a192e900Samaguire #include <errno.h>
34a192e900Samaguire #include <libintl.h>
35a192e900Samaguire #include <locale.h>
36a192e900Samaguire #include <fcntl.h>
37a192e900Samaguire #include <sys/types.h>
38a192e900Samaguire #include <sys/stat.h>
39ceb97a6aSamaguire #include <sys/socket.h>
40ceb97a6aSamaguire #include <sys/sockio.h>
41ceb97a6aSamaguire #include <inet/ip.h>
42ceb97a6aSamaguire #include <inet/nd.h>
43ceb97a6aSamaguire #include <net/if.h>
44a192e900Samaguire #include <libscf.h>
45a192e900Samaguire #include <libscf_priv.h>
46a192e900Samaguire #include <libuutil.h>
47a192e900Samaguire 
48a192e900Samaguire /*
49a192e900Samaguire  * This program moves routing management under SMF.  We do this by giving
50a192e900Samaguire  * routeadm options that allow interaction with SMF services.  These include:
51a192e900Samaguire  * - setting the routing services routeadm will enable
52a192e900Samaguire  *	# routeadm -s routing-svcs="fmri [fmri...]"
53a192e900Samaguire  * where each fmri is an SMF routing service.
54a192e900Samaguire  * - changing properties of routing services
55a192e900Samaguire  *	# routeadm -m fmri key=value [key=value...]
56a192e900Samaguire  * - listing routing daemon properties
57a192e900Samaguire  *	# routeadm -l fmri
58a192e900Samaguire  * where all properties in the "routing" property group are listed.
59a192e900Samaguire  *
60a192e900Samaguire  * By providing legacy routing services (legacy-routing:ipv4 and ipv6), we
61a192e900Samaguire  * can also support running of routing daemons with no SMF service under SMF.
62a192e900Samaguire  * Specifying a routing daemon with no SMF counterpart results in the
63a192e900Samaguire  * daemon, it`s arguments and stop command being set in the appropriate instance
64a192e900Samaguire  * to be picked up by start/stop methods.
65a192e900Samaguire  *
66a192e900Samaguire  * Internally, routeadm keeps track of routing services by setting the
67a192e900Samaguire  * "current-routing-svc" property to "true" in the services it manages.
68a192e900Samaguire  * So for example, running
69a192e900Samaguire  *	# routeadm -s routing-svcs="route:default ripng:default"
70a192e900Samaguire  * sets this variable in each instance specified. If the user specifies a
71a192e900Samaguire  * non-SMF routing daemon via
72a192e900Samaguire  * 	# routeadm -s ipv4-routing-daemon=/usr/sbin/mydaemon
73a192e900Samaguire  * the variable will be set for the legacy-routing:ipv4 instance.
74a192e900Samaguire  *
75a192e900Samaguire  * In order to ensure that the SMF versions of routing daemons are used
76a192e900Samaguire  * where possible, routeadm will check the daemons specified in
77a192e900Samaguire  * ipv4-routing-daemon/ipv6-routing-daemon to determine if there is an
78a192e900Samaguire  * SMF counterpart.  If so, rather than running the legacy service
79a192e900Samaguire  * we move configuration, specifically the associated daemon arguments
80a192e900Samaguire  * to the SMF counterpart.  From there,  when the daemon is enabled,  it
81a192e900Samaguire  * will pick up the daemon arguments setting,  transfer the argument string
82a192e900Samaguire  * to the appropriate properties and run the service.
83a192e900Samaguire  *
84a192e900Samaguire  * To support the semantics of routeadm -e (enable at next boot) through SMF,
85a192e900Samaguire  * we make use of temporary state changes,  which last only until reboot.
86a192e900Samaguire  * For example, if a service is disabled,  and it is to be enabled via
87a192e900Samaguire  * routeadm -e,  we simply change the disable to a temporary disable,
88a192e900Samaguire  * and set the persistent enabled value to true.  This ensures the daemon
89a192e900Samaguire  * will run at next boot,  but not now.  The reverse is true for disabling
90a192e900Samaguire  * enabled instances  (and if the daemon is enabled when we issue the enable,
91a192e900Samaguire  * we do nothing since it is already in the desired state).
92a192e900Samaguire  *
93a192e900Samaguire  * Since the code is quite involved,  we provide a guide to the more complex
94a192e900Samaguire  * actions taken in response to user commands.
95a192e900Samaguire  *
96a192e900Samaguire  * routeadm -e[d] ipv4[6]-routing[forwarding]
97a192e900Samaguire  *
98a192e900Samaguire  * 	In this case,  the goal is to prepare the configured routing daemons
99a192e900Samaguire  * 	(specified through routeadm -s routing-svcs="...") or forwarding
100a192e900Samaguire  *	services to switch on (-e) or of (-d) at next boot.
101a192e900Samaguire  *
102a192e900Samaguire  *	Since this operation must be applied to multiple services in the
103a192e900Samaguire  *	routing daemon case (as opposed to the single ipv4[6]-forwarding
104a192e900Samaguire  *	service),  we make use of the scf_walk_fmri() function,  which
105a192e900Samaguire  *	applies a callback function to all matching functions.  In the case
106a192e900Samaguire  *	of the routing daemons,  we pass in a NULL signifying that all
107a192e900Samaguire  *	instances should be walked  (we then weed out the relevant routing
108a192e900Samaguire  *	services through presence of the routeadm/protocol property).  In
109a192e900Samaguire  *	the case of enable, a routing service is enabled IFF it has the
110a192e900Samaguire  *	previously-mentioned property - with an appropriate value (i.e. ipv4
111a192e900Samaguire  *	for "routeadm -e ipv4-routing") - and it has routeadm/curr-routing-svc
112a192e900Samaguire  *	property set to true  (this is set by other operations such as
113a192e900Samaguire  *	routeadm -s routing-svcs="...").  Then,  smf_enable_instance() or
114a192e900Samaguire  *	smf_disable_instance() is called,  setting the temporary state to
115a192e900Samaguire  *	the current state of the service.  This then allows setting of
116a192e900Samaguire  *	general/enabled value to next-boot value.  In the case of disabling
117a192e900Samaguire  *	ipv4[6]-routing,  all valid ipv4[6] routing daemons are prepared
118a192e900Samaguire  *	for next-boot disable, not just those specified via routing-svcs (this
119a192e900Samaguire  *	means that if the user enables routing daemons with "svcadm enable",
120a192e900Samaguire  *	disabling global routing does really switch off all routing daemons).
121a192e900Samaguire  *
122a192e900Samaguire  *	This is implemented through the ra_get_set_opt_common_cb() function,
123a192e900Samaguire  *	called by the ra_set_persistent_opt_cb() function.  The same
124a192e900Samaguire  *	function can be used for both routing and forwarding options,  in the
125a192e900Samaguire  *	latter case we simply provide the specific FMRI of the forwarding
126a192e900Samaguire  *	service in question (ipv4-forwarding or ipv6-forwarding),  and dispense
127a192e900Samaguire  *	with the eligibility tests we need to weed out the routing services
128a192e900Samaguire  *	from the rest.
129a192e900Samaguire  *
130a192e900Samaguire  *	Before we initiate the "enable" however, we must check routing daemons
131a192e900Samaguire  *	specified via the legacy variables (ipv4-routing-daemon etc).
132a192e900Samaguire  *	If they map to SMF routing services,  we wish to transfer their
133a192e900Samaguire  *	configuration to the corresponding services and use them instead of
134a192e900Samaguire  *	the legacy services.  To do this,  we need to match the daemon program
135a192e900Samaguire  *	against the routeadm/daemon property of each routing daemon (we use
136a192e900Samaguire  *	scf_walk_fmri() and the routeadm/protocol property again to identify
137a192e900Samaguire  *	daemons).  If a match is found,  the daemon arguments are transferred
138a192e900Samaguire  *	to the appropriate service`s daemon-args property, to be picked up
139a192e900Samaguire  *	by it`s start method and converted into appropriate property values.
140a192e900Samaguire  *	This is accomplished by ra_check_legacy_daemons(), and the callback
141a192e900Samaguire  *	operation is carried out by ra_upgrade_legacy_daemons_cb().  If the
142a192e900Samaguire  *	daemon was not upgraded,  we need to mark the legacy-routing:ipv4[6]
143a192e900Samaguire  *	instance to be enabled (by routeadm -e),  since it now must run the
144a192e900Samaguire  *	un-upgradeable legacy daemon.
145a192e900Samaguire  *
146a192e900Samaguire  * routeadm -l fmri
147a192e900Samaguire  *
148a192e900Samaguire  *	Lists all properties and values in the routing property group associated
149a192e900Samaguire  *	with instance fmri.  We simply walk through the composed property
150a192e900Samaguire  *	group, displaying all values.  See ra_list_props_cb().
151a192e900Samaguire  *
152a192e900Samaguire  * routeadm -m fmri key=value ...
153a192e900Samaguire  *
154a192e900Samaguire  *	Modify property values in the routing property group.  If the same
155a192e900Samaguire  *	key is used more than once,  multiple property values are set for that
156a192e900Samaguire  *	property.  Properties must exist in the composed property group,  but
157a192e900Samaguire  *	will only ever be set at the instance level to prevent multiple
158a192e900Samaguire  *	instances inheriting the property in error.  See ra_modify_props_cb().
159a192e900Samaguire  *
160a192e900Samaguire  * routeadm -s var=value
161a192e900Samaguire  *
162a192e900Samaguire  *	In all cases bar the routing-svcs variable,  this simply involves
163a192e900Samaguire  *	setting the appropriate SMF property value for the variable.  The
164a192e900Samaguire  *	routing-svcs case is more complex,  since we would like operations
165a192e900Samaguire  *	like the following to have intuitive effects:
166a192e900Samaguire  *		# routeadm -s routing-svcs=route -e ipv4-routing -u
167a192e900Samaguire  *		# routeadm -s routing-svcs=rdisc -u
168a192e900Samaguire  *	i.e., in the end, rdisc is the only routing service running.  To
169a192e900Samaguire  *	accomplish this switchover,  we need to disable the old routing-svcs
170a192e900Samaguire  *	and enable the new, marking the latter with the curr-routing-svc
171a192e900Samaguire  *	property so that routeadm -e will pick them up.  This is carried
172a192e900Samaguire  *	out by the ra_update_routing_svcs() function.
173a192e900Samaguire  *
174a192e900Samaguire  * routeadm -R alt_root ...
175a192e900Samaguire  *
176a192e900Samaguire  *	Used to support use of routeadm in Custom Jumpstart scripts,  this
177a192e900Samaguire  *	option causes all subsequent commands to be appended to the
178a192e900Samaguire  *	/var/svc/profile/upgrade file,  which is run on the subsequent boot.
179a192e900Samaguire  *	This is done because the SMF repository is not available to make
180a192e900Samaguire  *	the modifications to property values required in routeadm operations.
181a192e900Samaguire  *
182a192e900Samaguire  * routeadm -u
183a192e900Samaguire  *
184a192e900Samaguire  *	Update applies the "next boot" state to the current system.  Here
185a192e900Samaguire  *	we simply take the persistent state (general/enabled value) and
186a192e900Samaguire  *	make it the current state through smf_enable_instance() or
187a192e900Samaguire  *	smf_disable_instance() as appropriate (these calls,  without the
188a192e900Samaguire  *	temporary flag set,  delete the general_ovr/enabled property).
189a192e900Samaguire  */
190a192e900Samaguire 
191a192e900Samaguire #define	RA_OPT_IPV4_ROUTING	"ipv4-routing"
192a192e900Samaguire #define	RA_OPT_IPV6_ROUTING	"ipv6-routing"
193a192e900Samaguire #define	RA_OPT_IPV4_FORWARDING	"ipv4-forwarding"
194a192e900Samaguire #define	RA_OPT_IPV6_FORWARDING	"ipv6-forwarding"
195a192e900Samaguire 
196a192e900Samaguire #define	IS_ROUTING_OPT(opt)	(strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
197a192e900Samaguire 				strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
198a192e900Samaguire 
199a192e900Samaguire #define	RA_VAR_IPV4_ROUTING_DAEMON	"ipv4-routing-daemon"
200a192e900Samaguire #define	RA_VAR_IPV4_ROUTING_DAEMON_ARGS	"ipv4-routing-daemon-args"
201a192e900Samaguire #define	RA_VAR_IPV4_ROUTING_STOP_CMD	"ipv4-routing-stop-cmd"
202a192e900Samaguire #define	RA_VAR_IPV6_ROUTING_DAEMON	"ipv6-routing-daemon"
203a192e900Samaguire #define	RA_VAR_IPV6_ROUTING_DAEMON_ARGS	"ipv6-routing-daemon-args"
204a192e900Samaguire #define	RA_VAR_IPV6_ROUTING_STOP_CMD	"ipv6-routing-stop-cmd"
205a192e900Samaguire #define	RA_VAR_ROUTING_SVCS		"routing-svcs"
206a192e900Samaguire 
207a192e900Samaguire 
208a192e900Samaguire #define	RA_INSTANCE_ALL			NULL
209a192e900Samaguire #define	RA_INSTANCE_ROUTING_SETUP	"svc:/network/routing-setup:default"
210a192e900Samaguire #define	RA_INSTANCE_IPV4_FORWARDING	"svc:/network/ipv4-forwarding:default"
211a192e900Samaguire #define	RA_INSTANCE_IPV6_FORWARDING	"svc:/network/ipv6-forwarding:default"
212a192e900Samaguire #define	RA_INSTANCE_LEGACY_ROUTING_IPV4 \
213a192e900Samaguire 	"svc:/network/routing/legacy-routing:ipv4"
214a192e900Samaguire #define	RA_INSTANCE_LEGACY_ROUTING_IPV6 \
215a192e900Samaguire 	"svc:/network/routing/legacy-routing:ipv6"
216ceb97a6aSamaguire #define	RA_INSTANCE_NDP			"svc:/network/routing/ndp:default"
217a192e900Samaguire 
218a192e900Samaguire #define	RA_PG_ROUTEADM			"routeadm"
219a192e900Samaguire #define	RA_PROP_CURR_ROUTING_SVC	"current-routing-svc"
220a192e900Samaguire #define	RA_PROP_ROUTING_SVCS		"routing-svcs"
221a192e900Samaguire #define	RA_PROP_DEFAULT_ROUTING_SVCS	"default-routing-svcs"
222a192e900Samaguire #define	RA_PROP_PROTO			"protocol"
223a192e900Samaguire #define	RA_PROP_DAEMON			"daemon"
224a192e900Samaguire #define	RA_PROP_DEFAULT_DAEMON		"default-daemon"
225a192e900Samaguire #define	RA_PROP_DAEMON_ARGS		"daemon-args"
226a192e900Samaguire #define	RA_PROP_DEFAULT_DAEMON_ARGS	"default-daemon-args"
227a192e900Samaguire #define	RA_PROP_DAEMON_STOP_CMD		"daemon-stop-cmd"
228a192e900Samaguire #define	RA_PROP_DEFAULT_STOP_CMD	"default-daemon"
229a192e900Samaguire #define	RA_PROP_LEGACY_DAEMON		"legacy-daemon"
230a192e900Samaguire #define	RA_PROP_DEFAULT_IPV4_ROUTING	"default-ipv4-routing"
231a192e900Samaguire #define	RA_PROP_DEFAULT_IPV6_ROUTING	"default-ipv6-routing"
232a192e900Samaguire #define	RA_PROP_DEFAULT_IPV4_FORWARDING	"default-ipv4-forwarding"
233a192e900Samaguire #define	RA_PROP_DEFAULT_IPV6_FORWARDING	"default-ipv6-forwarding"
234a192e900Samaguire #define	RA_PROP_IPV4_ROUTING_SET	"ipv4-routing-set"
235a192e900Samaguire #define	RA_PROP_IPV6_ROUTING_SET	"ipv6-routing-set"
236a192e900Samaguire #define	RA_PROP_ROUTING_CONF_READ	"routing-conf-read"
237a192e900Samaguire 
238a192e900Samaguire #define	RA_PG_ROUTING			"routing"
239a192e900Samaguire 
240a192e900Samaguire #define	RA_PROPVAL_BOOLEAN_TRUE		"true"
241a192e900Samaguire #define	RA_PROPVAL_BOOLEAN_FALSE	"false"
242a192e900Samaguire #define	RA_PROPVAL_PROTO_IPV4		"ipv4"
243a192e900Samaguire #define	RA_PROPVAL_PROTO_IPV6		"ipv6"
244a192e900Samaguire 
245a192e900Samaguire #define	RA_SVC_FLAG_NONE		0x0
246a192e900Samaguire #define	RA_SVC_FLAG_IPV4_ROUTING	0x1
247a192e900Samaguire #define	RA_SVC_FLAG_IPV6_ROUTING	0x2
248a192e900Samaguire 
249a192e900Samaguire #define	RA_SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
250*bbf21555SRichard Lowe #define	RA_SMF_UPGRADE_MSG		" # added by routeadm(8)"
251a192e900Samaguire #define	RA_CONF_FILE			"/etc/inet/routing.conf"
252a192e900Samaguire #define	RA_CONF_FILE_OLD		"/etc/inet/routing.conf.old"
253a192e900Samaguire #define	RA_MAX_CONF_LINE		256
254a192e900Samaguire 
255a192e900Samaguire /*
256a192e900Samaguire  * Option value.  Each option requires an FMRI identifying which services
257a192e900Samaguire  * to run the get_current/persistent scf_walk_fmri() function with,  and
258a192e900Samaguire  * associated flags (to ensure that in the case that multiple services
259a192e900Samaguire  * match, we select the correct ones). In addition, we specify the FMRI
260a192e900Samaguire  * and property used to set default option value.  The opt_enabled field
261a192e900Samaguire  * is used to hold retrieved state from get_*_opt_() callbacks and to specify
262a192e900Samaguire  * desired state for set_*_opt() operations.
263a192e900Samaguire  */
264a192e900Samaguire 
265a192e900Samaguire typedef struct raopt {
266a192e900Samaguire 	const char	*opt_name;
267a192e900Samaguire 	const char	*opt_fmri;
268a192e900Samaguire 	int		opt_flags;
269a192e900Samaguire 	boolean_t	opt_enabled;
270a192e900Samaguire 	const char	*opt_default_fmri;
271a192e900Samaguire 	const char	*opt_default_prop;
272a192e900Samaguire 	boolean_t	opt_default_enabled;
273a192e900Samaguire } raopt_t;
274a192e900Samaguire 
275a192e900Samaguire 
276a192e900Samaguire raopt_t ra_opts[] = {
277a192e900Samaguire 	{ RA_OPT_IPV4_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV4_ROUTING,
278a192e900Samaguire 	B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV4_ROUTING,
279a192e900Samaguire 	B_FALSE },
280a192e900Samaguire 	{ RA_OPT_IPV6_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV6_ROUTING,
281a192e900Samaguire 	B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV6_ROUTING,
282a192e900Samaguire 	B_FALSE },
283a192e900Samaguire 	{ RA_OPT_IPV4_FORWARDING, RA_INSTANCE_IPV4_FORWARDING, RA_SVC_FLAG_NONE,
284a192e900Samaguire 	B_FALSE, RA_INSTANCE_IPV4_FORWARDING, RA_PROP_DEFAULT_IPV4_FORWARDING,
285a192e900Samaguire 	B_FALSE },
286a192e900Samaguire 	{ RA_OPT_IPV6_FORWARDING, RA_INSTANCE_IPV6_FORWARDING, RA_SVC_FLAG_NONE,
287a192e900Samaguire 	B_FALSE, RA_INSTANCE_IPV6_FORWARDING, RA_PROP_DEFAULT_IPV6_FORWARDING,
288a192e900Samaguire 	B_FALSE },
289a192e900Samaguire 	{ NULL, NULL, RA_SVC_FLAG_NONE, B_FALSE, NULL, NULL, B_FALSE }
290a192e900Samaguire };
291a192e900Samaguire 
292a192e900Samaguire typedef enum option_values {
293a192e900Samaguire 	OPT_INVALID, OPT_ENABLED, OPT_DISABLED, OPT_DEFAULT, OPT_UNKNOWN
294a192e900Samaguire } oval_t;
295a192e900Samaguire 
296a192e900Samaguire typedef struct ra_var {
297a192e900Samaguire 	const char	*var_name;
298a192e900Samaguire 	const char	*var_fmri;
299a192e900Samaguire 	const char	*var_prop;
300a192e900Samaguire 	char		*var_value;
301a192e900Samaguire 	const char	*var_default_fmri;
302a192e900Samaguire 	const char	*var_default_prop;
303a192e900Samaguire 	char		*var_default_value;
304a192e900Samaguire } ravar_t;
305a192e900Samaguire 
306a192e900Samaguire ravar_t ra_vars[] = {
307a192e900Samaguire 	{ RA_VAR_IPV4_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV4,
308a192e900Samaguire 	RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
309a192e900Samaguire 	RA_PROP_DEFAULT_DAEMON, NULL},
310a192e900Samaguire 	{ RA_VAR_IPV4_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV4,
311a192e900Samaguire 	RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
312a192e900Samaguire 	RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
313a192e900Samaguire 	{ RA_VAR_IPV4_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV4,
314a192e900Samaguire 	RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
315a192e900Samaguire 	RA_PROP_DEFAULT_STOP_CMD, NULL },
316a192e900Samaguire 	{ RA_VAR_IPV6_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV6,
317a192e900Samaguire 	RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
318a192e900Samaguire 	RA_PROP_DEFAULT_DAEMON, NULL },
319a192e900Samaguire 	{ RA_VAR_IPV6_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV6,
320a192e900Samaguire 	RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
321a192e900Samaguire 	RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
322a192e900Samaguire 	{ RA_VAR_IPV6_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV6,
323a192e900Samaguire 	RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
324a192e900Samaguire 	RA_PROP_DEFAULT_STOP_CMD, NULL },
325a192e900Samaguire 	{ RA_VAR_ROUTING_SVCS, RA_INSTANCE_ROUTING_SETUP,
326a192e900Samaguire 	RA_PROP_ROUTING_SVCS, NULL, RA_INSTANCE_ROUTING_SETUP,
327a192e900Samaguire 	RA_PROP_DEFAULT_ROUTING_SVCS, NULL },
328a192e900Samaguire 	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
329a192e900Samaguire };
330a192e900Samaguire 
331a192e900Samaguire char *v_opt[] = {
332a192e900Samaguire #define	IPV4_ROUTING_DAEMON			0
333a192e900Samaguire 	RA_VAR_IPV4_ROUTING_DAEMON,
334a192e900Samaguire #define	IPV4_ROUTING_DAEMON_ARGS		1
335a192e900Samaguire 	RA_VAR_IPV4_ROUTING_DAEMON_ARGS,
336a192e900Samaguire #define	IPV4_ROUTING_STOP_CMD			2
337a192e900Samaguire 	RA_VAR_IPV4_ROUTING_STOP_CMD,
338a192e900Samaguire #define	IPV6_ROUTING_DAEMON			3
339a192e900Samaguire 	RA_VAR_IPV6_ROUTING_DAEMON,
340a192e900Samaguire #define	IPV6_ROUTING_DAEMON_ARGS		4
341a192e900Samaguire 	RA_VAR_IPV6_ROUTING_DAEMON_ARGS,
342a192e900Samaguire #define	IPV6_ROUTING_STOP_CMD			5
343a192e900Samaguire 	RA_VAR_IPV6_ROUTING_STOP_CMD,
344a192e900Samaguire #define	ROUTING_SVCS				6
345a192e900Samaguire 	RA_VAR_ROUTING_SVCS,
346a192e900Samaguire 	NULL
347a192e900Samaguire };
348a192e900Samaguire 
349a192e900Samaguire #define	IS_IPV4_VAR(varname)	(strncmp(varname, "ipv4", 4) == 0)
350a192e900Samaguire #define	IS_IPV6_VAR(varname)	(strncmp(varname, "ipv6", 4) == 0)
351a192e900Samaguire #define	VAR_PROTO_MATCH(varname, proto)	(strncmp(varname, proto, 4) == 0)
352a192e900Samaguire #define	IPV4_VARS_UNSET \
353a192e900Samaguire 	(strtok(ra_vars[IPV4_ROUTING_DAEMON].var_value, " \t") == NULL && \
354a192e900Samaguire 	strtok(ra_vars[IPV4_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
355a192e900Samaguire 	strtok(ra_vars[IPV4_ROUTING_STOP_CMD].var_value, " \t") == NULL)
356a192e900Samaguire 
357a192e900Samaguire #define	IPV6_VARS_UNSET	\
358a192e900Samaguire 	(strtok(ra_vars[IPV6_ROUTING_DAEMON].var_value, " \t") == NULL && \
359a192e900Samaguire 	strtok(ra_vars[IPV6_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
360a192e900Samaguire 	strtok(ra_vars[IPV6_ROUTING_STOP_CMD].var_value, " \t") == NULL)
361a192e900Samaguire 
362a192e900Samaguire /*
363a192e900Samaguire  * Structure used in modify operations to tie property name and multiple values
364a192e900Samaguire  * together.
365a192e900Samaguire  */
366a192e900Samaguire typedef struct ra_prop {
367a192e900Samaguire 	char	*prop_name;
368a192e900Samaguire 	char	**prop_values;
369a192e900Samaguire 	int	prop_numvalues;
370a192e900Samaguire } ra_prop_t;
371a192e900Samaguire 
372a192e900Samaguire typedef int (*ra_smf_cb_t)(void *, scf_walkinfo_t *);
373a192e900Samaguire 
374a192e900Samaguire /* Used to store program name */
375a192e900Samaguire static const char	*myname;
376a192e900Samaguire 
377a192e900Samaguire static void usage(void);
378a192e900Samaguire 
379a192e900Samaguire static int ra_check_legacy_daemons(void);
380a192e900Samaguire static int ra_upgrade_legacy_daemons(void);
381a192e900Samaguire static int ra_upgrade_cmd(char, int, char **);
382a192e900Samaguire static int ra_update(void);
383a192e900Samaguire static int ra_update_routing_svcs(char *);
384a192e900Samaguire static int ra_report(boolean_t, const char *);
385a192e900Samaguire static int ra_smf_cb(ra_smf_cb_t, const char *, void *);
386a192e900Samaguire static int ra_upgrade_from_legacy_conf(void);
387ceb97a6aSamaguire static int ra_numv6intfs(void);
388a192e900Samaguire static int ra_parseconf(void);
389a192e900Samaguire static int ra_parseopt(char *, int, raopt_t *);
390a192e900Samaguire static int ra_parsevar(char *, ravar_t *);
391a192e900Samaguire static oval_t ra_str2oval(const char *);
392a192e900Samaguire static raopt_t *ra_str2opt(const char *);
393a192e900Samaguire static void ra_resetopts(void);
394a192e900Samaguire static ravar_t *ra_str2var(const char *);
395a192e900Samaguire static void ra_resetvars(const char *);
396a192e900Samaguire static char *ra_intloptname(const char *);
397a192e900Samaguire 
398a192e900Samaguire /* Callback for upgrade of legacy daemons */
399a192e900Samaguire static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
400a192e900Samaguire 
401a192e900Samaguire /* Callbacks used to set/retieve routing options */
402a192e900Samaguire static int ra_set_current_opt_cb(void *, scf_walkinfo_t *);
403a192e900Samaguire static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t *);
404a192e900Samaguire static int ra_set_default_opt_cb(void *, scf_walkinfo_t *);
405a192e900Samaguire static int ra_get_current_opt_cb(void *, scf_walkinfo_t *);
406a192e900Samaguire static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t *);
407a192e900Samaguire static int ra_get_default_opt_cb(void *, scf_walkinfo_t *);
408a192e900Samaguire static int ra_get_set_opt_common_cb(raopt_t *, scf_walkinfo_t *, boolean_t,
409a192e900Samaguire     boolean_t);
410ef2c19a1Samaguire static int ra_routing_opt_set_cb(void *, scf_walkinfo_t *);
411ef2c19a1Samaguire static int ra_routing_opt_unset_cb(void *, scf_walkinfo_t *);
412ef2c19a1Samaguire static int ra_routing_opt_set_unset_cb(raopt_t *, scf_walkinfo_t *, boolean_t);
413a192e900Samaguire 
414a192e900Samaguire /* Callbacks used to set/retrieve routing variables */
415a192e900Samaguire static int ra_set_persistent_var_cb(void *, scf_walkinfo_t *);
416a192e900Samaguire static int ra_get_persistent_var_cb(void *, scf_walkinfo_t *);
417a192e900Samaguire static int ra_get_default_var_cb(void *, scf_walkinfo_t *);
418a192e900Samaguire static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t *);
419a192e900Samaguire 
420a192e900Samaguire /* Callbacks used to list/set daemon properties and list daemons and states. */
421a192e900Samaguire static int ra_list_props_cb(void *, scf_walkinfo_t *);
422a192e900Samaguire static int ra_modify_props_cb(void *, scf_walkinfo_t *);
423a192e900Samaguire static int ra_print_state_cb(void *, scf_walkinfo_t *);
424a192e900Samaguire 
425a192e900Samaguire /* Utility functions for SMF operations */
426a192e900Samaguire static int ra_get_pg(scf_handle_t *, scf_instance_t *, const char *,
427a192e900Samaguire     boolean_t, boolean_t, scf_propertygroup_t **);
428a192e900Samaguire static int ra_get_boolean_prop(scf_handle_t *, scf_instance_t *,
429a192e900Samaguire     const char *, const char *,  boolean_t, boolean_t, boolean_t *);
430a192e900Samaguire static int ra_get_single_prop_as_string(scf_handle_t *, scf_instance_t *,
431a192e900Samaguire     const char *, const char *, boolean_t, boolean_t, scf_type_t *, char **);
432a192e900Samaguire static int ra_get_prop_as_string(scf_handle_t *, scf_instance_t *,
433a192e900Samaguire     const char *, const char *, boolean_t, boolean_t, scf_type_t *, int *,
434a192e900Samaguire     char ***);
435a192e900Samaguire static void ra_free_prop_values(int, char **);
436a192e900Samaguire static int ra_set_boolean_prop(scf_handle_t *, scf_instance_t *,
437a192e900Samaguire     const char *, const char *, boolean_t, boolean_t);
438a192e900Samaguire static int ra_set_prop_from_string(scf_handle_t *, scf_instance_t *,
439a192e900Samaguire     const char *, const char *, scf_type_t, boolean_t, int,
440a192e900Samaguire     const char **);
441a192e900Samaguire 
442a192e900Samaguire static void
usage(void)443a192e900Samaguire usage(void)
444a192e900Samaguire {
445a192e900Samaguire 	(void) fprintf(stderr, gettext(
446a192e900Samaguire 	    "usage: %1$s [-p] [-R <root-dir>]\n"
447a192e900Samaguire 	    "       %1$s [-e <option>] [-d <option>] [-r <option>]\n"
448a192e900Samaguire 	    "           [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
449a192e900Samaguire 	    "           [-s <var>=<val>] [-R <root-dir>]\n"
450a192e900Samaguire 	    "       %1$s -u\n\n"
451a192e900Samaguire 	    "       <option> is one of:\n"
452a192e900Samaguire 	    "       ipv4-forwarding\n"
453a192e900Samaguire 	    "       ipv4-routing\n"
454a192e900Samaguire 	    "       ipv6-forwarding\n"
455a192e900Samaguire 	    "       ipv6-routing\n\n"
456a192e900Samaguire 	    "       <var> is one of:\n"
457a192e900Samaguire 	    "       ipv4-routing-daemon\n"
458a192e900Samaguire 	    "       ipv4-routing-daemon-args\n"
459a192e900Samaguire 	    "       ipv4-routing-stop-cmd\n"
460a192e900Samaguire 	    "       ipv6-routing-daemon\n"
461a192e900Samaguire 	    "       ipv6-routing-daemon-args\n"
462a192e900Samaguire 	    "       ipv6-routing-stop-cmd\n"
463a192e900Samaguire 	    "       routing-svcs\n"), myname);
464a192e900Samaguire }
465a192e900Samaguire 
466a192e900Samaguire int
main(int argc,char * argv[])467a192e900Samaguire main(int argc, char *argv[])
468a192e900Samaguire {
469a192e900Samaguire 	int		opt, opt_index, numargs, status = 0;
470a192e900Samaguire 	int		numvalues, i;
471a192e900Samaguire 	ssize_t		keylen;
472a192e900Samaguire 	boolean_t	modify = B_FALSE, report = B_TRUE, update = B_FALSE;
473ef2c19a1Samaguire 	boolean_t	booting = B_FALSE, alt_root_set = B_FALSE;
474a192e900Samaguire 	boolean_t	parseable = B_FALSE;
475a192e900Samaguire 	char		*key, *nk, *keyend, *val, **vals, *options, *fmri;
476a192e900Samaguire 	char		*parseopt = NULL;
477a192e900Samaguire 	raopt_t		*raopt;
478a192e900Samaguire 	ravar_t		*ravar;
479a192e900Samaguire 	ra_prop_t	raprop;
480a192e900Samaguire 
481a192e900Samaguire 	myname = argv[0];
482a192e900Samaguire 
483a192e900Samaguire 	(void) setlocale(LC_ALL, "");
484a192e900Samaguire 
485a192e900Samaguire #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
486a192e900Samaguire #define	TEXT_DOMAIN	"SYS_TEST"
487a192e900Samaguire #endif
488a192e900Samaguire 
489a192e900Samaguire 	(void) textdomain(TEXT_DOMAIN);
490a192e900Samaguire 
491a192e900Samaguire 	/*
492a192e900Samaguire 	 * Before processing any options, we parse /etc/inet/routing.conf
493a192e900Samaguire 	 * (if present) and transfer values to SMF.
494a192e900Samaguire 	 */
495a192e900Samaguire 	if (ra_upgrade_from_legacy_conf() == -1)
496a192e900Samaguire 		exit(EXIT_FAILURE);
497ef2c19a1Samaguire 	while ((opt = getopt(argc, argv, ":bd:e:l:m:p:R:r:s:u")) != EOF) {
498a192e900Samaguire 		switch (opt) {
499ef2c19a1Samaguire 		case 'b':
500ef2c19a1Samaguire 			/*
501ef2c19a1Samaguire 			 * Project-private option that tells us enable/disable
502ef2c19a1Samaguire 			 * operations should not set ipv4(6)-routing-set
503ef2c19a1Samaguire 			 * property.  Used in routing-setup service method
504ef2c19a1Samaguire 			 * to change default routing state, and, if
505ef2c19a1Samaguire 			 * no explicit enable/disable operations have been
506ef2c19a1Samaguire 			 * carried out, change current ipv4 routing state.
507ef2c19a1Samaguire 			 */
508ef2c19a1Samaguire 			booting = B_TRUE;
509ef2c19a1Samaguire 			break;
510a192e900Samaguire 		case 'd':
511a192e900Samaguire 		case 'e':
512a192e900Samaguire 		case 'r':
513a192e900Samaguire 			if (alt_root_set) {
514a192e900Samaguire 				if (ra_upgrade_cmd(opt, 1, &optarg) != 0)
515a192e900Samaguire 					exit(EXIT_FAILURE);
516a192e900Samaguire 				modify = B_TRUE;
517a192e900Samaguire 				break;
518a192e900Samaguire 			}
519a192e900Samaguire 			if ((raopt = ra_str2opt(optarg)) != NULL) {
520a192e900Samaguire 				/* Set current value appropriately */
521a192e900Samaguire 				switch (opt) {
522a192e900Samaguire 				case 'd':
523a192e900Samaguire 					raopt->opt_enabled = B_FALSE;
524a192e900Samaguire 					break;
525a192e900Samaguire 				case 'e':
526a192e900Samaguire 					/*
527a192e900Samaguire 					 * Check legacy daemons, mark
528a192e900Samaguire 					 * routing-svcs.
529a192e900Samaguire 					 */
530a192e900Samaguire 					if (IS_ROUTING_OPT(optarg) &&
531a192e900Samaguire 					    ra_check_legacy_daemons() == -1)
532a192e900Samaguire 						exit(EXIT_FAILURE);
533a192e900Samaguire 					raopt->opt_enabled = B_TRUE;
534a192e900Samaguire 					break;
535a192e900Samaguire 				case 'r':
536a192e900Samaguire 					/*
537a192e900Samaguire 					 * This callback sets opt_enabled to
538a192e900Samaguire 					 * the default value.
539a192e900Samaguire 					 */
540a192e900Samaguire 					ra_resetopts();
541a192e900Samaguire 					if (ra_smf_cb(ra_get_default_opt_cb,
542a192e900Samaguire 					    raopt->opt_default_fmri, raopt)
543a192e900Samaguire 					    == -1)
544a192e900Samaguire 						exit(EXIT_FAILURE);
545a192e900Samaguire 					if (raopt->opt_enabled &&
546a192e900Samaguire 					    IS_ROUTING_OPT(optarg) &&
547a192e900Samaguire 					    ra_check_legacy_daemons() == -1)
548a192e900Samaguire 						exit(EXIT_FAILURE);
549a192e900Samaguire 					/* set value to default */
550a192e900Samaguire 					raopt->opt_enabled =
551a192e900Samaguire 					    raopt->opt_default_enabled;
552a192e900Samaguire 					break;
553a192e900Samaguire 				}
554a192e900Samaguire 				if (ra_smf_cb(ra_set_persistent_opt_cb,
555a192e900Samaguire 				    raopt->opt_fmri, raopt) == -1)
556a192e900Samaguire 					exit(EXIT_FAILURE);
557ef2c19a1Samaguire 				/*
558ef2c19a1Samaguire 				 * ipv4(6)-routing explicitly enabled/disabled,
559ef2c19a1Samaguire 				 * need to set ipv4(6)-routing-set property
560ef2c19a1Samaguire 				 * for routing-setup service.  Once this
561ef2c19a1Samaguire 				 * is set, routing-setup will not override
562ef2c19a1Samaguire 				 * administrator action and will not enable
563ef2c19a1Samaguire 				 * ipv4-routing in the case that no default
564ef2c19a1Samaguire 				 * route can be determined.  If ipv4(6)-routing
565ef2c19a1Samaguire 				 * is reverted to its default value,  set
566ef2c19a1Samaguire 				 * ipv4(6)-routing-set back to false.
567ef2c19a1Samaguire 				 */
568ef2c19a1Samaguire 				if (!booting && (raopt->opt_flags &
569ef2c19a1Samaguire 				    (RA_SVC_FLAG_IPV4_ROUTING |
570ef2c19a1Samaguire 				    RA_SVC_FLAG_IPV6_ROUTING))) {
571ef2c19a1Samaguire 					if (ra_smf_cb(opt == 'r' ?
572ef2c19a1Samaguire 					    ra_routing_opt_unset_cb :
573ef2c19a1Samaguire 					    ra_routing_opt_set_cb,
574ef2c19a1Samaguire 					    raopt->opt_default_fmri, raopt)
575ef2c19a1Samaguire 					    == -1)
576ef2c19a1Samaguire 						exit(EXIT_FAILURE);
577ef2c19a1Samaguire 				}
578a192e900Samaguire 			} else if ((ravar = ra_str2var(optarg)) != NULL) {
579a192e900Samaguire 				if (opt != 'r') {
580a192e900Samaguire 					usage();
581a192e900Samaguire 					exit(EXIT_FAILURE);
582a192e900Samaguire 				}
583a192e900Samaguire 				/* set current value to default */
584a192e900Samaguire 				ra_resetopts();
585a192e900Samaguire 				if (ra_smf_cb(ra_get_default_var_cb,
586a192e900Samaguire 				    ravar->var_default_fmri, ravar) == -1)
587a192e900Samaguire 					exit(EXIT_FAILURE);
588a192e900Samaguire 				/* Need special case for routing-svcs var */
589a192e900Samaguire 				if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
590a192e900Samaguire 				    == 0) {
591a192e900Samaguire 					if (ra_update_routing_svcs(
592a192e900Samaguire 					    ravar->var_default_value) == -1)
593a192e900Samaguire 						exit(EXIT_FAILURE);
594a192e900Samaguire 				} else if (ra_smf_cb(ra_set_persistent_var_cb,
595a192e900Samaguire 				    ravar->var_fmri, ravar) == -1)
596a192e900Samaguire 					exit(EXIT_FAILURE);
597a192e900Samaguire 			} else {
598a192e900Samaguire 				(void) fprintf(stderr, gettext(
599a192e900Samaguire 				    "%1$s: invalid option: %2$s\n"), myname,
600a192e900Samaguire 				    optarg);
601a192e900Samaguire 				usage();
602a192e900Samaguire 				exit(EXIT_FAILURE);
603a192e900Samaguire 			}
604a192e900Samaguire 			modify = B_TRUE;
605a192e900Samaguire 			break;
606a192e900Samaguire 		case 'l':
607a192e900Samaguire 			if (ra_smf_cb(ra_list_props_cb, optarg, NULL) == -1)
608a192e900Samaguire 				exit(EXIT_FAILURE);
609a192e900Samaguire 			report = B_FALSE;
610a192e900Samaguire 			break;
611a192e900Samaguire 		case 'm':
612a192e900Samaguire 			fmri = optarg;
613a192e900Samaguire 			modify = B_TRUE;
614a192e900Samaguire 			/*
615a192e900Samaguire 			 * Argument list of key=value pairs, we need to
616a192e900Samaguire 			 * collate all matching keys to set multiple values.
617a192e900Samaguire 			 */
618a192e900Samaguire 			numargs = 1;
619a192e900Samaguire 			i = optind;
620a192e900Samaguire 			for (numargs = 1; argv[i] != NULL && argv[i][0] != '-';
621a192e900Samaguire 			    numargs++)
622a192e900Samaguire 				i++;
623a192e900Samaguire 			if (numargs == 1) {
624a192e900Samaguire 				(void) fprintf(stderr, gettext(
625a192e900Samaguire 				    "%s: key=value required for "
626a192e900Samaguire 				    "property change\n"), myname);
627a192e900Samaguire 				usage();
628a192e900Samaguire 				exit(EXIT_FAILURE);
629a192e900Samaguire 			}
630a192e900Samaguire 			if (alt_root_set) {
631a192e900Samaguire 				if (ra_upgrade_cmd(opt, numargs,
632a192e900Samaguire 				    &argv[optind - 1]) == -1)
633a192e900Samaguire 					exit(EXIT_FAILURE);
634a192e900Samaguire 				optind += numargs - 1;
635a192e900Samaguire 				break;
636a192e900Samaguire 			}
637a192e900Samaguire 			/*
638a192e900Samaguire 			 * Collect all key=value pairs which use same key
639a192e900Samaguire 			 * so we can add multiple property values.
640a192e900Samaguire 			 */
641a192e900Samaguire 			for (key = argv[optind]; key != NULL && key[0] != '-';
642a192e900Samaguire 			    key = argv[++optind]) {
643a192e900Samaguire 				if (key[0] == '\0')
644a192e900Samaguire 					continue;
645a192e900Samaguire 				vals = malloc(sizeof (char *));
646a192e900Samaguire 				if ((vals[0] = strchr(key, '=')) == NULL) {
647a192e900Samaguire 					(void) fprintf(stderr, gettext(
648a192e900Samaguire 					    "%s: Malformed name=value "
649a192e900Samaguire 					    "pair %s\n"), myname, key);
650a192e900Samaguire 					exit(EXIT_FAILURE);
651a192e900Samaguire 				}
652a192e900Samaguire 				numvalues = 1;
653a192e900Samaguire 				*(vals[0]) = '\0';
654a192e900Samaguire 				(vals[0])++;
655a192e900Samaguire 				i = optind + 1;
656a192e900Samaguire 				for (nk = argv[i];
657a192e900Samaguire 				    nk != NULL && nk[0] != '-';
658a192e900Samaguire 				    nk = argv[++i]) {
659a192e900Samaguire 					if (nk[0] == '\0')
660a192e900Samaguire 						continue;
661a192e900Samaguire 					if ((keyend = strchr(nk, '='))
662a192e900Samaguire 					    == NULL) {
663a192e900Samaguire 						(void) fprintf(stderr, gettext(
664a192e900Samaguire 						    "%s: Malformed name=value "
665a192e900Samaguire 						    " pair %s\n"), myname, nk);
666a192e900Samaguire 						exit(EXIT_FAILURE);
667a192e900Samaguire 					}
668a192e900Samaguire 					if ((keylen = keyend - nk) !=
669a192e900Samaguire 					    strlen(key))
670a192e900Samaguire 						continue;
671a192e900Samaguire 					if (strncmp(key, nk, keylen) == 0) {
672a192e900Samaguire 						vals = realloc(vals, ++numvalues
673a192e900Samaguire 						    * sizeof (char *));
674a192e900Samaguire 						vals[numvalues - 1] = ++keyend;
675a192e900Samaguire 						nk[0] = '\0';
676a192e900Samaguire 						optind++;
677a192e900Samaguire 					}
678a192e900Samaguire 				}
679a192e900Samaguire 				raprop.prop_name = key;
680a192e900Samaguire 				raprop.prop_values = vals;
681a192e900Samaguire 				raprop.prop_numvalues = numvalues;
682a192e900Samaguire 				if (ra_smf_cb(ra_modify_props_cb, fmri,
683a192e900Samaguire 				    &raprop) == -1)
684a192e900Samaguire 					exit(EXIT_FAILURE);
685a192e900Samaguire 			}
686a192e900Samaguire 			break;
687a192e900Samaguire 		case 'p':
688a192e900Samaguire 			parseable = B_TRUE;
689a192e900Samaguire 			parseopt = optarg;
690a192e900Samaguire 			break;
691a192e900Samaguire 		case 'R':
692a192e900Samaguire 			if (chroot(optarg) == -1) {
693a192e900Samaguire 				(void) fprintf(stderr, gettext(
694a192e900Samaguire 				    "%1$s: failed to chroot to %2$s: %3$s\n"),
695a192e900Samaguire 				    myname, optarg, strerror(errno));
696a192e900Samaguire 				exit(EXIT_FAILURE);
697a192e900Samaguire 			}
698a192e900Samaguire 			alt_root_set = B_TRUE;
699a192e900Samaguire 			report = B_FALSE;
700a192e900Samaguire 			break;
701a192e900Samaguire 		case 's':
702a192e900Samaguire 			if (alt_root_set) {
703a192e900Samaguire 				if (ra_upgrade_cmd(opt, 1, &optarg) == -1)
704a192e900Samaguire 					exit(EXIT_FAILURE);
705a192e900Samaguire 				modify = B_TRUE;
706a192e900Samaguire 				break;
707a192e900Samaguire 			}
708a192e900Samaguire 			options = optarg;
709a192e900Samaguire 			while (*options != '\0') {
710a192e900Samaguire 				opt_index = getsubopt(&options, v_opt, &val);
711a192e900Samaguire 				if (val == NULL) {
712a192e900Samaguire 					usage();
713a192e900Samaguire 					exit(EXIT_FAILURE);
714a192e900Samaguire 				}
715a192e900Samaguire 				if (opt_index == -1) {
716a192e900Samaguire 					(void) fprintf(stderr, gettext(
717a192e900Samaguire 					    "%1$s: invalid variable: %2$s\n"),
718a192e900Samaguire 					    myname, optarg);
719a192e900Samaguire 					usage();
720a192e900Samaguire 					exit(EXIT_FAILURE);
721a192e900Samaguire 				}
722a192e900Samaguire 				ravar = &ra_vars[opt_index];
723a192e900Samaguire 				/* Need special case for routing-svcs var */
724a192e900Samaguire 				if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
725a192e900Samaguire 				    == 0) {
726a192e900Samaguire 					if (ra_update_routing_svcs(val) == -1)
727a192e900Samaguire 						return (-1);
728a192e900Samaguire 				} else {
729a192e900Samaguire 					ravar->var_value = strdup(val);
730a192e900Samaguire 					if (ra_smf_cb(ra_set_persistent_var_cb,
731a192e900Samaguire 					    ravar->var_fmri, ravar) == -1)
732a192e900Samaguire 						exit(EXIT_FAILURE);
733a192e900Samaguire 				}
734a192e900Samaguire 			}
735a192e900Samaguire 			modify = B_TRUE;
736a192e900Samaguire 			break;
737a192e900Samaguire 		case 'u':
738a192e900Samaguire 			update = B_TRUE;
739a192e900Samaguire 			break;
740a192e900Samaguire 		case ':':
741a192e900Samaguire 			/* if not 'p', usage failure */
742a192e900Samaguire 			if (strcmp(argv[optind - 1], "-p") != 0) {
743a192e900Samaguire 				(void) fprintf(stderr, gettext(
744a192e900Samaguire 				    "%s: option requires an argument -%s\n"),
745a192e900Samaguire 				    myname, argv[optind - 1]);
746a192e900Samaguire 				usage();
747a192e900Samaguire 				exit(EXIT_FAILURE);
748a192e900Samaguire 			}
749a192e900Samaguire 			parseable = B_TRUE;
750a192e900Samaguire 			break;
751a192e900Samaguire 		case '?':
752a192e900Samaguire 			usage();
753a192e900Samaguire 			exit(EXIT_FAILURE);
754a192e900Samaguire 		}
755a192e900Samaguire 	}
756a192e900Samaguire 
757a192e900Samaguire 	if (argc > optind) {
758a192e900Samaguire 		/* There shouldn't be any extra args. */
759a192e900Samaguire 		usage();
760a192e900Samaguire 		exit(EXIT_FAILURE);
761a192e900Samaguire 	}
762a192e900Samaguire 
763a192e900Samaguire 	if (parseable && (update || modify)) {
764a192e900Samaguire 		(void) fprintf(stderr, gettext("%s: the -p option cannot be "
765a192e900Samaguire 		    "used with any of -demrsu\n"), myname);
766a192e900Samaguire 		usage();
767a192e900Samaguire 		exit(EXIT_FAILURE);
768a192e900Samaguire 	}
769a192e900Samaguire 
770a192e900Samaguire 	if (update && ! alt_root_set)
771a192e900Samaguire 		status = ra_update();
772a192e900Samaguire 
773a192e900Samaguire 	if (report && !modify && !update)
774a192e900Samaguire 		status = ra_report(parseable, parseopt);
775a192e900Samaguire 
776a192e900Samaguire 	return (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
777a192e900Samaguire }
778a192e900Samaguire 
779a192e900Samaguire /*
780a192e900Samaguire  * Upgrade legacy daemons,  mark to-be-enabled routing services.
781a192e900Samaguire  */
782a192e900Samaguire static int
ra_check_legacy_daemons(void)783a192e900Samaguire ra_check_legacy_daemons(void)
784a192e900Samaguire {
785a192e900Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
786a192e900Samaguire 	ravar_t		*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
787a192e900Samaguire 	ravar_t		*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
788a192e900Samaguire 	char		*fmri, *nextfmri;
789a192e900Samaguire 	boolean_t	mark = B_FALSE;
790a192e900Samaguire 
791a192e900Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
792a192e900Samaguire 	    routing_svcs) == -1)
793a192e900Samaguire 		return (-1);
794a192e900Samaguire 
795a192e900Samaguire 	/* First unmark all services */
796a192e900Samaguire 	if (ra_smf_cb(ra_mark_routing_svcs_cb, NULL, &mark) == -1)
797a192e900Samaguire 		return (-1);
798a192e900Samaguire 
799a192e900Samaguire 	mark = B_TRUE;
800a192e900Samaguire 	if (routing_svcs->var_value != NULL) {
801a192e900Samaguire 		/*
802a192e900Samaguire 		 * For routing-svcs variable, mark each named
803a192e900Samaguire 		 * service as a current-routing-svc.
804a192e900Samaguire 		 */
805a192e900Samaguire 		if ((fmri = strdup(routing_svcs->var_value)) == NULL) {
806a192e900Samaguire 			(void) fprintf(stderr, gettext(
807a192e900Samaguire 			    "%s: out of memory\n"), myname);
808a192e900Samaguire 			return (-1);
809a192e900Samaguire 		}
810a192e900Samaguire 		/* Now, mark each service named in routing-svcs. */
811a192e900Samaguire 		for (nextfmri = strtok(fmri, " \t");
812a192e900Samaguire 		    nextfmri != NULL;
813a192e900Samaguire 		    nextfmri = strtok(NULL, " \t")) {
814a192e900Samaguire 			if (ra_smf_cb(ra_mark_routing_svcs_cb, nextfmri,
815a192e900Samaguire 			    &mark) == -1) {
816a192e900Samaguire 				free(fmri);
817a192e900Samaguire 				return (-1);
818a192e900Samaguire 			}
819a192e900Samaguire 		}
820a192e900Samaguire 		free(fmri);
821a192e900Samaguire 	}
822a192e900Samaguire 
823a192e900Samaguire 	/*
824a192e900Samaguire 	 * Now check if legacy variables (if specified) map to SMF routing
825a192e900Samaguire 	 * daemons.  If so, transfer associated daemon arguments.
826a192e900Samaguire 	 */
827a192e900Samaguire 	if (ra_upgrade_legacy_daemons() == -1)
828a192e900Samaguire 		return (-1);
829a192e900Samaguire 
830a192e900Samaguire 	ra_resetvars(NULL);
831a192e900Samaguire 	/*
832a192e900Samaguire 	 * At this point, if the legacy services still have ipv4/ipv6
833a192e900Samaguire 	 * routing daemons specified, we know they weren`t upgraded, so
834a192e900Samaguire 	 * we mark them also.
835a192e900Samaguire 	 */
836a192e900Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
837a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1)
838a192e900Samaguire 		return (-1);
839a192e900Samaguire 
840a192e900Samaguire 	if (v4d->var_value != NULL && strtok(v4d->var_value, " \t") != NULL &&
841a192e900Samaguire 	    ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV4,
842a192e900Samaguire 	    &mark) == -1)
843a192e900Samaguire 		return (-1);
844a192e900Samaguire 	if (v6d->var_value != NULL && strtok(v6d->var_value, " \t") != NULL &&
845a192e900Samaguire 	    ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV6,
846a192e900Samaguire 	    &mark) == -1)
847a192e900Samaguire 		return (-1);
848a192e900Samaguire 
849a192e900Samaguire 	return (0);
850a192e900Samaguire }
851a192e900Samaguire 
852a192e900Samaguire /*
853a192e900Samaguire  * Retrieve legacy daemon variables,  and check if any SMF routing daemons
854a192e900Samaguire  * run the daemons specified.  If so, the legacy configuration (arguments
855a192e900Samaguire  * to the daemon) is transferred to the routeadm/daemon-args property
856a192e900Samaguire  * of the corresponding instance.  From there,  the instance picks up the
857a192e900Samaguire  * value and will transfer the daemon arguments to individiual properties
858a192e900Samaguire  * when enabled.
859a192e900Samaguire  */
860a192e900Samaguire static int
ra_upgrade_legacy_daemons(void)861a192e900Samaguire ra_upgrade_legacy_daemons(void)
862a192e900Samaguire {
863a192e900Samaguire 	ravar_t	*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
864a192e900Samaguire 	ravar_t	*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
865a192e900Samaguire 	ravar_t	*v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
866a192e900Samaguire 	ravar_t	*v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
867a192e900Samaguire 	ravar_t	*v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
868a192e900Samaguire 	ravar_t	*v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
869a192e900Samaguire 
870a192e900Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
871a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1 ||
872a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v4args->var_fmri, v4args)
873a192e900Samaguire 	    == -1 ||
874a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6args->var_fmri, v6args)
875a192e900Samaguire 	    == -1 ||
876a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v4stop->var_fmri, v4stop)
877a192e900Samaguire 	    == -1 ||
878a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6stop->var_fmri, v6stop)
879a192e900Samaguire 	    == -1)
880a192e900Samaguire 		return (-1);
881a192e900Samaguire 
882a192e900Samaguire 	return (ra_smf_cb(ra_upgrade_legacy_daemons_cb, NULL, NULL));
883a192e900Samaguire }
884a192e900Samaguire 
885a192e900Samaguire /*
886a192e900Samaguire  * Determine if service runs the same daemon as that which is specified
887a192e900Samaguire  * in ipv4-routing-daemon or ipv6-routing-daemon.  If so, the associated
888a192e900Samaguire  * daemon arguments are transferred to the service.
889a192e900Samaguire  */
890a192e900Samaguire 
891a192e900Samaguire /* ARGSUSED0 */
892a192e900Samaguire static int
ra_upgrade_legacy_daemons_cb(void * data,scf_walkinfo_t * wip)893a192e900Samaguire ra_upgrade_legacy_daemons_cb(void *data, scf_walkinfo_t *wip)
894a192e900Samaguire {
895a192e900Samaguire 	const char	*inst_fmri = wip->fmri;
896a192e900Samaguire 	scf_instance_t	*inst = wip->inst;
897a192e900Samaguire 	scf_handle_t	*h = scf_instance_handle(inst);
898a192e900Samaguire 	char		*daemon, *l_daemon = NULL;
899a192e900Samaguire 	ravar_t		*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
900a192e900Samaguire 	ravar_t		*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
901a192e900Samaguire 	ravar_t		*v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
902a192e900Samaguire 	ravar_t		*v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
903a192e900Samaguire 	ravar_t		*v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
904a192e900Samaguire 	ravar_t		*v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
905a192e900Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
906a192e900Samaguire 	boolean_t	mark, marked;
907a192e900Samaguire 	char		*new_routing_svcs;
908a192e900Samaguire 
909a192e900Samaguire 	/*
910a192e900Samaguire 	 * Ensure instance is a routing service, and not one of the
911a192e900Samaguire 	 * legacy instances - if it is, the daemon property is already
912a192e900Samaguire 	 * set to the legacy daemon.
913a192e900Samaguire 	 */
914a192e900Samaguire 	if (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
915a192e900Samaguire 	    RA_PROP_DAEMON, B_TRUE, B_FALSE, NULL, &daemon) == -1 ||
916a192e900Samaguire 	    strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV4, inst_fmri) == 0 ||
917a192e900Samaguire 	    strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV6, inst_fmri) == 0)
918a192e900Samaguire 		return (0);
919a192e900Samaguire 
920a192e900Samaguire 	/* A legacy daemon may be defined */
921a192e900Samaguire 	(void) ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
922a192e900Samaguire 	    RA_PROP_LEGACY_DAEMON, B_TRUE, B_FALSE, NULL, &l_daemon);
923a192e900Samaguire 
924a192e900Samaguire 	/*
925a192e900Samaguire 	 * If we match daemon/legacy_daemon with ipv4-routing-daemon or
926a192e900Samaguire 	 * ipv6-routing-daemon values, transfer daemon-args value
927a192e900Samaguire 	 * to the matching service.
928a192e900Samaguire 	 */
929a192e900Samaguire 	if (v4d->var_value != NULL && (strcmp(v4d->var_value, daemon) == 0 ||
930a192e900Samaguire 	    (l_daemon != NULL && strcmp(v4d->var_value, l_daemon) == 0))) {
931a192e900Samaguire 		(void) printf(gettext("%s: migrating daemon configuration "
932a192e900Samaguire 		    "for %s to %s\n"), myname, l_daemon != NULL ?
933a192e900Samaguire 		    l_daemon : daemon, inst_fmri);
934a192e900Samaguire 		/* Transfer daemon-args value, clear legacy v4 values */
935a192e900Samaguire 		if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
936a192e900Samaguire 		    RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
937a192e900Samaguire 		    (const char **)&(v4args->var_value)) == -1)
938a192e900Samaguire 			return (-1);
939a192e900Samaguire 		ra_resetvars(RA_PROPVAL_PROTO_IPV4);
940a192e900Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb,
941a192e900Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4d) == -1 ||
942a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
943a192e900Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4args) == -1 ||
944a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
945a192e900Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4stop) == -1)
946a192e900Samaguire 			return (-1);
947a192e900Samaguire 	} else if (v6d->var_value != NULL && (strcmp(v6d->var_value, daemon)
948a192e900Samaguire 	    == 0 ||
949a192e900Samaguire 	    (l_daemon != NULL && strcmp(v6d->var_value, l_daemon) == 0))) {
950a192e900Samaguire 		(void) printf(gettext("%s: migrating daemon configuration "
951a192e900Samaguire 		    "for %s to %s\n"), myname, l_daemon != NULL ?
952a192e900Samaguire 		    l_daemon : daemon, inst_fmri);
953a192e900Samaguire 		/* Transfer daemon-args value, clear legacy v6 values */
954a192e900Samaguire 		if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
955a192e900Samaguire 		    RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
956a192e900Samaguire 		    (const char **)&(v6args->var_value)) == -1)
957a192e900Samaguire 			return (-1);
958a192e900Samaguire 		ra_resetvars(RA_PROPVAL_PROTO_IPV6);
959a192e900Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb,
960a192e900Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6d) == -1 ||
961a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
962a192e900Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6args) == -1 ||
963a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
964a192e900Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6stop) == -1)
965a192e900Samaguire 			return (-1);
966a192e900Samaguire 	} else
967a192e900Samaguire 		return (0);
968a192e900Samaguire 
969a192e900Samaguire 	/*
970a192e900Samaguire 	 * If service is unmarked at this point, add it to routing-svcs and
971a192e900Samaguire 	 * mark it.
972a192e900Samaguire 	 */
973a192e900Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
974a192e900Samaguire 	    RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE, &marked) == -1 ||
975a192e900Samaguire 	    marked == B_FALSE) {
976a192e900Samaguire 		mark = B_TRUE;
977a192e900Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, inst_fmri, &mark)
978a192e900Samaguire 		    == -1 ||
979a192e900Samaguire 		    ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
980a192e900Samaguire 		    routing_svcs) == -1)
981a192e900Samaguire 			return (-1);
982a192e900Samaguire 		if ((new_routing_svcs =
983a192e900Samaguire 		    malloc(strlen(routing_svcs->var_value) +
984a192e900Samaguire 		    strlen(inst_fmri) + 2)) == NULL) {
985a192e900Samaguire 			(void) fprintf(stderr, gettext(
986a192e900Samaguire 			    "%s: out of memory"), myname);
987a192e900Samaguire 			return (-1);
988a192e900Samaguire 		}
989a192e900Samaguire 		if (strlen(routing_svcs->var_value) == 0)
990a192e900Samaguire 			(void) snprintf(new_routing_svcs,
991a192e900Samaguire 			    strlen(inst_fmri) + 1, "%s", inst_fmri);
992a192e900Samaguire 		else
993a192e900Samaguire 			(void) snprintf(new_routing_svcs,
994a192e900Samaguire 			    strlen(routing_svcs->var_value) +
995a192e900Samaguire 			    strlen(inst_fmri) + 2, "%s %s",
996a192e900Samaguire 			    routing_svcs->var_value, inst_fmri);
997a192e900Samaguire 		free(routing_svcs->var_value);
998a192e900Samaguire 		routing_svcs->var_value = new_routing_svcs;
999a192e900Samaguire 		(void) smf_refresh_instance(inst_fmri);
1000a192e900Samaguire 		return (ra_smf_cb(ra_set_persistent_var_cb,
1001a192e900Samaguire 		    routing_svcs->var_fmri, routing_svcs));
1002a192e900Samaguire 	}
1003a192e900Samaguire 	(void) smf_refresh_instance(inst_fmri);
1004a192e900Samaguire 	return (0);
1005a192e900Samaguire }
1006a192e900Samaguire 
1007a192e900Samaguire /*
1008a192e900Samaguire  * If we are upgrading,  append operation to <alt_root>/var/svc/profile/upgrade.
1009a192e900Samaguire  */
1010a192e900Samaguire static int
ra_upgrade_cmd(char opt,int argc,char ** argv)1011a192e900Samaguire ra_upgrade_cmd(char opt, int argc, char **argv)
1012a192e900Samaguire {
1013a192e900Samaguire 	FILE	*fp;
1014a192e900Samaguire 	int	i;
1015a192e900Samaguire 
1016a192e900Samaguire 	if ((fp = fopen(RA_SMF_UPGRADE_FILE, "a+")) == NULL) {
1017a192e900Samaguire 		(void) fprintf(stderr, gettext(
1018a192e900Samaguire 		    "%1$s: failed to open %2$s: %3$s\n"),
1019a192e900Samaguire 		    myname, RA_SMF_UPGRADE_FILE, strerror(errno));
1020a192e900Samaguire 		return (-1);
1021a192e900Samaguire 	}
1022a192e900Samaguire 	(void) fprintf(fp, "/sbin/routeadm -%c ", opt);
1023a192e900Samaguire 	if (argv != NULL) {
1024a192e900Samaguire 		for (i = 0; i < argc; i++)
1025a192e900Samaguire 			(void) fprintf(fp, "%s ", argv[i]);
1026a192e900Samaguire 	}
1027a192e900Samaguire 	(void) fprintf(fp, "%s\n", RA_SMF_UPGRADE_MSG);
1028a192e900Samaguire 	(void) fclose(fp);
1029a192e900Samaguire 	return (0);
1030a192e900Samaguire }
1031a192e900Samaguire 
1032a192e900Samaguire /*
1033a192e900Samaguire  * Set current state to "next boot" state, i.e. if general/enabled
1034a192e900Samaguire  * value is overlaid by a general_ovr/enabled value, set the current state
1035a192e900Samaguire  * to the value of the latter.  Doing this applies "next boot" changes to
1036ceb97a6aSamaguire  * the current setup.  If any IPv6 interfaces are present, also start in.ndpd.
1037a192e900Samaguire  */
1038a192e900Samaguire static int
ra_update(void)1039a192e900Samaguire ra_update(void)
1040a192e900Samaguire {
1041ceb97a6aSamaguire 	int	i;
1042a192e900Samaguire 
1043a192e900Samaguire 	if (ra_check_legacy_daemons() == -1)
1044a192e900Samaguire 		return (-1);
1045a192e900Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
1046ceb97a6aSamaguire 		if (ra_smf_cb(ra_set_current_opt_cb, ra_opts[i].opt_fmri,
1047ceb97a6aSamaguire 		    &ra_opts[i]) == -1) {
1048ceb97a6aSamaguire 			return (-1);
1049ceb97a6aSamaguire 		}
1050a192e900Samaguire 	}
1051ceb97a6aSamaguire 	/*
1052ceb97a6aSamaguire 	 * If in.ndpd isn't already running, then we start it here, regardless
1053ceb97a6aSamaguire 	 * of global IPv6 routing status (provided there are IPv6 interfaces
1054ceb97a6aSamaguire 	 * present).
1055ceb97a6aSamaguire 	 */
1056ceb97a6aSamaguire 	if (ra_numv6intfs() > 0)
1057ceb97a6aSamaguire 		return (smf_enable_instance(RA_INSTANCE_NDP, SMF_TEMPORARY));
1058ceb97a6aSamaguire 	return (0);
1059a192e900Samaguire }
1060a192e900Samaguire 
1061a192e900Samaguire /*
1062a192e900Samaguire  * Here we catch the special case where ipv4/ipv6 routing was enabled,
1063a192e900Samaguire  * and the user updates the routing-svcs list.  The problem is that
1064a192e900Samaguire  * the enabled state is the result of services on the old routing-svcs list
1065a192e900Samaguire  * being enabled, and we want to support users doing something like this:
1066a192e900Samaguire  *
1067a192e900Samaguire  * # routeadm -s routing-svcs=route -e ipv4-routing -u
1068a192e900Samaguire  *
1069a192e900Samaguire  * followed by
1070a192e900Samaguire  *
1071a192e900Samaguire  * # routeadm -s routing-svcs=rdisc -u
1072a192e900Samaguire  *
1073a192e900Samaguire  * To do this, we need to:
1074a192e900Samaguire  *	- cache the old ipv4-routing/ipv6-routing values.
1075a192e900Samaguire  *	- persistently disable the old routing-svcs list.
1076a192e900Samaguire  *	- if ipv4-routing was enabled, mark and persistently enable all the new
1077a192e900Samaguire  *	v4 routing-svcs
1078a192e900Samaguire  *	- if ipv6-routing was enabled, mark and persistently enable all the new
1079a192e900Samaguire  *	v6 routing-svcs.
1080a192e900Samaguire  * This will result in the next "-u" switching on the new routing-svcs, and
1081a192e900Samaguire  * switching off the old ones,  as the user would expect.
1082a192e900Samaguire  */
1083a192e900Samaguire static int
ra_update_routing_svcs(char * routing_svcs_new)1084a192e900Samaguire ra_update_routing_svcs(char *routing_svcs_new)
1085a192e900Samaguire {
1086a192e900Samaguire 	raopt_t		*v4opt = ra_str2opt(RA_OPT_IPV4_ROUTING);
1087a192e900Samaguire 	raopt_t		*v6opt = ra_str2opt(RA_OPT_IPV6_ROUTING);
1088a192e900Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
1089a192e900Samaguire 	char		*routing_svcs_old, *fmri;
1090a192e900Samaguire 	boolean_t	v4_old, v6_old, mark = B_FALSE;
1091a192e900Samaguire 
1092a192e900Samaguire 	ra_resetopts();
1093a192e900Samaguire 	if (ra_smf_cb(ra_get_persistent_opt_cb, v4opt->opt_fmri, v4opt) == -1 ||
1094a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_opt_cb, v6opt->opt_fmri, v6opt) == -1 ||
1095a192e900Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
1096a192e900Samaguire 	    routing_svcs) == -1)
1097a192e900Samaguire 		return (-1);
1098a192e900Samaguire 	v4_old = v4opt->opt_enabled;
1099a192e900Samaguire 	v6_old = v6opt->opt_enabled;
1100a192e900Samaguire 	routing_svcs_old = routing_svcs->var_value;
1101a192e900Samaguire 	routing_svcs->var_value = routing_svcs_new;
1102a192e900Samaguire 
1103a192e900Samaguire 	if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
1104a192e900Samaguire 	    routing_svcs) == -1) {
1105a192e900Samaguire 		free(routing_svcs_old);
1106a192e900Samaguire 		return (-1);
1107a192e900Samaguire 	}
1108a192e900Samaguire 
1109a192e900Samaguire 	if (!v4_old && !v6_old) {
1110a192e900Samaguire 		/* We don`t need to do anything, since services were disabled */
1111a192e900Samaguire 		free(routing_svcs_old);
1112a192e900Samaguire 		return (0);
1113a192e900Samaguire 	}
1114a192e900Samaguire 	v4opt->opt_enabled = B_FALSE;
1115a192e900Samaguire 	v6opt->opt_enabled = B_FALSE;
1116a192e900Samaguire 
1117a192e900Samaguire 	/* Persistently disable each old v4/v6 "routing-svc" */
1118a192e900Samaguire 	for (fmri = strtok(routing_svcs_old, " \t"); fmri != NULL;
1119a192e900Samaguire 	    fmri = strtok(NULL, " \t")) {
1120a192e900Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1) {
1121a192e900Samaguire 			free(routing_svcs_old);
1122a192e900Samaguire 			return (-1);
1123a192e900Samaguire 		}
1124a192e900Samaguire 		if (v4_old &&
1125a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1) {
1126a192e900Samaguire 			free(routing_svcs_old);
1127a192e900Samaguire 			return (-1);
1128a192e900Samaguire 		}
1129a192e900Samaguire 		if (v6_old &&
1130a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1) {
1131a192e900Samaguire 			free(routing_svcs_old);
1132a192e900Samaguire 			return (-1);
1133a192e900Samaguire 		}
1134a192e900Samaguire 	}
1135a192e900Samaguire 	free(routing_svcs_old);
1136a192e900Samaguire 	v4opt->opt_enabled = v4_old;
1137a192e900Samaguire 	v6opt->opt_enabled = v6_old;
1138a192e900Samaguire 
1139a192e900Samaguire 	/* Persistently enable each new v4/v6 "routing-svc" */
1140a192e900Samaguire 	mark = B_TRUE;
1141a192e900Samaguire 	for (fmri = strtok(routing_svcs_new, " \t"); fmri != NULL;
1142a192e900Samaguire 	    fmri = strtok(NULL, " \t")) {
1143a192e900Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1)
1144a192e900Samaguire 			return (-1);
1145a192e900Samaguire 		if (v4_old &&
1146a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1)
1147a192e900Samaguire 			return (-1);
1148a192e900Samaguire 		if (v6_old &&
1149a192e900Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1)
1150a192e900Samaguire 			return (-1);
1151a192e900Samaguire 	}
1152a192e900Samaguire 	return (0);
1153a192e900Samaguire }
1154a192e900Samaguire 
1155a192e900Samaguire /*
1156a192e900Samaguire  * Display status,  in parseable form if required.  If param is
1157a192e900Samaguire  * specified,  only the named option/variable is displayed  (this option is
1158a192e900Samaguire  * for parseable display only).
1159a192e900Samaguire  */
1160a192e900Samaguire static int
ra_report(boolean_t parseable,const char * param)1161a192e900Samaguire ra_report(boolean_t parseable, const char *param)
1162a192e900Samaguire {
1163a192e900Samaguire 	int		i;
1164a192e900Samaguire 	char		*c_state, *d_state, *p_state, *p_var, *d_var;
1165a192e900Samaguire 	char		*enabled = "enabled";
1166a192e900Samaguire 	char		*disabled = "disabled";
1167a192e900Samaguire 	boolean_t	param_found = B_FALSE;
1168a192e900Samaguire 
1169a192e900Samaguire 	if (!parseable) {
1170a192e900Samaguire 		(void) printf(gettext(
1171a192e900Samaguire 		    "              Configuration   Current              "
1172a192e900Samaguire 		    "Current\n"
1173a192e900Samaguire 		    "                     Option   Configuration        "
1174a192e900Samaguire 		    "System State\n"
1175a192e900Samaguire 		    "---------------------------------------------------"
1176a192e900Samaguire 		    "------------\n"));
1177a192e900Samaguire 	}
1178a192e900Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
1179a192e900Samaguire 		if (param != NULL) {
1180a192e900Samaguire 			if (strcmp(ra_opts[i].opt_name, param) == 0)
1181a192e900Samaguire 				param_found = B_TRUE;
1182a192e900Samaguire 			else
1183a192e900Samaguire 				continue;
1184a192e900Samaguire 		}
1185a192e900Samaguire 		if (ra_smf_cb(ra_get_current_opt_cb,
1186a192e900Samaguire 		    ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1187a192e900Samaguire 			return (-1);
1188a192e900Samaguire 		c_state = ra_opts[i].opt_enabled ? enabled : disabled;
1189a192e900Samaguire 		ra_resetopts();
1190a192e900Samaguire 		if (ra_smf_cb(ra_get_persistent_opt_cb,
1191a192e900Samaguire 		    ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1192a192e900Samaguire 			return (-1);
1193a192e900Samaguire 		p_state = ra_opts[i].opt_enabled ? enabled : disabled;
1194a192e900Samaguire 		ra_resetopts();
1195a192e900Samaguire 		if (ra_smf_cb(ra_get_default_opt_cb,
1196a192e900Samaguire 		    ra_opts[i].opt_default_fmri, &ra_opts[i]) == -1)
1197a192e900Samaguire 			return (-1);
1198a192e900Samaguire 		d_state = ra_opts[i].opt_default_enabled ? enabled : disabled;
1199a192e900Samaguire 		ra_resetopts();
1200a192e900Samaguire 		if (parseable) {
1201a192e900Samaguire 			if (param == NULL)
1202a192e900Samaguire 				(void) printf("%s ", ra_opts[i].opt_name);
1203a192e900Samaguire 			(void) printf("persistent=%s default=%s "
1204a192e900Samaguire 			    "current=%s\n", p_state, d_state, c_state);
1205a192e900Samaguire 		} else {
1206a192e900Samaguire 			(void) printf(gettext("%1$27s   %2$-21s%3$s\n"),
1207a192e900Samaguire 			    ra_intloptname(ra_opts[i].opt_name),
1208a192e900Samaguire 			    p_state, c_state);
1209a192e900Samaguire 		}
1210a192e900Samaguire 	}
1211a192e900Samaguire 	if (!parseable)
1212a192e900Samaguire 		(void) printf("\n");
1213a192e900Samaguire 
1214a192e900Samaguire 	ra_resetvars(NULL);
1215a192e900Samaguire 
1216a192e900Samaguire 	/* Gather persistent/default variable values */
1217a192e900Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
1218a192e900Samaguire 		if (ra_smf_cb(ra_get_persistent_var_cb,
1219a192e900Samaguire 		    ra_vars[i].var_fmri, &ra_vars[i]) == -1 ||
1220a192e900Samaguire 		    ra_smf_cb(ra_get_default_var_cb,
1221a192e900Samaguire 		    ra_vars[i].var_default_fmri, &ra_vars[i]) == -1)
1222a192e900Samaguire 			return (-1);
1223a192e900Samaguire 
1224a192e900Samaguire 	}
1225a192e900Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
1226a192e900Samaguire 		if (param != NULL) {
1227a192e900Samaguire 			if (strcmp(ra_vars[i].var_name, param) == 0)
1228a192e900Samaguire 				param_found = B_TRUE;
1229a192e900Samaguire 			else
1230a192e900Samaguire 				continue;
1231a192e900Samaguire 		}
1232a192e900Samaguire 		p_var = ra_vars[i].var_value == NULL ? "":
1233a192e900Samaguire 		    ra_vars[i].var_value;
1234a192e900Samaguire 		d_var = ra_vars[i].var_default_value == NULL ?
1235a192e900Samaguire 		    "": ra_vars[i].var_default_value;
1236a192e900Samaguire 		if (parseable) {
1237a192e900Samaguire 			if (param == NULL)
1238a192e900Samaguire 				(void) printf("%s ", ra_vars[i].var_name);
1239a192e900Samaguire 			(void) printf("persistent=\"%s\" "
1240a192e900Samaguire 			    "default=\"%s\" \n", p_var, d_var);
1241a192e900Samaguire 		} else {
1242a192e900Samaguire 			/* If daemon variables are not set, do not display. */
1243a192e900Samaguire 			if ((IS_IPV4_VAR(ra_vars[i].var_name) &&
1244a192e900Samaguire 			    IPV4_VARS_UNSET) ||
1245a192e900Samaguire 			    (IS_IPV6_VAR(ra_vars[i].var_name) &&
1246a192e900Samaguire 			    IPV6_VARS_UNSET))
1247a192e900Samaguire 				continue;
1248a192e900Samaguire 			(void) printf(gettext("%1$27s   \"%2$s\"\n"),
1249a192e900Samaguire 			    ra_intloptname(ra_vars[i].var_name), p_var);
1250a192e900Samaguire 		}
1251a192e900Samaguire 	}
1252a192e900Samaguire 
1253a192e900Samaguire 	if (param != NULL && !param_found) {
1254a192e900Samaguire 		(void) fprintf(stderr, gettext(
1255a192e900Samaguire 		    "%s: no such option/variable %s\n"), myname, param);
1256a192e900Samaguire 		return (-1);
1257a192e900Samaguire 	}
1258a192e900Samaguire 	if (parseable)
1259a192e900Samaguire 		return (0);
1260a192e900Samaguire 	(void) printf(gettext("\nRouting daemons:\n"));
1261a192e900Samaguire 	(void) printf("\n                      %s   %s\n", "STATE", "FMRI");
1262a192e900Samaguire 	if (ra_smf_cb(ra_print_state_cb, NULL, NULL) == -1)
1263a192e900Samaguire 		return (-1);
1264a192e900Samaguire 	return (0);
1265a192e900Samaguire }
1266a192e900Samaguire 
1267a192e900Samaguire /*
1268a192e900Samaguire  * Call scf_walk_fmri() with appropriate function, fmri, and data.
1269a192e900Samaguire  * A NULL fmri causes scf_walk_fmri() to run on all instances.  We make
1270a192e900Samaguire  * use of this many times in applying changes to the routing services.
1271a192e900Samaguire  */
1272a192e900Samaguire static int
ra_smf_cb(ra_smf_cb_t cbfunc,const char * fmri,void * data)1273a192e900Samaguire ra_smf_cb(ra_smf_cb_t cbfunc, const char *fmri, void *data)
1274a192e900Samaguire {
1275a192e900Samaguire 	scf_handle_t	*h;
1276a192e900Samaguire 	int		exit_status = 0;
1277a192e900Samaguire 
1278a192e900Samaguire 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
1279a192e900Samaguire 	    scf_handle_bind(h) == -1) {
1280a192e900Samaguire 		(void) fprintf(stderr, gettext(
1281a192e900Samaguire 		    "%s: cannot connect to SMF repository\n"), myname);
1282a192e900Samaguire 		return (-1);
1283a192e900Samaguire 	}
1284a192e900Samaguire 	return (scf_walk_fmri(h, fmri == NULL ? 0 : 1,
1285a192e900Samaguire 	    fmri == NULL ? NULL : (char **)&fmri, 0,
1286a192e900Samaguire 	    cbfunc, data, &exit_status, uu_die));
1287a192e900Samaguire }
1288a192e900Samaguire 
1289a192e900Samaguire /*
1290a192e900Samaguire  * Applies persistent configuration settings to current setup.
1291a192e900Samaguire  */
1292a192e900Samaguire static int
ra_set_current_opt_cb(void * data,scf_walkinfo_t * wip)1293a192e900Samaguire ra_set_current_opt_cb(void *data, scf_walkinfo_t *wip)
1294a192e900Samaguire {
1295a192e900Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_FALSE));
1296a192e900Samaguire }
1297a192e900Samaguire 
1298a192e900Samaguire /*
1299a192e900Samaguire  * Sets persistent value for option,  to be applied on next boot
1300a192e900Samaguire  * or by "routeadm -u".
1301a192e900Samaguire  */
1302a192e900Samaguire static int
ra_set_persistent_opt_cb(void * data,scf_walkinfo_t * wip)1303a192e900Samaguire ra_set_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1304a192e900Samaguire {
1305a192e900Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_FALSE));
1306a192e900Samaguire }
1307a192e900Samaguire 
1308a192e900Samaguire static int
ra_get_current_opt_cb(void * data,scf_walkinfo_t * wip)1309a192e900Samaguire ra_get_current_opt_cb(void *data, scf_walkinfo_t *wip)
1310a192e900Samaguire {
1311a192e900Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_TRUE));
1312a192e900Samaguire }
1313a192e900Samaguire 
1314a192e900Samaguire static int
ra_get_persistent_opt_cb(void * data,scf_walkinfo_t * wip)1315a192e900Samaguire ra_get_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1316a192e900Samaguire {
1317a192e900Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_TRUE));
1318a192e900Samaguire }
1319a192e900Samaguire 
1320ef2c19a1Samaguire static int
ra_routing_opt_set_cb(void * data,scf_walkinfo_t * wip)1321ef2c19a1Samaguire ra_routing_opt_set_cb(void *data, scf_walkinfo_t *wip)
1322ef2c19a1Samaguire {
1323ef2c19a1Samaguire 	return (ra_routing_opt_set_unset_cb(data, wip, B_TRUE));
1324ef2c19a1Samaguire }
1325ef2c19a1Samaguire 
1326ef2c19a1Samaguire static int
ra_routing_opt_unset_cb(void * data,scf_walkinfo_t * wip)1327ef2c19a1Samaguire ra_routing_opt_unset_cb(void *data, scf_walkinfo_t *wip)
1328ef2c19a1Samaguire {
1329ef2c19a1Samaguire 	return (ra_routing_opt_set_unset_cb(data, wip, B_FALSE));
1330ef2c19a1Samaguire }
1331ef2c19a1Samaguire 
1332ef2c19a1Samaguire /*
1333ef2c19a1Samaguire  * Notify network/routing-setup service that administrator has explicitly
1334ef2c19a1Samaguire  * set/reset ipv4(6)-routing value.  If no explicit setting of this value is
1335ef2c19a1Samaguire  * done,  ipv4-routing can be enabled in the situation when no default route can
1336ef2c19a1Samaguire  * be determined.
1337ef2c19a1Samaguire  */
1338ef2c19a1Samaguire static int
ra_routing_opt_set_unset_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t set)1339ef2c19a1Samaguire ra_routing_opt_set_unset_cb(raopt_t *raopt, scf_walkinfo_t *wip, boolean_t set)
1340ef2c19a1Samaguire {
1341ef2c19a1Samaguire 	scf_instance_t	*inst = wip->inst;
1342ef2c19a1Samaguire 	scf_handle_t	*h = scf_instance_handle(inst);
1343ef2c19a1Samaguire 
1344ef2c19a1Samaguire 	return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1345ef2c19a1Samaguire 	    raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING ?
1346ef2c19a1Samaguire 	    RA_PROP_IPV4_ROUTING_SET : RA_PROP_IPV6_ROUTING_SET,
1347ef2c19a1Samaguire 	    B_FALSE, set));
1348ef2c19a1Samaguire }
1349ef2c19a1Samaguire 
1350a192e900Samaguire /*
1351a192e900Samaguire  * Shared function that either sets or determines persistent or current
1352a192e900Samaguire  * state. Setting persistent state (for next boot) involves setting
1353a192e900Samaguire  * the general_ovr/enabled value to the current service state, and
1354a192e900Samaguire  * the general/enabled value to the desired (next-boot) state.
1355a192e900Samaguire  * Setting current state involves removing the temporary state
1356a192e900Samaguire  * setting so the persistent state has effect.
1357a192e900Samaguire  *
1358a192e900Samaguire  * Persistent state is reported as being enabled if any of the
1359a192e900Samaguire  * candidate services have a general/enabled value set to true,
1360a192e900Samaguire  * while current state is reported as being enabled if any of the
1361a192e900Samaguire  * candidate services has a general_ovr/enabled or general/enabled
1362a192e900Samaguire  * value set to true.
1363a192e900Samaguire  */
1364a192e900Samaguire static int
ra_get_set_opt_common_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t persistent,boolean_t get)1365a192e900Samaguire ra_get_set_opt_common_cb(raopt_t *raopt, scf_walkinfo_t *wip,
1366a192e900Samaguire     boolean_t persistent, boolean_t get)
1367a192e900Samaguire {
1368a192e900Samaguire 	const char		*inst_fmri = wip->fmri;
1369a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1370a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1371a192e900Samaguire 	scf_propertygroup_t	*routeadm_pg;
1372a192e900Samaguire 	boolean_t		persistent_state_enabled;
1373a192e900Samaguire 	boolean_t		temporary_state_enabled;
1374a192e900Samaguire 	boolean_t		current_state_enabled;
1375a192e900Samaguire 	boolean_t		curr_svc = B_TRUE;
1376a192e900Samaguire 	boolean_t		found_proto;
1377a192e900Samaguire 	char			**protolist = NULL;
1378a192e900Samaguire 	int			i, ret, numvalues = 0;
1379a192e900Samaguire 
1380a192e900Samaguire 	/*
1381a192e900Samaguire 	 * Ensure we are dealing with a routeadm-managed service.  If
1382a192e900Samaguire 	 * the FMRI used for walking instances is NULL,  it is reasonable
1383a192e900Samaguire 	 * that a service not have a routeadm property group as we will
1384a192e900Samaguire 	 * check all services in this case.
1385a192e900Samaguire 	 */
1386a192e900Samaguire 	if (ra_get_pg(h, inst, RA_PG_ROUTEADM, B_TRUE, raopt->opt_fmri != NULL,
1387a192e900Samaguire 	    &routeadm_pg) == -1) {
1388a192e900Samaguire 			/* Not a routing service, not an error. */
1389a192e900Samaguire 			if (scf_error() == SCF_ERROR_NOT_FOUND &&
1390a192e900Samaguire 			    raopt->opt_fmri == NULL)
1391a192e900Samaguire 				return (0);
1392a192e900Samaguire 			return (-1);
1393a192e900Samaguire 	}
1394a192e900Samaguire 	scf_pg_destroy(routeadm_pg);
1395a192e900Samaguire 
1396a192e900Samaguire 	/* Services with no "protocol" property are not routing daemons */
1397a192e900Samaguire 	if (raopt->opt_fmri == NULL && ra_get_prop_as_string(h, inst,
1398a192e900Samaguire 	    RA_PG_ROUTEADM, RA_PROP_PROTO, B_TRUE, B_FALSE, NULL, &numvalues,
1399a192e900Samaguire 	    &protolist) == -1) {
1400a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1401a192e900Samaguire 			return (0);
1402a192e900Samaguire 		return (-1);
1403a192e900Samaguire 	}
1404a192e900Samaguire 
1405a192e900Samaguire 	/*
1406a192e900Samaguire 	 * Skip invalid services based on flag settings.  Flags are used when
1407a192e900Samaguire 	 * we run callback functions on all instances to identify
1408a192e900Samaguire 	 * the correct instances to operate on.
1409a192e900Samaguire 	 */
1410a192e900Samaguire 	if (raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING) {
1411a192e900Samaguire 		found_proto = B_FALSE;
1412a192e900Samaguire 		if (protolist != NULL) {
1413a192e900Samaguire 			/* Check if protolist contains "ipv4" */
1414a192e900Samaguire 			for (i = 0; i < numvalues; i++) {
1415a192e900Samaguire 				if (protolist[i] != NULL && strcmp(
1416a192e900Samaguire 				    protolist[i], RA_PROPVAL_PROTO_IPV4) == 0)
1417a192e900Samaguire 					found_proto = B_TRUE;
1418a192e900Samaguire 			}
1419a192e900Samaguire 		}
1420a192e900Samaguire 		/* If not an ipv4 routing service, skip. */
1421a192e900Samaguire 		if (protolist == NULL || !found_proto) {
1422a192e900Samaguire 			ra_free_prop_values(numvalues, protolist);
1423a192e900Samaguire 			return (0);
1424a192e900Samaguire 		}
1425a192e900Samaguire 	}
1426a192e900Samaguire 	if (raopt->opt_flags & RA_SVC_FLAG_IPV6_ROUTING) {
1427a192e900Samaguire 		found_proto = B_FALSE;
1428a192e900Samaguire 		if (protolist != NULL) {
1429a192e900Samaguire 			/* Check if protolist contains "ipv6" */
1430a192e900Samaguire 			for (i = 0; i < numvalues; i++) {
1431a192e900Samaguire 				if (protolist[i] != NULL && strcmp(
1432a192e900Samaguire 				    protolist[i], RA_PROPVAL_PROTO_IPV6) == 0)
1433a192e900Samaguire 					found_proto = B_TRUE;
1434a192e900Samaguire 			}
1435a192e900Samaguire 		}
1436a192e900Samaguire 		/* If not an ipv6 routing service, skip. */
1437a192e900Samaguire 		if (protolist == NULL || !found_proto) {
1438a192e900Samaguire 			ra_free_prop_values(numvalues, protolist);
1439a192e900Samaguire 			return (0);
1440a192e900Samaguire 		}
1441ceb97a6aSamaguire 		/*
1442ceb97a6aSamaguire 		 * If no IPv6 interfaces are configured, do not apply
1443ceb97a6aSamaguire 		 * the "enable" state change to this IPv6 routing service.
1444ceb97a6aSamaguire 		 */
1445ceb97a6aSamaguire 		if (raopt->opt_enabled && ra_numv6intfs() < 1)
1446ceb97a6aSamaguire 			return (0);
1447a192e900Samaguire 	}
1448a192e900Samaguire 	ra_free_prop_values(numvalues, protolist);
1449a192e900Samaguire 
1450a192e900Samaguire 	/* If enabling routing services, select only current routing services */
1451a192e900Samaguire 	if (raopt->opt_fmri == NULL && !get && raopt->opt_enabled) {
1452a192e900Samaguire 		if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1453a192e900Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE,
1454a192e900Samaguire 		    &curr_svc) == -1)
1455a192e900Samaguire 			return (0);
1456a192e900Samaguire 		else if (!curr_svc && persistent) {
1457a192e900Samaguire 			/*
1458a192e900Samaguire 			 * We apply "current" routing changes to all routing
1459a192e900Samaguire 			 * daemons, whether current or not, so bail if
1460a192e900Samaguire 			 * we are trying to make a persistent update to a
1461a192e900Samaguire 			 * non-"routing-svc".
1462a192e900Samaguire 			 */
1463a192e900Samaguire 			return (0);
1464a192e900Samaguire 		}
1465a192e900Samaguire 	}
1466a192e900Samaguire 	if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
1467a192e900Samaguire 	    B_FALSE, B_TRUE, &persistent_state_enabled) == -1)
1468a192e900Samaguire 		return (-1);
1469a192e900Samaguire 
1470a192e900Samaguire 	current_state_enabled = persistent_state_enabled;
1471a192e900Samaguire 
1472a192e900Samaguire 	if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL_OVR,
1473a192e900Samaguire 	    SCF_PROPERTY_ENABLED, B_FALSE, B_FALSE, &temporary_state_enabled)
1474a192e900Samaguire 	    == 0)
1475a192e900Samaguire 		current_state_enabled = temporary_state_enabled;
1476a192e900Samaguire 
1477a192e900Samaguire 	if (get) {
1478a192e900Samaguire 		/*
1479a192e900Samaguire 		 * Persistent state is enabled if any services are
1480a192e900Samaguire 		 * persistently enabled, i.e. general/enabled == true).
1481a192e900Samaguire 		 * current state is enabled if any services
1482a192e900Samaguire 		 * services are currently enabled, i.e. if defined,
1483a192e900Samaguire 		 * general_ovr/enabled == true, if not, general/enabled == true.
1484a192e900Samaguire 		 */
1485a192e900Samaguire 		if (persistent)
1486a192e900Samaguire 			raopt->opt_enabled = raopt->opt_enabled ||
1487a192e900Samaguire 			    persistent_state_enabled;
1488a192e900Samaguire 		else
1489a192e900Samaguire 			raopt->opt_enabled = raopt->opt_enabled ||
1490a192e900Samaguire 			    current_state_enabled;
1491a192e900Samaguire 	} else {
1492a192e900Samaguire 		if (persistent) {
1493a192e900Samaguire 			/*
1494a192e900Samaguire 			 * For peristent state changes, from -e/-d,
1495a192e900Samaguire 			 * we set the general_ovr/enabled value to the
1496a192e900Samaguire 			 * current state (to ensure it is preserved),
1497a192e900Samaguire 			 * while setting the general/enabled value to
1498a192e900Samaguire 			 * the desired value.  This has the effect of
1499a192e900Samaguire 			 * the desired value coming into effect on next boot.
1500a192e900Samaguire 			 */
1501a192e900Samaguire 			ret = current_state_enabled ?
1502a192e900Samaguire 			    smf_enable_instance(inst_fmri, SMF_TEMPORARY) :
1503a192e900Samaguire 			    smf_disable_instance(inst_fmri, SMF_TEMPORARY);
1504a192e900Samaguire 			if (ret != 0) {
1505a192e900Samaguire 				(void) fprintf(stderr, gettext(
1506a192e900Samaguire 				    "%s: unexpected libscf error: %s\n"),
1507a192e900Samaguire 				    myname, scf_strerror(scf_error()));
1508a192e900Samaguire 				return (-1);
1509a192e900Samaguire 			}
1510a192e900Samaguire 			/*
1511a192e900Samaguire 			 * Refresh here so general_ovr/enabled state overrides
1512a192e900Samaguire 			 * general/enabled state.
1513a192e900Samaguire 			 */
1514a192e900Samaguire 			(void) smf_refresh_instance(inst_fmri);
1515a192e900Samaguire 			/*
1516a192e900Samaguire 			 * Now we can safely set the general/enabled value
1517a192e900Samaguire 			 * to the value we require on next boot (or
1518a192e900Samaguire 			 * "routeadm -u").
1519a192e900Samaguire 			 */
1520a192e900Samaguire 			ret = ra_set_boolean_prop(h, inst, SCF_PG_GENERAL,
1521a192e900Samaguire 			    SCF_PROPERTY_ENABLED, B_FALSE, raopt->opt_enabled);
1522a192e900Samaguire 			if (ret != 0)
1523a192e900Samaguire 				return (-1);
1524a192e900Samaguire 			/*
1525a192e900Samaguire 			 * Refresh here so general/enabled value is set.
1526a192e900Samaguire 			 */
1527a192e900Samaguire 			(void) smf_refresh_instance(inst_fmri);
1528a192e900Samaguire 			if (raopt->opt_fmri != NULL)
1529a192e900Samaguire 				return (0);
1530a192e900Samaguire 			(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
1531a192e900Samaguire 		} else {
15328b4b8c9cSamaguire 			/*
15338b4b8c9cSamaguire 			 * Refresh here to get latest property values prior
15348b4b8c9cSamaguire 			 * to starting daemon.
15358b4b8c9cSamaguire 			 */
15368b4b8c9cSamaguire 			(void) smf_refresh_instance(inst_fmri);
1537a192e900Samaguire 			/*
1538a192e900Samaguire 			 * For current changes (result of -u), we
1539a192e900Samaguire 			 * enable/disable depending on persistent value
1540a192e900Samaguire 			 * stored in general/enabled.  Here we disable
1541a192e900Samaguire 			 * old routing-svcs (identified by a current-routing-svc
1542a192e900Samaguire 			 * value of false) also.
1543a192e900Samaguire 			 */
1544a192e900Samaguire 			ret = persistent_state_enabled && curr_svc ?
1545a192e900Samaguire 			    smf_enable_instance(inst_fmri, 0) :
1546a192e900Samaguire 			    smf_disable_instance(inst_fmri, 0);
1547a192e900Samaguire 			if (ret != 0) {
1548a192e900Samaguire 				(void) fprintf(stderr, gettext(
1549a192e900Samaguire 				    "%s: unexpected libscf error: %s\n"),
1550a192e900Samaguire 				    myname, scf_strerror(scf_error()));
1551a192e900Samaguire 				return (-1);
1552a192e900Samaguire 			}
15538b4b8c9cSamaguire 			if (current_state_enabled && persistent_state_enabled) {
15548b4b8c9cSamaguire 				/*
15558b4b8c9cSamaguire 				 * Instance was already enabled, so we restart
15568b4b8c9cSamaguire 				 * to get latest property values.  This covers
15578b4b8c9cSamaguire 				 * the case where users update properties
15588b4b8c9cSamaguire 				 * via routeadm -m, and issue an update.  The
15598b4b8c9cSamaguire 				 * daemon should be running with the latest
15608b4b8c9cSamaguire 				 * property values.
15618b4b8c9cSamaguire 				 */
15628b4b8c9cSamaguire 				(void) smf_restart_instance(inst_fmri);
15638b4b8c9cSamaguire 			}
1564a192e900Samaguire 		}
1565a192e900Samaguire 	}
1566a192e900Samaguire 	return (0);
1567a192e900Samaguire }
1568a192e900Samaguire 
1569a192e900Samaguire static int
ra_set_default_opt_cb(void * data,scf_walkinfo_t * wip)1570a192e900Samaguire ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip)
1571a192e900Samaguire {
1572a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1573a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1574a192e900Samaguire 	raopt_t			*raopt = data;
1575a192e900Samaguire 
1576a192e900Samaguire 	return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1577a192e900Samaguire 	    raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled));
1578a192e900Samaguire }
1579a192e900Samaguire 
1580a192e900Samaguire static int
ra_get_default_opt_cb(void * data,scf_walkinfo_t * wip)1581a192e900Samaguire ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip)
1582a192e900Samaguire {
1583a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1584a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1585a192e900Samaguire 	raopt_t			*raopt = data;
1586a192e900Samaguire 
1587a192e900Samaguire 	return (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1588a192e900Samaguire 	    raopt->opt_default_prop, B_TRUE, B_TRUE,
1589a192e900Samaguire 	    &(raopt->opt_default_enabled)));
1590a192e900Samaguire }
1591a192e900Samaguire 
1592a192e900Samaguire /*
1593a192e900Samaguire  * Callbacks to set/retrieve persistent/default routing variable values.
1594a192e900Samaguire  * The set functions use the value stored in the var_value/var_default_value
1595a192e900Samaguire  * field of the associated ra_var_t, while the retrieval functions store
1596a192e900Samaguire  * the value retrieved in that field.
1597a192e900Samaguire  */
1598a192e900Samaguire static int
ra_get_persistent_var_cb(void * data,scf_walkinfo_t * wip)1599a192e900Samaguire ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1600a192e900Samaguire {
1601a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1602a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1603a192e900Samaguire 	ravar_t			*ravar = data;
1604a192e900Samaguire 
1605a192e900Samaguire 	return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
1606a192e900Samaguire 	    ravar->var_prop, B_TRUE, B_TRUE, NULL, &ravar->var_value));
1607a192e900Samaguire }
1608a192e900Samaguire 
1609a192e900Samaguire static int
ra_set_persistent_var_cb(void * data,scf_walkinfo_t * wip)1610a192e900Samaguire ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1611a192e900Samaguire {
1612a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1613a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1614a192e900Samaguire 	ravar_t			*ravar = data;
1615a192e900Samaguire 
1616a192e900Samaguire 	return (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
1617a192e900Samaguire 	    ravar->var_prop, SCF_TYPE_INVALID, B_FALSE, 1,
1618a192e900Samaguire 	    (const char **)&ravar->var_value));
1619a192e900Samaguire }
1620a192e900Samaguire 
1621a192e900Samaguire static int
ra_get_default_var_cb(void * data,scf_walkinfo_t * wip)1622a192e900Samaguire ra_get_default_var_cb(void *data, scf_walkinfo_t *wip)
1623a192e900Samaguire {
1624a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1625a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1626a192e900Samaguire 	ravar_t			*ravar = data;
1627a192e900Samaguire 
1628a192e900Samaguire 	return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
1629a192e900Samaguire 	    ravar->var_default_prop, B_TRUE, B_TRUE, NULL,
1630a192e900Samaguire 	    &ravar->var_default_value));
1631a192e900Samaguire }
1632a192e900Samaguire 
1633a192e900Samaguire /*
1634a192e900Samaguire  * Depending on the value of the boolean_t * passed in,  this callback
1635a192e900Samaguire  * either marks the relevant service(s) as current-routing-svcs (or unmarking)
1636a192e900Samaguire  * by setting that property to true or false.  When routing services
1637a192e900Samaguire  * are to be enabled,  the a current-routing-svc value of true flags the
1638a192e900Samaguire  * service as one to be enabled.
1639a192e900Samaguire  */
1640a192e900Samaguire static int
ra_mark_routing_svcs_cb(void * data,scf_walkinfo_t * wip)1641a192e900Samaguire ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip)
1642a192e900Samaguire {
1643a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1644a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1645a192e900Samaguire 	boolean_t		*mark = data;
1646a192e900Samaguire 	boolean_t		marked;
1647a192e900Samaguire 	int			numvalues = 0;
1648a192e900Samaguire 	char			**protolist = NULL;
1649a192e900Samaguire 
1650a192e900Samaguire 	/* Check we are dealing with a routing daemon service */
1651a192e900Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1652a192e900Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
1653a192e900Samaguire 		return (0);
1654a192e900Samaguire 	ra_free_prop_values(numvalues, protolist);
1655a192e900Samaguire 	if (*mark)
1656a192e900Samaguire 		return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1657a192e900Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_TRUE));
1658a192e900Samaguire 	/* Unmark service. */
1659a192e900Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1660a192e900Samaguire 	    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE, &marked) == 0 && marked)
1661a192e900Samaguire 		return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1662a192e900Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE));
1663a192e900Samaguire 	return (0);
1664a192e900Samaguire }
1665a192e900Samaguire 
1666a192e900Samaguire /*
1667a192e900Samaguire  * List property values for all properties in the "routing" property
1668a192e900Samaguire  * group of the routing service instance.
1669a192e900Samaguire  */
1670a192e900Samaguire 
1671a192e900Samaguire /* ARGSUSED0 */
1672a192e900Samaguire static int
ra_list_props_cb(void * data,scf_walkinfo_t * wip)1673a192e900Samaguire ra_list_props_cb(void *data, scf_walkinfo_t *wip)
1674a192e900Samaguire {
1675a192e900Samaguire 	const char		*inst_fmri = wip->fmri;
1676a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1677a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1678a192e900Samaguire 	scf_iter_t		*propiter, *valiter;
1679a192e900Samaguire 	scf_propertygroup_t	*pg;
1680a192e900Samaguire 	scf_property_t		*prop;
1681a192e900Samaguire 	scf_value_t		*val;
1682a192e900Samaguire 	char			**protolist = NULL, *pnamebuf, *valbuf;
1683a192e900Samaguire 	ssize_t			pnamelen, vallen;
1684a192e900Samaguire 	int			numvalues = 0;
1685a192e900Samaguire 	int			propiterret, valiterret, retval = 0;
1686a192e900Samaguire 
1687a192e900Samaguire 	/* Services with no "protocol" property are not routing daemons */
1688a192e900Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1689a192e900Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
1690a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1691a192e900Samaguire 			(void) fprintf(stderr,
1692a192e900Samaguire 			    gettext("%s: %s is not a routing daemon service\n"),
1693a192e900Samaguire 			    myname, inst_fmri);
1694a192e900Samaguire 		else
1695a192e900Samaguire 			(void) fprintf(stderr,
1696a192e900Samaguire 			    gettext("%s: unexpected libscf error: %s\n"),
1697a192e900Samaguire 			    myname, scf_strerror(scf_error()));
1698a192e900Samaguire 		ra_free_prop_values(numvalues, protolist);
1699a192e900Samaguire 		return (-1);
1700a192e900Samaguire 	}
1701a192e900Samaguire 	ra_free_prop_values(numvalues, protolist);
1702a192e900Samaguire 
1703a192e900Samaguire 	if (ra_get_pg(h, inst, RA_PG_ROUTING, B_TRUE, B_FALSE, &pg) == -1) {
1704a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1705a192e900Samaguire 			(void) printf("%s: no %s property group for %s\n",
1706a192e900Samaguire 			    myname, RA_PG_ROUTING, inst_fmri);
1707a192e900Samaguire 			return (0);
1708a192e900Samaguire 		}
1709a192e900Samaguire 		(void) fprintf(stderr,
1710a192e900Samaguire 		    gettext("%s: unexpected libscf error: %s\n"),
1711a192e900Samaguire 		    myname, scf_strerror(scf_error()));
1712a192e900Samaguire 		return (-1);
1713a192e900Samaguire 	}
1714a192e900Samaguire 
1715a192e900Samaguire 	(void) printf("%s:\n", inst_fmri);
1716a192e900Samaguire 
1717a192e900Samaguire 	/* Create an iterator to walk through all properties */
1718a192e900Samaguire 	if ((propiter = scf_iter_create(h)) == NULL ||
1719a192e900Samaguire 	    (prop = scf_property_create(h)) == NULL ||
1720a192e900Samaguire 	    scf_iter_pg_properties(propiter, pg) != 0) {
1721a192e900Samaguire 		(void) fprintf(stderr, gettext
1722a192e900Samaguire 		    ("%s: could not iterate through properties for %s: %s\n"),
1723a192e900Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
1724a192e900Samaguire 	}
1725a192e900Samaguire 	while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) {
1726a192e900Samaguire 		if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1)
1727a192e900Samaguire 		    == 0) {
1728a192e900Samaguire 			(void) fprintf(stderr, gettext("%s: could not retrieve "
1729a192e900Samaguire 			    "property name for instance %s: %s\n"), myname,
1730a192e900Samaguire 			    inst_fmri, scf_strerror(scf_error()));
1731a192e900Samaguire 			retval = -1;
1732a192e900Samaguire 			break;
1733a192e900Samaguire 		}
1734a192e900Samaguire 		if ((pnamebuf = malloc(pnamelen)) == NULL) {
1735a192e900Samaguire 			(void) fprintf(stderr,
1736a192e900Samaguire 			    gettext("%s: out of memory\n"), myname);
1737a192e900Samaguire 			retval = -1;
1738a192e900Samaguire 			break;
1739a192e900Samaguire 		}
1740a192e900Samaguire 		(void) scf_property_get_name(prop, pnamebuf,
1741a192e900Samaguire 		    pnamelen);
1742a192e900Samaguire 		(void) printf("\t%s = ", pnamebuf);
1743a192e900Samaguire 		if ((valiter = scf_iter_create(h)) == NULL ||
1744a192e900Samaguire 		    (val = scf_value_create(h)) == NULL ||
1745a192e900Samaguire 		    scf_iter_property_values(valiter, prop)
1746a192e900Samaguire 		    != 0) {
1747a192e900Samaguire 			(void) fprintf(stderr, gettext
1748a192e900Samaguire 			    ("%s: could not iterate through "
1749a192e900Samaguire 			    "properties for %s: %s\n"), myname, inst_fmri,
1750a192e900Samaguire 			    scf_strerror(scf_error()));
1751a192e900Samaguire 			scf_value_destroy(val);
1752a192e900Samaguire 			scf_iter_destroy(valiter);
1753a192e900Samaguire 			free(pnamebuf);
1754a192e900Samaguire 			retval = -1;
1755a192e900Samaguire 			break;
1756a192e900Samaguire 		}
1757a192e900Samaguire 		while ((valiterret = scf_iter_next_value(valiter, val)) == 1) {
1758a192e900Samaguire 			if ((vallen = scf_value_get_as_string
1759a192e900Samaguire 			    (val, NULL, 0) + 1) == 0) {
1760a192e900Samaguire 				(void) fprintf(stderr, gettext
1761a192e900Samaguire 				    ("%s: could not retrieve "
1762a192e900Samaguire 				    "property value for instance %s, "
1763a192e900Samaguire 				    "property %s: %s\n"), myname, inst_fmri,
1764a192e900Samaguire 				    pnamebuf, scf_strerror(scf_error()));
1765a192e900Samaguire 				retval = -1;
1766a192e900Samaguire 			} else if ((valbuf = malloc(vallen)) == NULL) {
1767a192e900Samaguire 				(void) fprintf(stderr,
1768a192e900Samaguire 				    gettext("%s: out of memory\n"), myname);
1769a192e900Samaguire 				retval = -1;
1770a192e900Samaguire 			}
1771a192e900Samaguire 			if (retval == -1) {
1772a192e900Samaguire 				scf_iter_destroy(valiter);
1773a192e900Samaguire 				scf_value_destroy(val);
1774a192e900Samaguire 				free(pnamebuf);
1775a192e900Samaguire 				goto out;
1776a192e900Samaguire 			}
1777a192e900Samaguire 			(void) scf_value_get_as_string(val, valbuf, vallen);
1778a192e900Samaguire 			(void) printf("%s ", valbuf);
1779a192e900Samaguire 			free(valbuf);
1780a192e900Samaguire 		}
1781a192e900Samaguire 		(void) printf("\n");
1782a192e900Samaguire 		scf_iter_destroy(valiter);
1783a192e900Samaguire 		scf_value_destroy(val);
1784a192e900Samaguire 		free(pnamebuf);
1785a192e900Samaguire 		if (valiterret == -1) {
1786a192e900Samaguire 			(void) fprintf(stderr,
1787a192e900Samaguire 			    gettext("%s: could not iterate through"
1788a192e900Samaguire 			    "properties for %s: %s\n"), myname, inst_fmri,
1789a192e900Samaguire 			    scf_strerror(scf_error()));
1790a192e900Samaguire 			retval = -1;
1791a192e900Samaguire 			break;
1792a192e900Samaguire 		}
1793a192e900Samaguire 	}
1794a192e900Samaguire out:
1795a192e900Samaguire 	scf_iter_destroy(propiter);
1796a192e900Samaguire 	scf_property_destroy(prop);
1797a192e900Samaguire 	scf_pg_destroy(pg);
1798a192e900Samaguire 	if (propiterret == -1)
1799a192e900Samaguire 		(void) fprintf(stderr, gettext
1800a192e900Samaguire 		    ("%s: could not iterate through properties for %s: %s\n"),
1801a192e900Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
1802a192e900Samaguire 	return (retval);
1803a192e900Samaguire }
1804a192e900Samaguire 
1805a192e900Samaguire /*
1806a192e900Samaguire  * Modify property with name stored in passed-in ra_prop_t to have
1807a192e900Samaguire  * the assocatied values.  Only works for existing properties in
1808a192e900Samaguire  * the "routing" property group for routing daemon services,  so all
1809a192e900Samaguire  * routing daemons should place configurable options in that group.
1810a192e900Samaguire  */
1811a192e900Samaguire static int
ra_modify_props_cb(void * data,scf_walkinfo_t * wip)1812a192e900Samaguire ra_modify_props_cb(void *data, scf_walkinfo_t *wip)
1813a192e900Samaguire {
1814a192e900Samaguire 	const char		*inst_fmri = wip->fmri;
1815a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1816a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1817a192e900Samaguire 	ra_prop_t		*raprop = data;
1818a192e900Samaguire 	int			numvalues = 0;
1819a192e900Samaguire 	char			**protolist = NULL;
1820a192e900Samaguire 
1821a192e900Samaguire 	/* Services with no "protocol" property are not routing daemons */
1822a192e900Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1823a192e900Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
1824a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
1825a192e900Samaguire 			(void) fprintf(stderr,
1826a192e900Samaguire 			    gettext("%s: %s is not a routing daemon service\n"),
1827a192e900Samaguire 			    myname, inst_fmri);
1828a192e900Samaguire 		else
1829a192e900Samaguire 			(void) fprintf(stderr,
1830a192e900Samaguire 			    gettext("%s: unexpected libscf error: %s\n"),
1831a192e900Samaguire 			    myname, scf_strerror(scf_error()));
1832a192e900Samaguire 		ra_free_prop_values(numvalues, protolist);
1833a192e900Samaguire 		return (-1);
1834a192e900Samaguire 	}
1835a192e900Samaguire 	ra_free_prop_values(numvalues, protolist);
1836a192e900Samaguire 
1837a192e900Samaguire 	if (ra_set_prop_from_string(h, inst, RA_PG_ROUTING, raprop->prop_name,
1838a192e900Samaguire 	    SCF_TYPE_INVALID, B_FALSE, raprop->prop_numvalues,
1839a192e900Samaguire 	    (const char **)raprop->prop_values) == -1)
1840a192e900Samaguire 		return (-1);
1841a192e900Samaguire 
1842a192e900Samaguire 	(void) smf_refresh_instance(inst_fmri);
1843a192e900Samaguire 	return (0);
1844a192e900Samaguire }
1845a192e900Samaguire 
1846a192e900Samaguire /*
1847a192e900Samaguire  * Display FMRI, state for each routing daemon service.
1848a192e900Samaguire  */
1849a192e900Samaguire 
1850a192e900Samaguire /* ARGSUSED0 */
1851a192e900Samaguire static int
ra_print_state_cb(void * data,scf_walkinfo_t * wip)1852a192e900Samaguire ra_print_state_cb(void *data, scf_walkinfo_t *wip)
1853a192e900Samaguire {
1854a192e900Samaguire 	const char		*inst_fmri = wip->fmri;
1855a192e900Samaguire 	scf_instance_t		*inst = wip->inst;
1856a192e900Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
1857a192e900Samaguire 	char			*inst_state, **protolist = NULL;
1858a192e900Samaguire 	int			numvalues = 0;
1859a192e900Samaguire 
1860a192e900Samaguire 	/* Ensure service is a routing daemon */
1861a192e900Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1862a192e900Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
1863a192e900Samaguire 		return (0);
1864a192e900Samaguire 	ra_free_prop_values(numvalues, protolist);
1865a192e900Samaguire 
1866a192e900Samaguire 	if ((inst_state = smf_get_state(inst_fmri)) == NULL) {
1867a192e900Samaguire 		(void) fprintf(stderr,
1868a192e900Samaguire 		    gettext("%s: could not retrieve state for %s: %s\n"),
1869a192e900Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
1870a192e900Samaguire 		return (-1);
1871a192e900Samaguire 	}
1872a192e900Samaguire 	(void) printf("%27s   %2s\n", inst_state, inst_fmri);
1873a192e900Samaguire 	free(inst_state);
1874a192e900Samaguire 
1875a192e900Samaguire 	return (0);
1876a192e900Samaguire }
1877a192e900Samaguire 
1878a192e900Samaguire static int
ra_get_pg(scf_handle_t * h,scf_instance_t * inst,const char * pgname,boolean_t composed,boolean_t required,scf_propertygroup_t ** pg)1879a192e900Samaguire ra_get_pg(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
1880a192e900Samaguire     boolean_t composed, boolean_t required, scf_propertygroup_t **pg)
1881a192e900Samaguire {
1882a192e900Samaguire 	/* Retrieve (possibly composed) property group for instance */
1883a192e900Samaguire 	if ((*pg = scf_pg_create(h)) == NULL || (composed &&
1884a192e900Samaguire 	    scf_instance_get_pg_composed(inst, NULL, pgname, *pg) != 0) ||
1885a192e900Samaguire 	    (!composed && scf_instance_get_pg(inst, pgname, *pg) != 0)) {
1886a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1887a192e900Samaguire 			if (required)
1888a192e900Samaguire 				(void) fprintf(stderr, gettext(
1889a192e900Samaguire 				    "%s: no such property group %s\n"),
1890a192e900Samaguire 				    myname, pgname);
1891a192e900Samaguire 			return (-1);
1892a192e900Samaguire 		}
1893a192e900Samaguire 		if (required)
1894a192e900Samaguire 			(void) fprintf(stderr, gettext(
1895a192e900Samaguire 			    "%s: unexpected libscf error: %s\n"), myname,
1896a192e900Samaguire 			    scf_strerror(scf_error()));
1897a192e900Samaguire 		return (-1);
1898a192e900Samaguire 	}
1899a192e900Samaguire 	return (0);
1900a192e900Samaguire }
1901a192e900Samaguire 
1902a192e900Samaguire static int
ra_get_boolean_prop(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,boolean_t * val)1903a192e900Samaguire ra_get_boolean_prop(scf_handle_t *h, scf_instance_t *inst,
1904a192e900Samaguire     const char *pgname, const char *propname, boolean_t composed,
1905a192e900Samaguire     boolean_t required, boolean_t *val)
1906a192e900Samaguire {
1907a192e900Samaguire 	char	*valstr;
1908a192e900Samaguire 
1909a192e900Samaguire 	if (ra_get_single_prop_as_string(h, inst, pgname, propname,
1910a192e900Samaguire 	    composed, required, NULL, &valstr) != 0)
1911a192e900Samaguire 		return (-1);
1912a192e900Samaguire 	*val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0;
1913a192e900Samaguire 	free(valstr);
1914a192e900Samaguire 	return (0);
1915a192e900Samaguire }
1916a192e900Samaguire 
1917a192e900Samaguire static int
ra_get_single_prop_as_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,scf_type_t * type,char ** value)1918a192e900Samaguire ra_get_single_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
1919a192e900Samaguire     const char *pgname, const char *propname, boolean_t composed,
1920a192e900Samaguire     boolean_t required, scf_type_t *type, char **value)
1921a192e900Samaguire {
1922a192e900Samaguire 	char	**values;
1923a192e900Samaguire 	int	numvalues = 1;
1924a192e900Samaguire 
1925a192e900Samaguire 	if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required,
1926a192e900Samaguire 	    type, &numvalues, &values) == -1)
1927a192e900Samaguire 		return (-1);
1928a192e900Samaguire 	*value = values[0];
1929a192e900Samaguire 	free(values);
1930a192e900Samaguire 	return (0);
1931a192e900Samaguire }
1932a192e900Samaguire 
1933a192e900Samaguire /*
1934a192e900Samaguire  * Retrieve property named in propname,  possibly using the composed
1935a192e900Samaguire  * property group view (union of instance and service-level properties,
1936a192e900Samaguire  * where instance-level properties override service-level values).
1937a192e900Samaguire  */
1938a192e900Samaguire static int
ra_get_prop_as_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,scf_type_t * type,int * numvalues,char *** values)1939a192e900Samaguire ra_get_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
1940a192e900Samaguire     const char *pgname, const char *propname, boolean_t composed,
1941a192e900Samaguire     boolean_t required, scf_type_t *type, int *numvalues, char ***values)
1942a192e900Samaguire {
1943a192e900Samaguire 	scf_propertygroup_t	*pg = NULL;
1944a192e900Samaguire 	scf_property_t		*prop = NULL;
1945a192e900Samaguire 	scf_iter_t		*valiter = NULL;
1946a192e900Samaguire 	scf_value_t		*val = NULL;
1947a192e900Samaguire 	ssize_t			vallen = 0;
1948a192e900Samaguire 	int			valiterret, i, numvalues_retrieved, ret = 0;
1949a192e900Samaguire 
1950a192e900Samaguire 	if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1)
1951a192e900Samaguire 		return (-1);
1952a192e900Samaguire 
1953a192e900Samaguire 	*values = NULL;
1954a192e900Samaguire 	/*
1955a192e900Samaguire 	 * Retrieve values. All values routeadm needs to retrieve
1956a192e900Samaguire 	 * (bar those gathered by routeadm -l), are known to be single-valued.
1957a192e900Samaguire 	 */
1958a192e900Samaguire 	if ((prop = scf_property_create(h)) == NULL)
1959a192e900Samaguire 		goto error;
1960a192e900Samaguire 	if (scf_pg_get_property(pg, propname, prop) != 0) {
1961a192e900Samaguire 		*numvalues = 0;
1962a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1963a192e900Samaguire 			if (required)
1964a192e900Samaguire 				(void) fprintf(stderr, gettext(
1965a192e900Samaguire 				    "%s: property %s/%s not found\n"),
1966a192e900Samaguire 				    myname, pgname, propname);
1967a192e900Samaguire 			ret = -1;
1968a192e900Samaguire 			goto out;
1969a192e900Samaguire 		}
1970a192e900Samaguire 		goto error;
1971a192e900Samaguire 	}
1972a192e900Samaguire 	if ((val = scf_value_create(h)) == NULL &&
1973a192e900Samaguire 	    scf_property_get_value(prop, val) != 0 ||
1974a192e900Samaguire 	    (valiter = scf_iter_create(h)) == NULL ||
1975a192e900Samaguire 	    scf_iter_property_values(valiter, prop) != 0)
1976a192e900Samaguire 		goto error;
1977a192e900Samaguire 	/* retrieve each value */
1978a192e900Samaguire 	for (numvalues_retrieved = 0;
1979a192e900Samaguire 	    (valiterret = scf_iter_next_value(valiter, val)) == 1;
1980a192e900Samaguire 	    numvalues_retrieved++) {
1981a192e900Samaguire 		if ((vallen = scf_value_get_as_string
1982a192e900Samaguire 		    (val, NULL, 0) + 1) == 0)
1983a192e900Samaguire 			goto error;
1984a192e900Samaguire 		if ((*values = realloc(*values,
1985a192e900Samaguire 		    sizeof (*values) + sizeof (char *))) == NULL ||
1986a192e900Samaguire 		    ((*values)[numvalues_retrieved] = malloc(vallen)) == NULL) {
1987a192e900Samaguire 			(void) fprintf(stderr, gettext(
1988a192e900Samaguire 			    "%s: out of memory\n"), myname);
1989a192e900Samaguire 			ret = -1;
1990a192e900Samaguire 			goto out;
1991a192e900Samaguire 		}
1992a192e900Samaguire 		(void) scf_value_get_as_string(val,
1993a192e900Samaguire 		    (*values)[numvalues_retrieved], vallen);
1994a192e900Samaguire 	}
1995a192e900Samaguire 	if (valiterret == -1)
1996a192e900Samaguire 		goto error;
1997a192e900Samaguire 	/*
1998a192e900Samaguire 	 * if *numvalues != 0, it holds expected number of values.  If a
1999a192e900Samaguire 	 * different number are found, it is an error.
2000a192e900Samaguire 	 */
2001a192e900Samaguire 	if (*numvalues != 0 && *numvalues != numvalues_retrieved) {
2002a192e900Samaguire 		(void) fprintf(stderr, gettext(
2003a192e900Samaguire 		    "%s: got %d values for property %s/%s, expected %d\n"),
2004a192e900Samaguire 		    myname, numvalues_retrieved, pgname, propname, *numvalues);
2005a192e900Samaguire 		ret = -1;
2006a192e900Samaguire 		goto out;
2007a192e900Samaguire 	}
2008a192e900Samaguire 	*numvalues = numvalues_retrieved;
2009a192e900Samaguire 
2010a192e900Samaguire 	/* Retrieve property type if required. */
2011a192e900Samaguire 	if (type != NULL)
2012a192e900Samaguire 		(void) scf_property_type(prop, type);
2013a192e900Samaguire 
2014a192e900Samaguire 	goto out;
2015a192e900Samaguire error:
2016a192e900Samaguire 	if (scf_error() == SCF_ERROR_NOT_FOUND) {
2017a192e900Samaguire 		(void) fprintf(stderr, gettext(
2018a192e900Samaguire 		    "%s: property %s not found"), myname, propname);
2019a192e900Samaguire 	} else {
2020a192e900Samaguire 		(void) fprintf(stderr, gettext(
2021a192e900Samaguire 		    "%s: unexpected libscf error: %s, "), myname);
2022a192e900Samaguire 	}
2023a192e900Samaguire 	for (i = 0; i < numvalues_retrieved; i++)
2024a192e900Samaguire 		free((*values)[i]);
2025a192e900Samaguire 	if (*values != NULL)
2026a192e900Samaguire 		free(*values);
2027a192e900Samaguire 
2028a192e900Samaguire 	ret = -1;
2029a192e900Samaguire out:
2030a192e900Samaguire 	if (val != NULL)
2031a192e900Samaguire 		scf_value_destroy(val);
2032a192e900Samaguire 	if (valiter != NULL)
2033a192e900Samaguire 		scf_iter_destroy(valiter);
2034a192e900Samaguire 	if (prop != NULL)
2035a192e900Samaguire 		scf_property_destroy(prop);
2036a192e900Samaguire 	if (pg != NULL)
2037a192e900Samaguire 		scf_pg_destroy(pg);
2038a192e900Samaguire 	return (ret);
2039a192e900Samaguire }
2040a192e900Samaguire 
2041a192e900Samaguire static void
ra_free_prop_values(int numvalues,char ** values)2042a192e900Samaguire ra_free_prop_values(int numvalues, char **values)
2043a192e900Samaguire {
2044a192e900Samaguire 	int	i;
2045a192e900Samaguire 	if (values != NULL) {
2046a192e900Samaguire 		for (i = 0; i < numvalues; i++)
2047a192e900Samaguire 			free(values[i]);
2048a192e900Samaguire 		free(values);
2049a192e900Samaguire 	}
2050a192e900Samaguire }
2051a192e900Samaguire 
2052a192e900Samaguire static int
ra_set_boolean_prop(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * prop,boolean_t create,boolean_t propval)2053a192e900Samaguire ra_set_boolean_prop(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
2054a192e900Samaguire     const char *prop, boolean_t create, boolean_t propval)
2055a192e900Samaguire {
2056a192e900Samaguire 	const char	*val = propval ? RA_PROPVAL_BOOLEAN_TRUE :
2057a192e900Samaguire 	    RA_PROPVAL_BOOLEAN_FALSE;
2058a192e900Samaguire 
2059a192e900Samaguire 	return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN,
2060a192e900Samaguire 	    create, 1, &val));
2061a192e900Samaguire }
2062a192e900Samaguire 
2063a192e900Samaguire /*
2064a192e900Samaguire  * Set the property named in propname to the values passed in in the propvals
2065a192e900Samaguire  * array.  Only create a new property if "create" is true.
2066a192e900Samaguire  */
2067a192e900Samaguire static int
ra_set_prop_from_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,scf_type_t proptype,boolean_t create,int numpropvals,const char ** propvals)2068a192e900Samaguire ra_set_prop_from_string(scf_handle_t *h, scf_instance_t *inst,
2069a192e900Samaguire     const char *pgname, const char *propname, scf_type_t proptype,
2070a192e900Samaguire     boolean_t create, int numpropvals, const char **propvals)
2071a192e900Samaguire {
2072a192e900Samaguire 	scf_propertygroup_t	*instpg = NULL, *cpg = NULL;
2073a192e900Samaguire 	scf_type_t		oldproptype, newproptype = proptype;
2074a192e900Samaguire 	scf_property_t		*prop = NULL;
2075a192e900Samaguire 	scf_value_t		**values = NULL;
2076a192e900Samaguire 	scf_transaction_t	*tx = NULL;
2077a192e900Samaguire 	scf_transaction_entry_t	*ent = NULL;
2078a192e900Samaguire 	boolean_t		new = B_FALSE;
2079a192e900Samaguire 	int			i, retval, numvalues = 0, ret = 0;
2080a192e900Samaguire 	char			*pgtype = NULL, **ovalues;
2081a192e900Samaguire 	ssize_t			typelen;
2082a192e900Samaguire 
2083a192e900Samaguire 	/* Firstly, does property exist? If not, and create is false, bail */
2084a192e900Samaguire 	if (ra_get_prop_as_string(h, inst, pgname, propname, B_TRUE,
2085a192e900Samaguire 	    B_FALSE, &oldproptype, &numvalues, &ovalues) == -1) {
2086a192e900Samaguire 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2087a192e900Samaguire 			goto error;
2088a192e900Samaguire 		if (!create) {
2089a192e900Samaguire 			(void) fprintf(stderr, gettext(
2090a192e900Samaguire 			    "%s: no such property %s/%s\n"), myname, pgname,
2091a192e900Samaguire 			    propname);
2092a192e900Samaguire 			return (-1);
2093a192e900Samaguire 		}
2094a192e900Samaguire 	} else
2095a192e900Samaguire 		ra_free_prop_values(numvalues, ovalues);
2096a192e900Samaguire 
2097a192e900Samaguire 	/* Use old property type */
2098a192e900Samaguire 	if (proptype == SCF_TYPE_INVALID)
2099a192e900Samaguire 		newproptype = oldproptype;
2100a192e900Samaguire 
2101a192e900Samaguire 	/*
2102a192e900Samaguire 	 * Does property group exist at instance level?  If not, we need to
2103a192e900Samaguire 	 * create it,  since the composed view of the property group did
2104a192e900Samaguire 	 * contain the property.  We never modify properties at the service
2105a192e900Samaguire 	 * level,  as it`s possible that multiple instances will inherit those
2106a192e900Samaguire 	 * settings.
2107a192e900Samaguire 	 */
2108a192e900Samaguire 	if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) {
2109a192e900Samaguire 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2110a192e900Samaguire 			goto error;
2111a192e900Samaguire 		/* Ensure pg exists at service level, get composed pg */
2112a192e900Samaguire 		if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1)
2113a192e900Samaguire 			goto error;
2114a192e900Samaguire 
2115a192e900Samaguire 		/* Create instance-level property group */
2116a192e900Samaguire 		if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0)
2117a192e900Samaguire 			goto error;
2118a192e900Samaguire 		if ((pgtype = malloc(typelen)) == NULL) {
2119a192e900Samaguire 			(void) fprintf(stderr, gettext(
2120a192e900Samaguire 			    "%s: out of memory\n"), myname);
2121a192e900Samaguire 			goto error;
2122a192e900Samaguire 		}
2123a192e900Samaguire 		(void) scf_pg_get_type(cpg, pgtype, typelen);
2124a192e900Samaguire 		if ((instpg = scf_pg_create(h)) == NULL ||
2125a192e900Samaguire 		    scf_instance_add_pg(inst, pgname, pgtype, 0, instpg)
2126a192e900Samaguire 		    == -1) {
2127a192e900Samaguire 			(void) fprintf(stderr, gettext(
2128a192e900Samaguire 			    "%s: could not create property group %s\n"),
2129a192e900Samaguire 			    myname, pgname);
2130a192e900Samaguire 			goto error;
2131a192e900Samaguire 		}
2132a192e900Samaguire 	}
2133a192e900Samaguire 	if ((prop = scf_property_create(h)) == NULL)
2134a192e900Samaguire 		goto error;
2135a192e900Samaguire 	if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) {
2136a192e900Samaguire 		(void) fprintf(stderr, gettext("%s: out of memory"), myname);
2137a192e900Samaguire 		goto error;
2138a192e900Samaguire 	}
2139a192e900Samaguire 	if (scf_pg_get_property(instpg, propname, prop) != 0) {
2140a192e900Samaguire 		/* New property? */
2141a192e900Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
2142a192e900Samaguire 			new = B_TRUE;
2143a192e900Samaguire 		else
2144a192e900Samaguire 			goto error;
2145a192e900Samaguire 	}
2146a192e900Samaguire 	if ((tx = scf_transaction_create(h)) == NULL ||
2147a192e900Samaguire 	    (ent = scf_entry_create(h)) == NULL)
2148a192e900Samaguire 		goto error;
2149a192e900Samaguire retry:
2150a192e900Samaguire 	if (scf_transaction_start(tx, instpg) == -1)
2151a192e900Samaguire 		goto error;
2152a192e900Samaguire 	if (new) {
2153a192e900Samaguire 		if (scf_transaction_property_new(tx, ent, propname,
2154a192e900Samaguire 		    newproptype) == -1)
2155a192e900Samaguire 			goto error;
2156a192e900Samaguire 	} else if (scf_transaction_property_change(tx, ent, propname,
2157a192e900Samaguire 	    newproptype) == -1)
2158a192e900Samaguire 		goto error;
2159a192e900Samaguire 	for (i = 0; i < numpropvals; i++) {
2160a192e900Samaguire 		if ((values[i] = scf_value_create(h)) == NULL ||
2161a192e900Samaguire 		    scf_value_set_from_string(values[i], newproptype,
2162a192e900Samaguire 		    propvals[i] == NULL ? "": propvals[i]) == -1 ||
2163a192e900Samaguire 		    scf_entry_add_value(ent, values[i]) != 0)
2164a192e900Samaguire 			goto error;
2165a192e900Samaguire 	}
2166a192e900Samaguire 	retval = scf_transaction_commit(tx);
2167a192e900Samaguire 	if (retval == 0) {
2168a192e900Samaguire 		scf_transaction_reset(tx);
2169a192e900Samaguire 		if (scf_pg_update(instpg) == -1)
2170a192e900Samaguire 			goto error;
2171a192e900Samaguire 		goto retry;
2172a192e900Samaguire 	}
2173a192e900Samaguire 	if (retval == -1)
2174a192e900Samaguire 		goto error;
2175a192e900Samaguire 	goto out;
2176a192e900Samaguire error:
2177a192e900Samaguire 	switch (scf_error()) {
2178a192e900Samaguire 	case SCF_ERROR_INVALID_ARGUMENT:
2179a192e900Samaguire 		(void) fprintf(stderr, gettext(
2180a192e900Samaguire 		    "%s: invalid value for property %s/%s\n"), myname,
2181a192e900Samaguire 		    pgname, propname);
2182a192e900Samaguire 		break;
2183a192e900Samaguire 	case SCF_ERROR_NOT_FOUND:
2184a192e900Samaguire 		(void) fprintf(stderr, gettext(
2185a192e900Samaguire 		    "%s: no such property %s/%s\n"), myname,
2186a192e900Samaguire 		    pgname, propname);
2187a192e900Samaguire 		break;
2188a192e900Samaguire 	default:
2189a192e900Samaguire 		(void) fprintf(stderr, gettext(
2190a192e900Samaguire 		    "%s: unexpected libscf error: %s\n"), myname,
2191a192e900Samaguire 		    scf_strerror(scf_error()));
2192a192e900Samaguire 		break;
2193a192e900Samaguire 	}
2194a192e900Samaguire 	ret = -1;
2195a192e900Samaguire out:
2196a192e900Samaguire 	if (tx != NULL)
2197a192e900Samaguire 		scf_transaction_destroy(tx);
2198a192e900Samaguire 	if (ent != NULL)
2199a192e900Samaguire 		scf_entry_destroy(ent);
2200a192e900Samaguire 	if (values != NULL) {
2201a192e900Samaguire 		for (i = 0; i < numpropvals; i++) {
2202a192e900Samaguire 			if (values[i] != NULL)
2203a192e900Samaguire 				scf_value_destroy(values[i]);
2204a192e900Samaguire 		}
2205a192e900Samaguire 		free(values);
2206a192e900Samaguire 	}
2207a192e900Samaguire 	if (prop != NULL)
2208a192e900Samaguire 		scf_property_destroy(prop);
2209a192e900Samaguire 	if (cpg != NULL)
2210a192e900Samaguire 		scf_pg_destroy(cpg);
2211a192e900Samaguire 	if (instpg != NULL)
2212a192e900Samaguire 		scf_pg_destroy(instpg);
2213a192e900Samaguire 	if (pgtype != NULL)
2214a192e900Samaguire 		free(pgtype);
2215a192e900Samaguire 	return (ret);
2216a192e900Samaguire }
2217a192e900Samaguire 
2218a192e900Samaguire /*
2219a192e900Samaguire  * This function gathers configuration from the legacy /etc/inet/routing.conf,
2220a192e900Samaguire  * if any, and sets the appropriate variable values accordingly.  Once
2221a192e900Samaguire  * these are set,  the legacy daemons are checked to see if they have
2222a192e900Samaguire  * SMF counterparts (ra_check_legacy_daemons()).  If they do, the
2223a192e900Samaguire  * configuration is upgraded.  Finally,  the legacy option settings are
2224a192e900Samaguire  * applied,  enabling/disabling the routing/forwarding services as
2225a192e900Samaguire  * appropriate.
2226a192e900Samaguire  */
2227a192e900Samaguire static int
ra_upgrade_from_legacy_conf(void)2228a192e900Samaguire ra_upgrade_from_legacy_conf(void)
2229a192e900Samaguire {
2230a192e900Samaguire 	scf_handle_t	*h = NULL;
2231a192e900Samaguire 	scf_instance_t	*inst = NULL;
2232a192e900Samaguire 	int		ret = 0, i, r;
2233a192e900Samaguire 	boolean_t	old_conf_read;
2234a192e900Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
2235a192e900Samaguire 
2236a192e900Samaguire 	/*
2237a192e900Samaguire 	 * First, determine if we have already upgraded - if "routing-conf-read"
2238a192e900Samaguire 	 * is true, we bail.  The use of a boolean property indicating if
2239a192e900Samaguire 	 * routing.conf has been read and applied might seem a lot more
2240a192e900Samaguire 	 * work than simply copying routing.conf aside,  but leaving the
2241a192e900Samaguire 	 * file in place allows users to downgrade and have their old
2242a192e900Samaguire 	 * routing configuration still in place.
2243a192e900Samaguire 	 */
2244a192e900Samaguire 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
2245a192e900Samaguire 	    scf_handle_bind(h) == -1) {
2246a192e900Samaguire 		(void) fprintf(stderr, gettext(
2247a192e900Samaguire 		    "%s: cannot connect to SMF repository\n"), myname);
2248a192e900Samaguire 		ret = -1;
2249a192e900Samaguire 		goto out;
2250a192e900Samaguire 	}
2251a192e900Samaguire 	if ((inst = scf_instance_create(h)) == NULL ||
2252a192e900Samaguire 	    scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP,
2253a192e900Samaguire 	    NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2254a192e900Samaguire 		(void) fprintf(stderr, gettext(
2255a192e900Samaguire 		    "%s: unexpected libscf error: %s\n"), myname,
2256a192e900Samaguire 		    scf_strerror(scf_error()));
2257a192e900Samaguire 		ret = -1;
2258a192e900Samaguire 		goto out;
2259a192e900Samaguire 	}
2260a192e900Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
2261a192e900Samaguire 	    RA_PROP_ROUTING_CONF_READ, B_TRUE, B_TRUE, &old_conf_read) == -1) {
2262a192e900Samaguire 		ret = -1;
2263a192e900Samaguire 		goto out;
2264a192e900Samaguire 	}
2265a192e900Samaguire 
2266a192e900Samaguire 	if (old_conf_read)
2267a192e900Samaguire 		goto out;
2268a192e900Samaguire 
2269a192e900Samaguire 	/*
2270a192e900Samaguire 	 * Now set "routing-conf-read" to true so we don`t reimport legacy
2271a192e900Samaguire 	 * configuration again.
2272a192e900Samaguire 	 */
2273a192e900Samaguire 	if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
2274a192e900Samaguire 	    RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1)
2275a192e900Samaguire 		return (-1);
2276a192e900Samaguire 	(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
2277a192e900Samaguire 
2278a192e900Samaguire 	ra_resetvars(NULL);
2279a192e900Samaguire 
2280a192e900Samaguire 	/* First, gather values from routing.conf */
2281a192e900Samaguire 	if ((r = ra_parseconf()) == -1) {
2282a192e900Samaguire 		ret = -1;
2283a192e900Samaguire 		goto out;
2284a192e900Samaguire 	}
2285a192e900Samaguire 	/* No routing.conf file found */
2286a192e900Samaguire 	if (r == 0)
2287a192e900Samaguire 		goto out;
2288a192e900Samaguire 	/*
2289a192e900Samaguire 	 * Now, set the options/variables gathered.  We set variables first,
2290a192e900Samaguire 	 * as we cannot enable routing before we determine the daemons
2291a192e900Samaguire 	 * to enable.
2292a192e900Samaguire 	 */
2293a192e900Samaguire 
2294a192e900Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
2295a192e900Samaguire 		/* Skip routing-svcs var, not featured in legacy config */
2296a192e900Samaguire 		if (strcmp(ra_vars[i].var_name, RA_VAR_ROUTING_SVCS) == 0)
2297a192e900Samaguire 			continue;
2298a192e900Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri,
2299a192e900Samaguire 		    &(ra_vars[i])) == -1) {
2300a192e900Samaguire 			ret = -1;
2301a192e900Samaguire 			goto out;
2302a192e900Samaguire 		}
2303a192e900Samaguire 	}
2304a192e900Samaguire 	/* Clear routing-svcs value */
2305a192e900Samaguire 	if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
2306a192e900Samaguire 	    routing_svcs) == -1) {
2307a192e900Samaguire 		ret = -1;
2308a192e900Samaguire 		goto out;
2309a192e900Samaguire 	}
2310a192e900Samaguire 
2311a192e900Samaguire 	if (ra_check_legacy_daemons() == -1) {
2312a192e900Samaguire 		ret = -1;
2313a192e900Samaguire 		goto out;
2314a192e900Samaguire 	}
2315a192e900Samaguire 
2316a192e900Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2317a192e900Samaguire 		if (ra_smf_cb(ra_set_persistent_opt_cb, ra_opts[i].opt_fmri,
2318a192e900Samaguire 		    &(ra_opts[i])) == -1 ||
2319a192e900Samaguire 		    ra_smf_cb(ra_set_default_opt_cb,
2320a192e900Samaguire 		    ra_opts[i].opt_default_fmri, &(ra_opts[i])) == -1) {
2321a192e900Samaguire 			ret = -1;
2322a192e900Samaguire 			break;
2323a192e900Samaguire 		}
2324a192e900Samaguire 	}
2325a192e900Samaguire out:
2326a192e900Samaguire 	if (inst != NULL)
2327a192e900Samaguire 		scf_instance_destroy(inst);
2328a192e900Samaguire 	if (h != NULL)
2329a192e900Samaguire 		scf_handle_destroy(h);
2330a192e900Samaguire 
2331a192e900Samaguire 	return (ret);
2332a192e900Samaguire }
2333a192e900Samaguire 
2334ceb97a6aSamaguire /*
2335ceb97a6aSamaguire  *
2336ceb97a6aSamaguire  * Return the number of IPv6 addresses configured.  This answers the
2337ceb97a6aSamaguire  * generic question, "is IPv6 configured?".  We only start in.ndpd if IPv6
2338ceb97a6aSamaguire  * is configured, and we also only enable IPv6 routing daemons if IPv6 is
2339ceb97a6aSamaguire  * enabled.
2340ceb97a6aSamaguire  */
2341ceb97a6aSamaguire static int
ra_numv6intfs(void)2342ceb97a6aSamaguire ra_numv6intfs(void)
2343ceb97a6aSamaguire {
2344ceb97a6aSamaguire 	static int	num = -1;
2345ceb97a6aSamaguire 	int		ipsock;
2346ceb97a6aSamaguire 	struct lifnum	lifn;
2347ceb97a6aSamaguire 
2348ceb97a6aSamaguire 	if (num != -1)
2349ceb97a6aSamaguire 		return (num);
2350ceb97a6aSamaguire 
2351ceb97a6aSamaguire 	if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
2352ceb97a6aSamaguire 		(void) fprintf(stderr,
2353ceb97a6aSamaguire 		    gettext("%1$s: unable to open %2$s: %3$s\n"),
2354ceb97a6aSamaguire 		    myname, IP_DEV_NAME, strerror(errno));
2355ceb97a6aSamaguire 		return (0);
2356ceb97a6aSamaguire 	}
2357ceb97a6aSamaguire 	lifn.lifn_family = AF_INET6;
2358ceb97a6aSamaguire 	lifn.lifn_flags = 0;
2359ceb97a6aSamaguire 
2360ceb97a6aSamaguire 	if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
2361ceb97a6aSamaguire 		(void) close(ipsock);
2362ceb97a6aSamaguire 		return (0);
2363ceb97a6aSamaguire 	}
2364ceb97a6aSamaguire 	(void) close(ipsock);
2365ceb97a6aSamaguire 
2366ceb97a6aSamaguire 	return (num = lifn.lifn_count);
2367ceb97a6aSamaguire }
2368ceb97a6aSamaguire 
2369a192e900Samaguire /*
2370a192e900Samaguire  * Parse the configuration file and fill the ra_opts array with opt_value
2371a192e900Samaguire  * and opt_default_value values, and the ra_vars array with var_value and
2372a192e900Samaguire  * var_default_value values.  Then copy aside routing.conf so it will not
2373a192e900Samaguire  * be read by future invokations of routeadm.
2374a192e900Samaguire  */
2375a192e900Samaguire static int
ra_parseconf(void)2376a192e900Samaguire ra_parseconf(void)
2377a192e900Samaguire {
2378a192e900Samaguire 	FILE	*fp;
2379a192e900Samaguire 	uint_t	lineno;
2380a192e900Samaguire 	char	line[RA_MAX_CONF_LINE];
2381a192e900Samaguire 	char	*cp, *confstr;
2382a192e900Samaguire 	raopt_t	*raopt;
2383a192e900Samaguire 	ravar_t *ravar;
2384a192e900Samaguire 
2385a192e900Samaguire 	if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) {
2386a192e900Samaguire 		/*
2387a192e900Samaguire 		 * There's no config file, so we simply return as there
2388a192e900Samaguire 		 * is no work to do.
2389a192e900Samaguire 		 */
2390a192e900Samaguire 		return (0);
2391a192e900Samaguire 	}
2392a192e900Samaguire 
2393a192e900Samaguire 	for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) {
2394a192e900Samaguire 		if (line[strlen(line) - 1] == '\n')
2395a192e900Samaguire 			line[strlen(line) - 1] = '\0';
2396a192e900Samaguire 
2397a192e900Samaguire 		cp = line;
2398a192e900Samaguire 
2399a192e900Samaguire 		/* Skip leading whitespace */
2400a192e900Samaguire 		while (isspace(*cp))
2401a192e900Samaguire 			cp++;
2402a192e900Samaguire 
2403a192e900Samaguire 		/* Skip comment lines and empty lines */
2404a192e900Samaguire 		if (*cp == '#' || *cp == '\0')
2405a192e900Samaguire 			continue;
2406a192e900Samaguire 
2407a192e900Samaguire 		/*
2408a192e900Samaguire 		 * Anything else must be of the form:
2409a192e900Samaguire 		 * <option> <value> <default_value>
2410a192e900Samaguire 		 */
2411a192e900Samaguire 		if ((confstr = strtok(cp, " ")) == NULL) {
2412a192e900Samaguire 			(void) fprintf(stderr,
2413a192e900Samaguire 			    gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
2414a192e900Samaguire 			    myname, RA_CONF_FILE, lineno);
2415a192e900Samaguire 			continue;
2416a192e900Samaguire 		}
2417a192e900Samaguire 
2418a192e900Samaguire 		if ((raopt = ra_str2opt(confstr)) != NULL) {
2419a192e900Samaguire 			if (ra_parseopt(confstr, lineno, raopt) != 0) {
2420a192e900Samaguire 				(void) fclose(fp);
2421a192e900Samaguire 				return (-1);
2422a192e900Samaguire 			}
2423a192e900Samaguire 		} else if ((ravar = ra_str2var(confstr)) != NULL) {
2424a192e900Samaguire 			if (ra_parsevar(confstr, ravar) != 0) {
2425a192e900Samaguire 				(void) fclose(fp);
2426a192e900Samaguire 				return (-1);
2427a192e900Samaguire 			}
2428a192e900Samaguire 		} else {
2429a192e900Samaguire 			(void) fprintf(stderr,
2430a192e900Samaguire 			    gettext("%1$s: %2$s: invalid option name on "
2431a192e900Samaguire 				"line %3$d\n"),
2432a192e900Samaguire 			    myname, RA_CONF_FILE, lineno);
2433a192e900Samaguire 			continue;
2434a192e900Samaguire 		}
2435a192e900Samaguire 	}
2436a192e900Samaguire 
2437a192e900Samaguire 	(void) fclose(fp);
2438a192e900Samaguire 
2439a192e900Samaguire 	return (1);
2440a192e900Samaguire }
2441a192e900Samaguire 
2442a192e900Samaguire static int
ra_parseopt(char * confstr,int lineno,raopt_t * raopt)2443a192e900Samaguire ra_parseopt(char *confstr, int lineno, raopt_t *raopt)
2444a192e900Samaguire {
2445a192e900Samaguire 	oval_t oval, d_oval;
2446a192e900Samaguire 
2447a192e900Samaguire 	if ((confstr = strtok(NULL, " ")) == NULL) {
2448a192e900Samaguire 		(void) fprintf(stderr,
2449a192e900Samaguire 		    gettext("%1$s: %2$s: missing value on line %3$d\n"),
2450a192e900Samaguire 		    myname, RA_CONF_FILE, lineno);
2451a192e900Samaguire 		return (0);
2452a192e900Samaguire 	}
2453a192e900Samaguire 	if ((oval = ra_str2oval(confstr)) == OPT_INVALID) {
2454a192e900Samaguire 		(void) fprintf(stderr,
2455a192e900Samaguire 		    gettext("%1$s: %2$s: invalid option "
2456a192e900Samaguire 			"value on line %3$d\n"),
2457a192e900Samaguire 		    myname, RA_CONF_FILE, lineno);
2458a192e900Samaguire 		return (0);
2459a192e900Samaguire 	}
2460a192e900Samaguire 	if (oval != OPT_DEFAULT)
2461a192e900Samaguire 		raopt->opt_enabled = oval == OPT_ENABLED;
2462a192e900Samaguire 
2463a192e900Samaguire 	if ((confstr = strtok(NULL, " ")) == NULL) {
2464a192e900Samaguire 		(void) fprintf(stderr,
2465a192e900Samaguire 		    gettext("%1$s: %2$s: missing revert "
2466a192e900Samaguire 			"value on line %3$d\n"),
2467a192e900Samaguire 		    myname, RA_CONF_FILE, lineno);
2468a192e900Samaguire 		return (0);
2469a192e900Samaguire 	}
2470a192e900Samaguire 	if ((d_oval = ra_str2oval(confstr)) == OPT_INVALID) {
2471a192e900Samaguire 		(void) fprintf(stderr,
2472a192e900Samaguire 		    gettext("%1$s: %2$s: invalid revert "
2473a192e900Samaguire 			"value on line %3$d\n"),
2474a192e900Samaguire 		    myname, RA_CONF_FILE, lineno, confstr);
2475a192e900Samaguire 		return (0);
2476a192e900Samaguire 	}
2477a192e900Samaguire 	raopt->opt_default_enabled = d_oval == OPT_ENABLED;
2478a192e900Samaguire 	if (oval == OPT_DEFAULT)
2479a192e900Samaguire 		raopt->opt_enabled = d_oval == OPT_ENABLED;
2480ef2c19a1Samaguire 
2481ef2c19a1Samaguire 	/*
2482ef2c19a1Samaguire 	 * Set ipv4(6)-routing-set property as appropriate on upgrading
2483ef2c19a1Samaguire 	 * routing.conf.  If option was default, set this value to false,
2484ef2c19a1Samaguire 	 * as this indicates the administrator has not explicitly enabled
2485ef2c19a1Samaguire 	 * or disabled ipv4(6)-routing.  The ipv4-routing-set value is used
2486ef2c19a1Samaguire 	 * in the routing-setup service, and if it is false, ipv4-routing
2487ef2c19a1Samaguire 	 * is enabled in the case where no default route can be determined.
2488ef2c19a1Samaguire 	 */
2489ef2c19a1Samaguire 	if (raopt->opt_flags & (RA_SVC_FLAG_IPV4_ROUTING |
2490ef2c19a1Samaguire 	    RA_SVC_FLAG_IPV6_ROUTING)) {
2491ef2c19a1Samaguire 		if (ra_smf_cb(oval == OPT_DEFAULT ? ra_routing_opt_unset_cb :
2492ef2c19a1Samaguire 		    ra_routing_opt_set_cb, raopt->opt_default_fmri, raopt)
2493ef2c19a1Samaguire 		    == -1)
2494ef2c19a1Samaguire 			return (-1);
2495ef2c19a1Samaguire 	}
2496a192e900Samaguire 	return (0);
2497a192e900Samaguire }
2498a192e900Samaguire 
2499a192e900Samaguire static int
ra_parsevar(char * confstr,ravar_t * ravar)2500a192e900Samaguire ra_parsevar(char *confstr, ravar_t *ravar)
2501a192e900Samaguire {
2502a192e900Samaguire 	confstr = strtok(NULL, "=");
2503a192e900Samaguire 	if (confstr == NULL) {
2504a192e900Samaguire 		/*
2505a192e900Samaguire 		 * This isn't an error condition, it simply means that the
2506a192e900Samaguire 		 * variable has no value.
2507a192e900Samaguire 		 */
2508a192e900Samaguire 		ravar->var_value = NULL;
2509a192e900Samaguire 		return (0);
2510a192e900Samaguire 	}
2511a192e900Samaguire 
2512a192e900Samaguire 	if ((ravar->var_value = strdup(confstr)) == NULL) {
2513a192e900Samaguire 		(void) fprintf(stderr, gettext("%s: "
2514a192e900Samaguire 		    "unable to allocate memory\n"), myname);
2515a192e900Samaguire 		return (-1);
2516a192e900Samaguire 	}
2517a192e900Samaguire 	return (0);
2518a192e900Samaguire }
2519a192e900Samaguire 
2520a192e900Samaguire /* Convert a string to an option value. */
2521a192e900Samaguire static oval_t
ra_str2oval(const char * valstr)2522a192e900Samaguire ra_str2oval(const char *valstr)
2523a192e900Samaguire {
2524a192e900Samaguire 	if (strcmp(valstr, "enabled") == 0)
2525a192e900Samaguire 		return (OPT_ENABLED);
2526a192e900Samaguire 	else if (strcmp(valstr, "disabled") == 0)
2527a192e900Samaguire 		return (OPT_DISABLED);
2528a192e900Samaguire 	else if (strcmp(valstr, "default") == 0)
2529a192e900Samaguire 		return (OPT_DEFAULT);
2530a192e900Samaguire 	return (OPT_INVALID);
2531a192e900Samaguire }
2532a192e900Samaguire 
2533a192e900Samaguire static raopt_t *
ra_str2opt(const char * optnamestr)2534a192e900Samaguire ra_str2opt(const char *optnamestr)
2535a192e900Samaguire {
2536a192e900Samaguire 	int	i;
2537a192e900Samaguire 
2538a192e900Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2539a192e900Samaguire 		if (strcmp(optnamestr, ra_opts[i].opt_name) == 0)
2540a192e900Samaguire 			break;
2541a192e900Samaguire 	}
2542a192e900Samaguire 	if (ra_opts[i].opt_name == NULL)
2543a192e900Samaguire 		return (NULL);
2544a192e900Samaguire 	return (&ra_opts[i]);
2545a192e900Samaguire }
2546a192e900Samaguire 
2547a192e900Samaguire /*
2548a192e900Samaguire  * Reset all option values previously gathered to B_FALSE.
2549a192e900Samaguire  */
2550a192e900Samaguire static void
ra_resetopts(void)2551a192e900Samaguire ra_resetopts(void)
2552a192e900Samaguire {
2553a192e900Samaguire 	int	i;
2554a192e900Samaguire 
2555a192e900Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2556a192e900Samaguire 		ra_opts[i].opt_enabled = B_FALSE;
2557a192e900Samaguire 		ra_opts[i].opt_default_enabled = B_FALSE;
2558a192e900Samaguire 	}
2559a192e900Samaguire }
2560a192e900Samaguire 
2561a192e900Samaguire static ravar_t *
ra_str2var(const char * varnamestr)2562a192e900Samaguire ra_str2var(const char *varnamestr)
2563a192e900Samaguire {
2564a192e900Samaguire 	int	i;
2565a192e900Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
2566a192e900Samaguire 		if (strcmp(varnamestr, ra_vars[i].var_name) == 0)
2567a192e900Samaguire 			break;
2568a192e900Samaguire 	}
2569a192e900Samaguire 	if (ra_vars[i].var_name == NULL)
2570a192e900Samaguire 		return (NULL);
2571a192e900Samaguire 	return (&ra_vars[i]);
2572a192e900Samaguire }
2573a192e900Samaguire 
2574a192e900Samaguire /*
2575a192e900Samaguire  * Reset variable values previously gathered to NULL.
2576a192e900Samaguire  */
2577a192e900Samaguire static void
ra_resetvars(const char * proto)2578a192e900Samaguire ra_resetvars(const char *proto)
2579a192e900Samaguire {
2580a192e900Samaguire 	int	i;
2581a192e900Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
2582a192e900Samaguire 		if (proto != NULL &&
2583a192e900Samaguire 		    !VAR_PROTO_MATCH(ra_vars[i].var_name, proto))
2584a192e900Samaguire 			continue;
2585a192e900Samaguire 		if (ra_vars[i].var_value != NULL)
2586a192e900Samaguire 			free(ra_vars[i].var_value);
2587a192e900Samaguire 		ra_vars[i].var_value = NULL;
2588a192e900Samaguire 		if (ra_vars[i].var_default_value != NULL)
2589a192e900Samaguire 			free(ra_vars[i].var_default_value);
2590a192e900Samaguire 		ra_vars[i].var_default_value = NULL;
2591a192e900Samaguire 	}
2592a192e900Samaguire }
2593a192e900Samaguire 
2594a192e900Samaguire /*
2595a192e900Samaguire  * Given an option name, this function provides an internationalized, human
2596a192e900Samaguire  * readable version of the option name.
2597a192e900Samaguire  */
2598a192e900Samaguire static char *
ra_intloptname(const char * optname)2599a192e900Samaguire ra_intloptname(const char *optname)
2600a192e900Samaguire {
2601a192e900Samaguire 	if (strcmp(optname, RA_OPT_IPV4_FORWARDING) == 0)
2602a192e900Samaguire 		return (gettext("IPv4 forwarding"));
2603a192e900Samaguire 	else if (strcmp(optname, RA_OPT_IPV4_ROUTING) == 0)
2604a192e900Samaguire 		return (gettext("IPv4 routing"));
2605a192e900Samaguire 	else if (strcmp(optname, RA_OPT_IPV6_FORWARDING) == 0)
2606a192e900Samaguire 		return (gettext("IPv6 forwarding"));
2607a192e900Samaguire 	else if (strcmp(optname, RA_OPT_IPV6_ROUTING) == 0)
2608a192e900Samaguire 		return (gettext("IPv6 routing"));
2609a192e900Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON) == 0)
2610a192e900Samaguire 		return (gettext("IPv4 routing daemon"));
2611a192e900Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON_ARGS) == 0)
2612a192e900Samaguire 		return (gettext("IPv4 routing daemon args"));
2613a192e900Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_STOP_CMD) == 0)
2614a192e900Samaguire 		return (gettext("IPv4 routing daemon stop"));
2615a192e900Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON) == 0)
2616a192e900Samaguire 		return (gettext("IPv6 routing daemon"));
2617a192e900Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON_ARGS) == 0)
2618a192e900Samaguire 		return (gettext("IPv6 routing daemon args"));
2619a192e900Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_STOP_CMD) == 0)
2620a192e900Samaguire 		return (gettext("IPv6 routing daemon stop"));
2621a192e900Samaguire 	else if (strcmp(optname, RA_VAR_ROUTING_SVCS) == 0)
2622a192e900Samaguire 		return (gettext("Routing services"));
2623a192e900Samaguire 	/*
2624a192e900Samaguire 	 * If we get here, there's a bug and someone should trip over this
2625a192e900Samaguire 	 * NULL pointer.
2626a192e900Samaguire 	 */
2627a192e900Samaguire 	return (NULL);
2628a192e900Samaguire }
2629