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