xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/routeadm/routeadm.c (revision 3294:46722b32aa88)
13048Samaguire /*
23048Samaguire  * CDDL HEADER START
33048Samaguire  *
43048Samaguire  * The contents of this file are subject to the terms of the
53048Samaguire  * Common Development and Distribution License (the "License").
63048Samaguire  * You may not use this file except in compliance with the License.
73048Samaguire  *
83048Samaguire  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93048Samaguire  * or http://www.opensolaris.org/os/licensing.
103048Samaguire  * See the License for the specific language governing permissions
113048Samaguire  * and limitations under the License.
123048Samaguire  *
133048Samaguire  * When distributing Covered Code, include this CDDL HEADER in each
143048Samaguire  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153048Samaguire  * If applicable, add the following below this CDDL HEADER, with the
163048Samaguire  * fields enclosed by brackets "[]" replaced with your own identifying
173048Samaguire  * information: Portions Copyright [yyyy] [name of copyright owner]
183048Samaguire  *
193048Samaguire  * CDDL HEADER END
203048Samaguire  */
213048Samaguire /*
223048Samaguire  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
233048Samaguire  * Use is subject to license terms.
243048Samaguire  */
253048Samaguire 
263048Samaguire #pragma ident	"%Z%%M%	%I%	%E% SMI"
273048Samaguire 
283048Samaguire #include <stdio.h>
293048Samaguire #include <string.h>
303048Samaguire #include <stdlib.h>
313048Samaguire #include <unistd.h>
323048Samaguire #include <limits.h>
333048Samaguire #include <ctype.h>
343048Samaguire #include <stropts.h>
353048Samaguire #include <errno.h>
363048Samaguire #include <libintl.h>
373048Samaguire #include <locale.h>
383048Samaguire #include <fcntl.h>
393048Samaguire #include <sys/types.h>
403048Samaguire #include <sys/stat.h>
413094Samaguire #include <sys/socket.h>
423094Samaguire #include <sys/sockio.h>
433094Samaguire #include <inet/ip.h>
443094Samaguire #include <inet/nd.h>
453094Samaguire #include <net/if.h>
463048Samaguire #include <libscf.h>
473048Samaguire #include <libscf_priv.h>
483048Samaguire #include <libuutil.h>
493048Samaguire 
503048Samaguire /*
513048Samaguire  * This program moves routing management under SMF.  We do this by giving
523048Samaguire  * routeadm options that allow interaction with SMF services.  These include:
533048Samaguire  * - setting the routing services routeadm will enable
543048Samaguire  *	# routeadm -s routing-svcs="fmri [fmri...]"
553048Samaguire  * where each fmri is an SMF routing service.
563048Samaguire  * - changing properties of routing services
573048Samaguire  *	# routeadm -m fmri key=value [key=value...]
583048Samaguire  * - listing routing daemon properties
593048Samaguire  *	# routeadm -l fmri
603048Samaguire  * where all properties in the "routing" property group are listed.
613048Samaguire  *
623048Samaguire  * By providing legacy routing services (legacy-routing:ipv4 and ipv6), we
633048Samaguire  * can also support running of routing daemons with no SMF service under SMF.
643048Samaguire  * Specifying a routing daemon with no SMF counterpart results in the
653048Samaguire  * daemon, it`s arguments and stop command being set in the appropriate instance
663048Samaguire  * to be picked up by start/stop methods.
673048Samaguire  *
683048Samaguire  * Internally, routeadm keeps track of routing services by setting the
693048Samaguire  * "current-routing-svc" property to "true" in the services it manages.
703048Samaguire  * So for example, running
713048Samaguire  *	# routeadm -s routing-svcs="route:default ripng:default"
723048Samaguire  * sets this variable in each instance specified. If the user specifies a
733048Samaguire  * non-SMF routing daemon via
743048Samaguire  * 	# routeadm -s ipv4-routing-daemon=/usr/sbin/mydaemon
753048Samaguire  * the variable will be set for the legacy-routing:ipv4 instance.
763048Samaguire  *
773048Samaguire  * In order to ensure that the SMF versions of routing daemons are used
783048Samaguire  * where possible, routeadm will check the daemons specified in
793048Samaguire  * ipv4-routing-daemon/ipv6-routing-daemon to determine if there is an
803048Samaguire  * SMF counterpart.  If so, rather than running the legacy service
813048Samaguire  * we move configuration, specifically the associated daemon arguments
823048Samaguire  * to the SMF counterpart.  From there,  when the daemon is enabled,  it
833048Samaguire  * will pick up the daemon arguments setting,  transfer the argument string
843048Samaguire  * to the appropriate properties and run the service.
853048Samaguire  *
863048Samaguire  * To support the semantics of routeadm -e (enable at next boot) through SMF,
873048Samaguire  * we make use of temporary state changes,  which last only until reboot.
883048Samaguire  * For example, if a service is disabled,  and it is to be enabled via
893048Samaguire  * routeadm -e,  we simply change the disable to a temporary disable,
903048Samaguire  * and set the persistent enabled value to true.  This ensures the daemon
913048Samaguire  * will run at next boot,  but not now.  The reverse is true for disabling
923048Samaguire  * enabled instances  (and if the daemon is enabled when we issue the enable,
933048Samaguire  * we do nothing since it is already in the desired state).
943048Samaguire  *
953048Samaguire  * Since the code is quite involved,  we provide a guide to the more complex
963048Samaguire  * actions taken in response to user commands.
973048Samaguire  *
983048Samaguire  * routeadm -e[d] ipv4[6]-routing[forwarding]
993048Samaguire  *
1003048Samaguire  * 	In this case,  the goal is to prepare the configured routing daemons
1013048Samaguire  * 	(specified through routeadm -s routing-svcs="...") or forwarding
1023048Samaguire  *	services to switch on (-e) or of (-d) at next boot.
1033048Samaguire  *
1043048Samaguire  *	Since this operation must be applied to multiple services in the
1053048Samaguire  *	routing daemon case (as opposed to the single ipv4[6]-forwarding
1063048Samaguire  *	service),  we make use of the scf_walk_fmri() function,  which
1073048Samaguire  *	applies a callback function to all matching functions.  In the case
1083048Samaguire  *	of the routing daemons,  we pass in a NULL signifying that all
1093048Samaguire  *	instances should be walked  (we then weed out the relevant routing
1103048Samaguire  *	services through presence of the routeadm/protocol property).  In
1113048Samaguire  *	the case of enable, a routing service is enabled IFF it has the
1123048Samaguire  *	previously-mentioned property - with an appropriate value (i.e. ipv4
1133048Samaguire  *	for "routeadm -e ipv4-routing") - and it has routeadm/curr-routing-svc
1143048Samaguire  *	property set to true  (this is set by other operations such as
1153048Samaguire  *	routeadm -s routing-svcs="...").  Then,  smf_enable_instance() or
1163048Samaguire  *	smf_disable_instance() is called,  setting the temporary state to
1173048Samaguire  *	the current state of the service.  This then allows setting of
1183048Samaguire  *	general/enabled value to next-boot value.  In the case of disabling
1193048Samaguire  *	ipv4[6]-routing,  all valid ipv4[6] routing daemons are prepared
1203048Samaguire  *	for next-boot disable, not just those specified via routing-svcs (this
1213048Samaguire  *	means that if the user enables routing daemons with "svcadm enable",
1223048Samaguire  *	disabling global routing does really switch off all routing daemons).
1233048Samaguire  *
1243048Samaguire  *	This is implemented through the ra_get_set_opt_common_cb() function,
1253048Samaguire  *	called by the ra_set_persistent_opt_cb() function.  The same
1263048Samaguire  *	function can be used for both routing and forwarding options,  in the
1273048Samaguire  *	latter case we simply provide the specific FMRI of the forwarding
1283048Samaguire  *	service in question (ipv4-forwarding or ipv6-forwarding),  and dispense
1293048Samaguire  *	with the eligibility tests we need to weed out the routing services
1303048Samaguire  *	from the rest.
1313048Samaguire  *
1323048Samaguire  *	Before we initiate the "enable" however, we must check routing daemons
1333048Samaguire  *	specified via the legacy variables (ipv4-routing-daemon etc).
1343048Samaguire  *	If they map to SMF routing services,  we wish to transfer their
1353048Samaguire  *	configuration to the corresponding services and use them instead of
1363048Samaguire  *	the legacy services.  To do this,  we need to match the daemon program
1373048Samaguire  *	against the routeadm/daemon property of each routing daemon (we use
1383048Samaguire  *	scf_walk_fmri() and the routeadm/protocol property again to identify
1393048Samaguire  *	daemons).  If a match is found,  the daemon arguments are transferred
1403048Samaguire  *	to the appropriate service`s daemon-args property, to be picked up
1413048Samaguire  *	by it`s start method and converted into appropriate property values.
1423048Samaguire  *	This is accomplished by ra_check_legacy_daemons(), and the callback
1433048Samaguire  *	operation is carried out by ra_upgrade_legacy_daemons_cb().  If the
1443048Samaguire  *	daemon was not upgraded,  we need to mark the legacy-routing:ipv4[6]
1453048Samaguire  *	instance to be enabled (by routeadm -e),  since it now must run the
1463048Samaguire  *	un-upgradeable legacy daemon.
1473048Samaguire  *
1483048Samaguire  * routeadm -l fmri
1493048Samaguire  *
1503048Samaguire  *	Lists all properties and values in the routing property group associated
1513048Samaguire  *	with instance fmri.  We simply walk through the composed property
1523048Samaguire  *	group, displaying all values.  See ra_list_props_cb().
1533048Samaguire  *
1543048Samaguire  * routeadm -m fmri key=value ...
1553048Samaguire  *
1563048Samaguire  *	Modify property values in the routing property group.  If the same
1573048Samaguire  *	key is used more than once,  multiple property values are set for that
1583048Samaguire  *	property.  Properties must exist in the composed property group,  but
1593048Samaguire  *	will only ever be set at the instance level to prevent multiple
1603048Samaguire  *	instances inheriting the property in error.  See ra_modify_props_cb().
1613048Samaguire  *
1623048Samaguire  * routeadm -s var=value
1633048Samaguire  *
1643048Samaguire  *	In all cases bar the routing-svcs variable,  this simply involves
1653048Samaguire  *	setting the appropriate SMF property value for the variable.  The
1663048Samaguire  *	routing-svcs case is more complex,  since we would like operations
1673048Samaguire  *	like the following to have intuitive effects:
1683048Samaguire  *		# routeadm -s routing-svcs=route -e ipv4-routing -u
1693048Samaguire  *		# routeadm -s routing-svcs=rdisc -u
1703048Samaguire  *	i.e., in the end, rdisc is the only routing service running.  To
1713048Samaguire  *	accomplish this switchover,  we need to disable the old routing-svcs
1723048Samaguire  *	and enable the new, marking the latter with the curr-routing-svc
1733048Samaguire  *	property so that routeadm -e will pick them up.  This is carried
1743048Samaguire  *	out by the ra_update_routing_svcs() function.
1753048Samaguire  *
1763048Samaguire  * routeadm -R alt_root ...
1773048Samaguire  *
1783048Samaguire  *	Used to support use of routeadm in Custom Jumpstart scripts,  this
1793048Samaguire  *	option causes all subsequent commands to be appended to the
1803048Samaguire  *	/var/svc/profile/upgrade file,  which is run on the subsequent boot.
1813048Samaguire  *	This is done because the SMF repository is not available to make
1823048Samaguire  *	the modifications to property values required in routeadm operations.
1833048Samaguire  *
1843048Samaguire  * routeadm -u
1853048Samaguire  *
1863048Samaguire  *	Update applies the "next boot" state to the current system.  Here
1873048Samaguire  *	we simply take the persistent state (general/enabled value) and
1883048Samaguire  *	make it the current state through smf_enable_instance() or
1893048Samaguire  *	smf_disable_instance() as appropriate (these calls,  without the
1903048Samaguire  *	temporary flag set,  delete the general_ovr/enabled property).
1913048Samaguire  */
1923048Samaguire 
1933048Samaguire #define	RA_OPT_IPV4_ROUTING	"ipv4-routing"
1943048Samaguire #define	RA_OPT_IPV6_ROUTING	"ipv6-routing"
1953048Samaguire #define	RA_OPT_IPV4_FORWARDING	"ipv4-forwarding"
1963048Samaguire #define	RA_OPT_IPV6_FORWARDING	"ipv6-forwarding"
1973048Samaguire 
1983048Samaguire #define	IS_ROUTING_OPT(opt)	(strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
1993048Samaguire 				strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
2003048Samaguire 
2013048Samaguire #define	RA_VAR_IPV4_ROUTING_DAEMON	"ipv4-routing-daemon"
2023048Samaguire #define	RA_VAR_IPV4_ROUTING_DAEMON_ARGS	"ipv4-routing-daemon-args"
2033048Samaguire #define	RA_VAR_IPV4_ROUTING_STOP_CMD	"ipv4-routing-stop-cmd"
2043048Samaguire #define	RA_VAR_IPV6_ROUTING_DAEMON	"ipv6-routing-daemon"
2053048Samaguire #define	RA_VAR_IPV6_ROUTING_DAEMON_ARGS	"ipv6-routing-daemon-args"
2063048Samaguire #define	RA_VAR_IPV6_ROUTING_STOP_CMD	"ipv6-routing-stop-cmd"
2073048Samaguire #define	RA_VAR_ROUTING_SVCS		"routing-svcs"
2083048Samaguire 
2093048Samaguire 
2103048Samaguire #define	RA_INSTANCE_ALL			NULL
2113048Samaguire #define	RA_INSTANCE_ROUTING_SETUP	"svc:/network/routing-setup:default"
2123048Samaguire #define	RA_INSTANCE_IPV4_FORWARDING	"svc:/network/ipv4-forwarding:default"
2133048Samaguire #define	RA_INSTANCE_IPV6_FORWARDING	"svc:/network/ipv6-forwarding:default"
2143048Samaguire #define	RA_INSTANCE_LEGACY_ROUTING_IPV4 \
2153048Samaguire 	"svc:/network/routing/legacy-routing:ipv4"
2163048Samaguire #define	RA_INSTANCE_LEGACY_ROUTING_IPV6 \
2173048Samaguire 	"svc:/network/routing/legacy-routing:ipv6"
2183094Samaguire #define	RA_INSTANCE_NDP			"svc:/network/routing/ndp:default"
2193048Samaguire 
2203048Samaguire #define	RA_PG_ROUTEADM			"routeadm"
2213048Samaguire #define	RA_PROP_CURR_ROUTING_SVC	"current-routing-svc"
2223048Samaguire #define	RA_PROP_ROUTING_SVCS		"routing-svcs"
2233048Samaguire #define	RA_PROP_DEFAULT_ROUTING_SVCS	"default-routing-svcs"
2243048Samaguire #define	RA_PROP_PROTO			"protocol"
2253048Samaguire #define	RA_PROP_DAEMON			"daemon"
2263048Samaguire #define	RA_PROP_DEFAULT_DAEMON		"default-daemon"
2273048Samaguire #define	RA_PROP_DAEMON_ARGS		"daemon-args"
2283048Samaguire #define	RA_PROP_DEFAULT_DAEMON_ARGS	"default-daemon-args"
2293048Samaguire #define	RA_PROP_DAEMON_STOP_CMD		"daemon-stop-cmd"
2303048Samaguire #define	RA_PROP_DEFAULT_STOP_CMD	"default-daemon"
2313048Samaguire #define	RA_PROP_LEGACY_DAEMON		"legacy-daemon"
2323048Samaguire #define	RA_PROP_DEFAULT_IPV4_ROUTING	"default-ipv4-routing"
2333048Samaguire #define	RA_PROP_DEFAULT_IPV6_ROUTING	"default-ipv6-routing"
2343048Samaguire #define	RA_PROP_DEFAULT_IPV4_FORWARDING	"default-ipv4-forwarding"
2353048Samaguire #define	RA_PROP_DEFAULT_IPV6_FORWARDING	"default-ipv6-forwarding"
2363048Samaguire #define	RA_PROP_IPV4_ROUTING_SET	"ipv4-routing-set"
2373048Samaguire #define	RA_PROP_IPV6_ROUTING_SET	"ipv6-routing-set"
2383048Samaguire #define	RA_PROP_ROUTING_CONF_READ	"routing-conf-read"
2393048Samaguire 
2403048Samaguire #define	RA_PG_ROUTING			"routing"
2413048Samaguire 
2423048Samaguire #define	RA_PROPVAL_BOOLEAN_TRUE		"true"
2433048Samaguire #define	RA_PROPVAL_BOOLEAN_FALSE	"false"
2443048Samaguire #define	RA_PROPVAL_PROTO_IPV4		"ipv4"
2453048Samaguire #define	RA_PROPVAL_PROTO_IPV6		"ipv6"
2463048Samaguire 
2473048Samaguire #define	RA_SVC_FLAG_NONE		0x0
2483048Samaguire #define	RA_SVC_FLAG_IPV4_ROUTING	0x1
2493048Samaguire #define	RA_SVC_FLAG_IPV6_ROUTING	0x2
2503048Samaguire 
2513048Samaguire #define	RA_SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
2523048Samaguire #define	RA_SMF_UPGRADE_MSG		" # added by routeadm(1M)"
2533048Samaguire #define	RA_CONF_FILE			"/etc/inet/routing.conf"
2543048Samaguire #define	RA_CONF_FILE_OLD		"/etc/inet/routing.conf.old"
2553048Samaguire #define	RA_MAX_CONF_LINE		256
2563048Samaguire 
2573048Samaguire /*
2583048Samaguire  * Option value.  Each option requires an FMRI identifying which services
2593048Samaguire  * to run the get_current/persistent scf_walk_fmri() function with,  and
2603048Samaguire  * associated flags (to ensure that in the case that multiple services
2613048Samaguire  * match, we select the correct ones). In addition, we specify the FMRI
2623048Samaguire  * and property used to set default option value.  The opt_enabled field
2633048Samaguire  * is used to hold retrieved state from get_*_opt_() callbacks and to specify
2643048Samaguire  * desired state for set_*_opt() operations.
2653048Samaguire  */
2663048Samaguire 
2673048Samaguire typedef struct raopt {
2683048Samaguire 	const char	*opt_name;
2693048Samaguire 	const char	*opt_fmri;
2703048Samaguire 	int		opt_flags;
2713048Samaguire 	boolean_t	opt_enabled;
2723048Samaguire 	const char	*opt_default_fmri;
2733048Samaguire 	const char	*opt_default_prop;
2743048Samaguire 	boolean_t	opt_default_enabled;
2753048Samaguire } raopt_t;
2763048Samaguire 
2773048Samaguire 
2783048Samaguire raopt_t ra_opts[] = {
2793048Samaguire 	{ RA_OPT_IPV4_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV4_ROUTING,
2803048Samaguire 	B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV4_ROUTING,
2813048Samaguire 	B_FALSE },
2823048Samaguire 	{ RA_OPT_IPV6_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV6_ROUTING,
2833048Samaguire 	B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV6_ROUTING,
2843048Samaguire 	B_FALSE },
2853048Samaguire 	{ RA_OPT_IPV4_FORWARDING, RA_INSTANCE_IPV4_FORWARDING, RA_SVC_FLAG_NONE,
2863048Samaguire 	B_FALSE, RA_INSTANCE_IPV4_FORWARDING, RA_PROP_DEFAULT_IPV4_FORWARDING,
2873048Samaguire 	B_FALSE },
2883048Samaguire 	{ RA_OPT_IPV6_FORWARDING, RA_INSTANCE_IPV6_FORWARDING, RA_SVC_FLAG_NONE,
2893048Samaguire 	B_FALSE, RA_INSTANCE_IPV6_FORWARDING, RA_PROP_DEFAULT_IPV6_FORWARDING,
2903048Samaguire 	B_FALSE },
2913048Samaguire 	{ NULL, NULL, RA_SVC_FLAG_NONE, B_FALSE, NULL, NULL, B_FALSE }
2923048Samaguire };
2933048Samaguire 
2943048Samaguire typedef enum option_values {
2953048Samaguire 	OPT_INVALID, OPT_ENABLED, OPT_DISABLED, OPT_DEFAULT, OPT_UNKNOWN
2963048Samaguire } oval_t;
2973048Samaguire 
2983048Samaguire typedef struct ra_var {
2993048Samaguire 	const char	*var_name;
3003048Samaguire 	const char	*var_fmri;
3013048Samaguire 	const char	*var_prop;
3023048Samaguire 	char		*var_value;
3033048Samaguire 	const char	*var_default_fmri;
3043048Samaguire 	const char	*var_default_prop;
3053048Samaguire 	char		*var_default_value;
3063048Samaguire } ravar_t;
3073048Samaguire 
3083048Samaguire ravar_t ra_vars[] = {
3093048Samaguire 	{ RA_VAR_IPV4_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV4,
3103048Samaguire 	RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
3113048Samaguire 	RA_PROP_DEFAULT_DAEMON, NULL},
3123048Samaguire 	{ RA_VAR_IPV4_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV4,
3133048Samaguire 	RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
3143048Samaguire 	RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
3153048Samaguire 	{ RA_VAR_IPV4_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV4,
3163048Samaguire 	RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
3173048Samaguire 	RA_PROP_DEFAULT_STOP_CMD, NULL },
3183048Samaguire 	{ RA_VAR_IPV6_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV6,
3193048Samaguire 	RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
3203048Samaguire 	RA_PROP_DEFAULT_DAEMON, NULL },
3213048Samaguire 	{ RA_VAR_IPV6_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV6,
3223048Samaguire 	RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
3233048Samaguire 	RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
3243048Samaguire 	{ RA_VAR_IPV6_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV6,
3253048Samaguire 	RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
3263048Samaguire 	RA_PROP_DEFAULT_STOP_CMD, NULL },
3273048Samaguire 	{ RA_VAR_ROUTING_SVCS, RA_INSTANCE_ROUTING_SETUP,
3283048Samaguire 	RA_PROP_ROUTING_SVCS, NULL, RA_INSTANCE_ROUTING_SETUP,
3293048Samaguire 	RA_PROP_DEFAULT_ROUTING_SVCS, NULL },
3303048Samaguire 	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
3313048Samaguire };
3323048Samaguire 
3333048Samaguire char *v_opt[] = {
3343048Samaguire #define	IPV4_ROUTING_DAEMON			0
3353048Samaguire 	RA_VAR_IPV4_ROUTING_DAEMON,
3363048Samaguire #define	IPV4_ROUTING_DAEMON_ARGS		1
3373048Samaguire 	RA_VAR_IPV4_ROUTING_DAEMON_ARGS,
3383048Samaguire #define	IPV4_ROUTING_STOP_CMD			2
3393048Samaguire 	RA_VAR_IPV4_ROUTING_STOP_CMD,
3403048Samaguire #define	IPV6_ROUTING_DAEMON			3
3413048Samaguire 	RA_VAR_IPV6_ROUTING_DAEMON,
3423048Samaguire #define	IPV6_ROUTING_DAEMON_ARGS		4
3433048Samaguire 	RA_VAR_IPV6_ROUTING_DAEMON_ARGS,
3443048Samaguire #define	IPV6_ROUTING_STOP_CMD			5
3453048Samaguire 	RA_VAR_IPV6_ROUTING_STOP_CMD,
3463048Samaguire #define	ROUTING_SVCS				6
3473048Samaguire 	RA_VAR_ROUTING_SVCS,
3483048Samaguire 	NULL
3493048Samaguire };
3503048Samaguire 
3513048Samaguire #define	IS_IPV4_VAR(varname)	(strncmp(varname, "ipv4", 4) == 0)
3523048Samaguire #define	IS_IPV6_VAR(varname)	(strncmp(varname, "ipv6", 4) == 0)
3533048Samaguire #define	VAR_PROTO_MATCH(varname, proto)	(strncmp(varname, proto, 4) == 0)
3543048Samaguire #define	IPV4_VARS_UNSET \
3553048Samaguire 	(strtok(ra_vars[IPV4_ROUTING_DAEMON].var_value, " \t") == NULL && \
3563048Samaguire 	strtok(ra_vars[IPV4_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
3573048Samaguire 	strtok(ra_vars[IPV4_ROUTING_STOP_CMD].var_value, " \t") == NULL)
3583048Samaguire 
3593048Samaguire #define	IPV6_VARS_UNSET	\
3603048Samaguire 	(strtok(ra_vars[IPV6_ROUTING_DAEMON].var_value, " \t") == NULL && \
3613048Samaguire 	strtok(ra_vars[IPV6_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
3623048Samaguire 	strtok(ra_vars[IPV6_ROUTING_STOP_CMD].var_value, " \t") == NULL)
3633048Samaguire 
3643048Samaguire /*
3653048Samaguire  * Structure used in modify operations to tie property name and multiple values
3663048Samaguire  * together.
3673048Samaguire  */
3683048Samaguire typedef struct ra_prop {
3693048Samaguire 	char	*prop_name;
3703048Samaguire 	char	**prop_values;
3713048Samaguire 	int	prop_numvalues;
3723048Samaguire } ra_prop_t;
3733048Samaguire 
3743048Samaguire typedef int (*ra_smf_cb_t)(void *, scf_walkinfo_t *);
3753048Samaguire 
3763048Samaguire /* Used to store program name */
3773048Samaguire static const char	*myname;
3783048Samaguire 
3793048Samaguire static void usage(void);
3803048Samaguire 
3813048Samaguire static int ra_check_legacy_daemons(void);
3823048Samaguire static int ra_upgrade_legacy_daemons(void);
3833048Samaguire static int ra_upgrade_cmd(char, int, char **);
3843048Samaguire static int ra_update(void);
3853048Samaguire static int ra_update_routing_svcs(char *);
3863048Samaguire static int ra_report(boolean_t, const char *);
3873048Samaguire static int ra_smf_cb(ra_smf_cb_t, const char *, void *);
3883048Samaguire static int ra_upgrade_from_legacy_conf(void);
3893094Samaguire static int ra_numv6intfs(void);
3903048Samaguire static int ra_parseconf(void);
3913048Samaguire static int ra_parseopt(char *, int, raopt_t *);
3923048Samaguire static int ra_parsevar(char *, ravar_t *);
3933048Samaguire static oval_t ra_str2oval(const char *);
3943048Samaguire static raopt_t *ra_str2opt(const char *);
3953048Samaguire static void ra_resetopts(void);
3963048Samaguire static ravar_t *ra_str2var(const char *);
3973048Samaguire static void ra_resetvars(const char *);
3983048Samaguire static char *ra_intloptname(const char *);
3993048Samaguire 
4003048Samaguire /* Callback for upgrade of legacy daemons */
4013048Samaguire static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
4023048Samaguire 
4033048Samaguire /* Callbacks used to set/retieve routing options */
4043048Samaguire static int ra_set_current_opt_cb(void *, scf_walkinfo_t *);
4053048Samaguire static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t *);
4063048Samaguire static int ra_set_default_opt_cb(void *, scf_walkinfo_t *);
4073048Samaguire static int ra_get_current_opt_cb(void *, scf_walkinfo_t *);
4083048Samaguire static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t *);
4093048Samaguire static int ra_get_default_opt_cb(void *, scf_walkinfo_t *);
4103048Samaguire static int ra_get_set_opt_common_cb(raopt_t *, scf_walkinfo_t *, boolean_t,
4113048Samaguire     boolean_t);
412*3294Samaguire static int ra_routing_opt_set_cb(void *, scf_walkinfo_t *);
413*3294Samaguire static int ra_routing_opt_unset_cb(void *, scf_walkinfo_t *);
414*3294Samaguire static int ra_routing_opt_set_unset_cb(raopt_t *, scf_walkinfo_t *, boolean_t);
4153048Samaguire 
4163048Samaguire /* Callbacks used to set/retrieve routing variables */
4173048Samaguire static int ra_set_persistent_var_cb(void *, scf_walkinfo_t *);
4183048Samaguire static int ra_get_persistent_var_cb(void *, scf_walkinfo_t *);
4193048Samaguire static int ra_get_default_var_cb(void *, scf_walkinfo_t *);
4203048Samaguire static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t *);
4213048Samaguire 
4223048Samaguire /* Callbacks used to list/set daemon properties and list daemons and states. */
4233048Samaguire static int ra_list_props_cb(void *, scf_walkinfo_t *);
4243048Samaguire static int ra_modify_props_cb(void *, scf_walkinfo_t *);
4253048Samaguire static int ra_print_state_cb(void *, scf_walkinfo_t *);
4263048Samaguire 
4273048Samaguire /* Utility functions for SMF operations */
4283048Samaguire static int ra_get_pg(scf_handle_t *, scf_instance_t *, const char *,
4293048Samaguire     boolean_t, boolean_t, scf_propertygroup_t **);
4303048Samaguire static int ra_get_boolean_prop(scf_handle_t *, scf_instance_t *,
4313048Samaguire     const char *, const char *,  boolean_t, boolean_t, boolean_t *);
4323048Samaguire static int ra_get_single_prop_as_string(scf_handle_t *, scf_instance_t *,
4333048Samaguire     const char *, const char *, boolean_t, boolean_t, scf_type_t *, char **);
4343048Samaguire static int ra_get_prop_as_string(scf_handle_t *, scf_instance_t *,
4353048Samaguire     const char *, const char *, boolean_t, boolean_t, scf_type_t *, int *,
4363048Samaguire     char ***);
4373048Samaguire static void ra_free_prop_values(int, char **);
4383048Samaguire static int ra_set_boolean_prop(scf_handle_t *, scf_instance_t *,
4393048Samaguire     const char *, const char *, boolean_t, boolean_t);
4403048Samaguire static int ra_set_prop_from_string(scf_handle_t *, scf_instance_t *,
4413048Samaguire     const char *, const char *, scf_type_t, boolean_t, int,
4423048Samaguire     const char **);
4433048Samaguire 
4443048Samaguire static void
usage(void)4453048Samaguire usage(void)
4463048Samaguire {
4473048Samaguire 	(void) fprintf(stderr, gettext(
4483048Samaguire 	    "usage: %1$s [-p] [-R <root-dir>]\n"
4493048Samaguire 	    "       %1$s [-e <option>] [-d <option>] [-r <option>]\n"
4503048Samaguire 	    "           [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
4513048Samaguire 	    "           [-s <var>=<val>] [-R <root-dir>]\n"
4523048Samaguire 	    "       %1$s -u\n\n"
4533048Samaguire 	    "       <option> is one of:\n"
4543048Samaguire 	    "       ipv4-forwarding\n"
4553048Samaguire 	    "       ipv4-routing\n"
4563048Samaguire 	    "       ipv6-forwarding\n"
4573048Samaguire 	    "       ipv6-routing\n\n"
4583048Samaguire 	    "       <var> is one of:\n"
4593048Samaguire 	    "       ipv4-routing-daemon\n"
4603048Samaguire 	    "       ipv4-routing-daemon-args\n"
4613048Samaguire 	    "       ipv4-routing-stop-cmd\n"
4623048Samaguire 	    "       ipv6-routing-daemon\n"
4633048Samaguire 	    "       ipv6-routing-daemon-args\n"
4643048Samaguire 	    "       ipv6-routing-stop-cmd\n"
4653048Samaguire 	    "       routing-svcs\n"), myname);
4663048Samaguire }
4673048Samaguire 
4683048Samaguire int
main(int argc,char * argv[])4693048Samaguire main(int argc, char *argv[])
4703048Samaguire {
4713048Samaguire 	int		opt, opt_index, numargs, status = 0;
4723048Samaguire 	int		numvalues, i;
4733048Samaguire 	ssize_t		keylen;
4743048Samaguire 	boolean_t	modify = B_FALSE, report = B_TRUE, update = B_FALSE;
475*3294Samaguire 	boolean_t	booting = B_FALSE, alt_root_set = B_FALSE;
4763048Samaguire 	boolean_t	parseable = B_FALSE;
4773048Samaguire 	char		*key, *nk, *keyend, *val, **vals, *options, *fmri;
4783048Samaguire 	char		*parseopt = NULL;
4793048Samaguire 	raopt_t		*raopt;
4803048Samaguire 	ravar_t		*ravar;
4813048Samaguire 	ra_prop_t	raprop;
4823048Samaguire 
4833048Samaguire 	myname = argv[0];
4843048Samaguire 
4853048Samaguire 	(void) setlocale(LC_ALL, "");
4863048Samaguire 
4873048Samaguire #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
4883048Samaguire #define	TEXT_DOMAIN	"SYS_TEST"
4893048Samaguire #endif
4903048Samaguire 
4913048Samaguire 	(void) textdomain(TEXT_DOMAIN);
4923048Samaguire 
4933048Samaguire 	/*
4943048Samaguire 	 * Before processing any options, we parse /etc/inet/routing.conf
4953048Samaguire 	 * (if present) and transfer values to SMF.
4963048Samaguire 	 */
4973048Samaguire 	if (ra_upgrade_from_legacy_conf() == -1)
4983048Samaguire 		exit(EXIT_FAILURE);
499*3294Samaguire 	while ((opt = getopt(argc, argv, ":bd:e:l:m:p:R:r:s:u")) != EOF) {
5003048Samaguire 		switch (opt) {
501*3294Samaguire 		case 'b':
502*3294Samaguire 			/*
503*3294Samaguire 			 * Project-private option that tells us enable/disable
504*3294Samaguire 			 * operations should not set ipv4(6)-routing-set
505*3294Samaguire 			 * property.  Used in routing-setup service method
506*3294Samaguire 			 * to change default routing state, and, if
507*3294Samaguire 			 * no explicit enable/disable operations have been
508*3294Samaguire 			 * carried out, change current ipv4 routing state.
509*3294Samaguire 			 */
510*3294Samaguire 			booting = B_TRUE;
511*3294Samaguire 			break;
5123048Samaguire 		case 'd':
5133048Samaguire 		case 'e':
5143048Samaguire 		case 'r':
5153048Samaguire 			if (alt_root_set) {
5163048Samaguire 				if (ra_upgrade_cmd(opt, 1, &optarg) != 0)
5173048Samaguire 					exit(EXIT_FAILURE);
5183048Samaguire 				modify = B_TRUE;
5193048Samaguire 				break;
5203048Samaguire 			}
5213048Samaguire 			if ((raopt = ra_str2opt(optarg)) != NULL) {
5223048Samaguire 				/* Set current value appropriately */
5233048Samaguire 				switch (opt) {
5243048Samaguire 				case 'd':
5253048Samaguire 					raopt->opt_enabled = B_FALSE;
5263048Samaguire 					break;
5273048Samaguire 				case 'e':
5283048Samaguire 					/*
5293048Samaguire 					 * Check legacy daemons, mark
5303048Samaguire 					 * routing-svcs.
5313048Samaguire 					 */
5323048Samaguire 					if (IS_ROUTING_OPT(optarg) &&
5333048Samaguire 					    ra_check_legacy_daemons() == -1)
5343048Samaguire 						exit(EXIT_FAILURE);
5353048Samaguire 					raopt->opt_enabled = B_TRUE;
5363048Samaguire 					break;
5373048Samaguire 				case 'r':
5383048Samaguire 					/*
5393048Samaguire 					 * This callback sets opt_enabled to
5403048Samaguire 					 * the default value.
5413048Samaguire 					 */
5423048Samaguire 					ra_resetopts();
5433048Samaguire 					if (ra_smf_cb(ra_get_default_opt_cb,
5443048Samaguire 					    raopt->opt_default_fmri, raopt)
5453048Samaguire 					    == -1)
5463048Samaguire 						exit(EXIT_FAILURE);
5473048Samaguire 					if (raopt->opt_enabled &&
5483048Samaguire 					    IS_ROUTING_OPT(optarg) &&
5493048Samaguire 					    ra_check_legacy_daemons() == -1)
5503048Samaguire 						exit(EXIT_FAILURE);
5513048Samaguire 					/* set value to default */
5523048Samaguire 					raopt->opt_enabled =
5533048Samaguire 					    raopt->opt_default_enabled;
5543048Samaguire 					break;
5553048Samaguire 				}
5563048Samaguire 				if (ra_smf_cb(ra_set_persistent_opt_cb,
5573048Samaguire 				    raopt->opt_fmri, raopt) == -1)
5583048Samaguire 					exit(EXIT_FAILURE);
559*3294Samaguire 				/*
560*3294Samaguire 				 * ipv4(6)-routing explicitly enabled/disabled,
561*3294Samaguire 				 * need to set ipv4(6)-routing-set property
562*3294Samaguire 				 * for routing-setup service.  Once this
563*3294Samaguire 				 * is set, routing-setup will not override
564*3294Samaguire 				 * administrator action and will not enable
565*3294Samaguire 				 * ipv4-routing in the case that no default
566*3294Samaguire 				 * route can be determined.  If ipv4(6)-routing
567*3294Samaguire 				 * is reverted to its default value,  set
568*3294Samaguire 				 * ipv4(6)-routing-set back to false.
569*3294Samaguire 				 */
570*3294Samaguire 				if (!booting && (raopt->opt_flags &
571*3294Samaguire 				    (RA_SVC_FLAG_IPV4_ROUTING |
572*3294Samaguire 				    RA_SVC_FLAG_IPV6_ROUTING))) {
573*3294Samaguire 					if (ra_smf_cb(opt == 'r' ?
574*3294Samaguire 					    ra_routing_opt_unset_cb :
575*3294Samaguire 					    ra_routing_opt_set_cb,
576*3294Samaguire 					    raopt->opt_default_fmri, raopt)
577*3294Samaguire 					    == -1)
578*3294Samaguire 						exit(EXIT_FAILURE);
579*3294Samaguire 				}
5803048Samaguire 			} else if ((ravar = ra_str2var(optarg)) != NULL) {
5813048Samaguire 				if (opt != 'r') {
5823048Samaguire 					usage();
5833048Samaguire 					exit(EXIT_FAILURE);
5843048Samaguire 				}
5853048Samaguire 				/* set current value to default */
5863048Samaguire 				ra_resetopts();
5873048Samaguire 				if (ra_smf_cb(ra_get_default_var_cb,
5883048Samaguire 				    ravar->var_default_fmri, ravar) == -1)
5893048Samaguire 					exit(EXIT_FAILURE);
5903048Samaguire 				/* Need special case for routing-svcs var */
5913048Samaguire 				if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
5923048Samaguire 				    == 0) {
5933048Samaguire 					if (ra_update_routing_svcs(
5943048Samaguire 					    ravar->var_default_value) == -1)
5953048Samaguire 						exit(EXIT_FAILURE);
5963048Samaguire 				} else if (ra_smf_cb(ra_set_persistent_var_cb,
5973048Samaguire 				    ravar->var_fmri, ravar) == -1)
5983048Samaguire 					exit(EXIT_FAILURE);
5993048Samaguire 			} else {
6003048Samaguire 				(void) fprintf(stderr, gettext(
6013048Samaguire 				    "%1$s: invalid option: %2$s\n"), myname,
6023048Samaguire 				    optarg);
6033048Samaguire 				usage();
6043048Samaguire 				exit(EXIT_FAILURE);
6053048Samaguire 			}
6063048Samaguire 			modify = B_TRUE;
6073048Samaguire 			break;
6083048Samaguire 		case 'l':
6093048Samaguire 			if (ra_smf_cb(ra_list_props_cb, optarg, NULL) == -1)
6103048Samaguire 				exit(EXIT_FAILURE);
6113048Samaguire 			report = B_FALSE;
6123048Samaguire 			break;
6133048Samaguire 		case 'm':
6143048Samaguire 			fmri = optarg;
6153048Samaguire 			modify = B_TRUE;
6163048Samaguire 			/*
6173048Samaguire 			 * Argument list of key=value pairs, we need to
6183048Samaguire 			 * collate all matching keys to set multiple values.
6193048Samaguire 			 */
6203048Samaguire 			numargs = 1;
6213048Samaguire 			i = optind;
6223048Samaguire 			for (numargs = 1; argv[i] != NULL && argv[i][0] != '-';
6233048Samaguire 			    numargs++)
6243048Samaguire 				i++;
6253048Samaguire 			if (numargs == 1) {
6263048Samaguire 				(void) fprintf(stderr, gettext(
6273048Samaguire 				    "%s: key=value required for "
6283048Samaguire 				    "property change\n"), myname);
6293048Samaguire 				usage();
6303048Samaguire 				exit(EXIT_FAILURE);
6313048Samaguire 			}
6323048Samaguire 			if (alt_root_set) {
6333048Samaguire 				if (ra_upgrade_cmd(opt, numargs,
6343048Samaguire 				    &argv[optind - 1]) == -1)
6353048Samaguire 					exit(EXIT_FAILURE);
6363048Samaguire 				optind += numargs - 1;
6373048Samaguire 				break;
6383048Samaguire 			}
6393048Samaguire 			/*
6403048Samaguire 			 * Collect all key=value pairs which use same key
6413048Samaguire 			 * so we can add multiple property values.
6423048Samaguire 			 */
6433048Samaguire 			for (key = argv[optind]; key != NULL && key[0] != '-';
6443048Samaguire 			    key = argv[++optind]) {
6453048Samaguire 				if (key[0] == '\0')
6463048Samaguire 					continue;
6473048Samaguire 				vals = malloc(sizeof (char *));
6483048Samaguire 				if ((vals[0] = strchr(key, '=')) == NULL) {
6493048Samaguire 					(void) fprintf(stderr, gettext(
6503048Samaguire 					    "%s: Malformed name=value "
6513048Samaguire 					    "pair %s\n"), myname, key);
6523048Samaguire 					exit(EXIT_FAILURE);
6533048Samaguire 				}
6543048Samaguire 				numvalues = 1;
6553048Samaguire 				*(vals[0]) = '\0';
6563048Samaguire 				(vals[0])++;
6573048Samaguire 				i = optind + 1;
6583048Samaguire 				for (nk = argv[i];
6593048Samaguire 				    nk != NULL && nk[0] != '-';
6603048Samaguire 				    nk = argv[++i]) {
6613048Samaguire 					if (nk[0] == '\0')
6623048Samaguire 						continue;
6633048Samaguire 					if ((keyend = strchr(nk, '='))
6643048Samaguire 					    == NULL) {
6653048Samaguire 						(void) fprintf(stderr, gettext(
6663048Samaguire 						    "%s: Malformed name=value "
6673048Samaguire 						    " pair %s\n"), myname, nk);
6683048Samaguire 						exit(EXIT_FAILURE);
6693048Samaguire 					}
6703048Samaguire 					if ((keylen = keyend - nk) !=
6713048Samaguire 					    strlen(key))
6723048Samaguire 						continue;
6733048Samaguire 					if (strncmp(key, nk, keylen) == 0) {
6743048Samaguire 						vals = realloc(vals, ++numvalues
6753048Samaguire 						    * sizeof (char *));
6763048Samaguire 						vals[numvalues - 1] = ++keyend;
6773048Samaguire 						nk[0] = '\0';
6783048Samaguire 						optind++;
6793048Samaguire 					}
6803048Samaguire 				}
6813048Samaguire 				raprop.prop_name = key;
6823048Samaguire 				raprop.prop_values = vals;
6833048Samaguire 				raprop.prop_numvalues = numvalues;
6843048Samaguire 				if (ra_smf_cb(ra_modify_props_cb, fmri,
6853048Samaguire 				    &raprop) == -1)
6863048Samaguire 					exit(EXIT_FAILURE);
6873048Samaguire 			}
6883048Samaguire 			break;
6893048Samaguire 		case 'p':
6903048Samaguire 			parseable = B_TRUE;
6913048Samaguire 			parseopt = optarg;
6923048Samaguire 			break;
6933048Samaguire 		case 'R':
6943048Samaguire 			if (chroot(optarg) == -1) {
6953048Samaguire 				(void) fprintf(stderr, gettext(
6963048Samaguire 				    "%1$s: failed to chroot to %2$s: %3$s\n"),
6973048Samaguire 				    myname, optarg, strerror(errno));
6983048Samaguire 				exit(EXIT_FAILURE);
6993048Samaguire 			}
7003048Samaguire 			alt_root_set = B_TRUE;
7013048Samaguire 			report = B_FALSE;
7023048Samaguire 			break;
7033048Samaguire 		case 's':
7043048Samaguire 			if (alt_root_set) {
7053048Samaguire 				if (ra_upgrade_cmd(opt, 1, &optarg) == -1)
7063048Samaguire 					exit(EXIT_FAILURE);
7073048Samaguire 				modify = B_TRUE;
7083048Samaguire 				break;
7093048Samaguire 			}
7103048Samaguire 			options = optarg;
7113048Samaguire 			while (*options != '\0') {
7123048Samaguire 				opt_index = getsubopt(&options, v_opt, &val);
7133048Samaguire 				if (val == NULL) {
7143048Samaguire 					usage();
7153048Samaguire 					exit(EXIT_FAILURE);
7163048Samaguire 				}
7173048Samaguire 				if (opt_index == -1) {
7183048Samaguire 					(void) fprintf(stderr, gettext(
7193048Samaguire 					    "%1$s: invalid variable: %2$s\n"),
7203048Samaguire 					    myname, optarg);
7213048Samaguire 					usage();
7223048Samaguire 					exit(EXIT_FAILURE);
7233048Samaguire 				}
7243048Samaguire 				ravar = &ra_vars[opt_index];
7253048Samaguire 				/* Need special case for routing-svcs var */
7263048Samaguire 				if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
7273048Samaguire 				    == 0) {
7283048Samaguire 					if (ra_update_routing_svcs(val) == -1)
7293048Samaguire 						return (-1);
7303048Samaguire 				} else {
7313048Samaguire 					ravar->var_value = strdup(val);
7323048Samaguire 					if (ra_smf_cb(ra_set_persistent_var_cb,
7333048Samaguire 					    ravar->var_fmri, ravar) == -1)
7343048Samaguire 						exit(EXIT_FAILURE);
7353048Samaguire 				}
7363048Samaguire 			}
7373048Samaguire 			modify = B_TRUE;
7383048Samaguire 			break;
7393048Samaguire 		case 'u':
7403048Samaguire 			update = B_TRUE;
7413048Samaguire 			break;
7423048Samaguire 		case ':':
7433048Samaguire 			/* if not 'p', usage failure */
7443048Samaguire 			if (strcmp(argv[optind - 1], "-p") != 0) {
7453048Samaguire 				(void) fprintf(stderr, gettext(
7463048Samaguire 				    "%s: option requires an argument -%s\n"),
7473048Samaguire 				    myname, argv[optind - 1]);
7483048Samaguire 				usage();
7493048Samaguire 				exit(EXIT_FAILURE);
7503048Samaguire 			}
7513048Samaguire 			parseable = B_TRUE;
7523048Samaguire 			break;
7533048Samaguire 		case '?':
7543048Samaguire 			usage();
7553048Samaguire 			exit(EXIT_FAILURE);
7563048Samaguire 		}
7573048Samaguire 	}
7583048Samaguire 
7593048Samaguire 	if (argc > optind) {
7603048Samaguire 		/* There shouldn't be any extra args. */
7613048Samaguire 		usage();
7623048Samaguire 		exit(EXIT_FAILURE);
7633048Samaguire 	}
7643048Samaguire 
7653048Samaguire 	if (parseable && (update || modify)) {
7663048Samaguire 		(void) fprintf(stderr, gettext("%s: the -p option cannot be "
7673048Samaguire 		    "used with any of -demrsu\n"), myname);
7683048Samaguire 		usage();
7693048Samaguire 		exit(EXIT_FAILURE);
7703048Samaguire 	}
7713048Samaguire 
7723048Samaguire 	if (update && ! alt_root_set)
7733048Samaguire 		status = ra_update();
7743048Samaguire 
7753048Samaguire 	if (report && !modify && !update)
7763048Samaguire 		status = ra_report(parseable, parseopt);
7773048Samaguire 
7783048Samaguire 	return (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
7793048Samaguire }
7803048Samaguire 
7813048Samaguire /*
7823048Samaguire  * Upgrade legacy daemons,  mark to-be-enabled routing services.
7833048Samaguire  */
7843048Samaguire static int
ra_check_legacy_daemons(void)7853048Samaguire ra_check_legacy_daemons(void)
7863048Samaguire {
7873048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
7883048Samaguire 	ravar_t		*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
7893048Samaguire 	ravar_t		*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
7903048Samaguire 	char		*fmri, *nextfmri;
7913048Samaguire 	boolean_t	mark = B_FALSE;
7923048Samaguire 
7933048Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
7943048Samaguire 	    routing_svcs) == -1)
7953048Samaguire 		return (-1);
7963048Samaguire 
7973048Samaguire 	/* First unmark all services */
7983048Samaguire 	if (ra_smf_cb(ra_mark_routing_svcs_cb, NULL, &mark) == -1)
7993048Samaguire 		return (-1);
8003048Samaguire 
8013048Samaguire 	mark = B_TRUE;
8023048Samaguire 	if (routing_svcs->var_value != NULL) {
8033048Samaguire 		/*
8043048Samaguire 		 * For routing-svcs variable, mark each named
8053048Samaguire 		 * service as a current-routing-svc.
8063048Samaguire 		 */
8073048Samaguire 		if ((fmri = strdup(routing_svcs->var_value)) == NULL) {
8083048Samaguire 			(void) fprintf(stderr, gettext(
8093048Samaguire 			    "%s: out of memory\n"), myname);
8103048Samaguire 			return (-1);
8113048Samaguire 		}
8123048Samaguire 		/* Now, mark each service named in routing-svcs. */
8133048Samaguire 		for (nextfmri = strtok(fmri, " \t");
8143048Samaguire 		    nextfmri != NULL;
8153048Samaguire 		    nextfmri = strtok(NULL, " \t")) {
8163048Samaguire 			if (ra_smf_cb(ra_mark_routing_svcs_cb, nextfmri,
8173048Samaguire 			    &mark) == -1) {
8183048Samaguire 				free(fmri);
8193048Samaguire 				return (-1);
8203048Samaguire 			}
8213048Samaguire 		}
8223048Samaguire 		free(fmri);
8233048Samaguire 	}
8243048Samaguire 
8253048Samaguire 	/*
8263048Samaguire 	 * Now check if legacy variables (if specified) map to SMF routing
8273048Samaguire 	 * daemons.  If so, transfer associated daemon arguments.
8283048Samaguire 	 */
8293048Samaguire 	if (ra_upgrade_legacy_daemons() == -1)
8303048Samaguire 		return (-1);
8313048Samaguire 
8323048Samaguire 	ra_resetvars(NULL);
8333048Samaguire 	/*
8343048Samaguire 	 * At this point, if the legacy services still have ipv4/ipv6
8353048Samaguire 	 * routing daemons specified, we know they weren`t upgraded, so
8363048Samaguire 	 * we mark them also.
8373048Samaguire 	 */
8383048Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
8393048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1)
8403048Samaguire 		return (-1);
8413048Samaguire 
8423048Samaguire 	if (v4d->var_value != NULL && strtok(v4d->var_value, " \t") != NULL &&
8433048Samaguire 	    ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV4,
8443048Samaguire 	    &mark) == -1)
8453048Samaguire 		return (-1);
8463048Samaguire 	if (v6d->var_value != NULL && strtok(v6d->var_value, " \t") != NULL &&
8473048Samaguire 	    ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV6,
8483048Samaguire 	    &mark) == -1)
8493048Samaguire 		return (-1);
8503048Samaguire 
8513048Samaguire 	return (0);
8523048Samaguire }
8533048Samaguire 
8543048Samaguire /*
8553048Samaguire  * Retrieve legacy daemon variables,  and check if any SMF routing daemons
8563048Samaguire  * run the daemons specified.  If so, the legacy configuration (arguments
8573048Samaguire  * to the daemon) is transferred to the routeadm/daemon-args property
8583048Samaguire  * of the corresponding instance.  From there,  the instance picks up the
8593048Samaguire  * value and will transfer the daemon arguments to individiual properties
8603048Samaguire  * when enabled.
8613048Samaguire  */
8623048Samaguire static int
ra_upgrade_legacy_daemons(void)8633048Samaguire ra_upgrade_legacy_daemons(void)
8643048Samaguire {
8653048Samaguire 	ravar_t	*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
8663048Samaguire 	ravar_t	*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
8673048Samaguire 	ravar_t	*v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
8683048Samaguire 	ravar_t	*v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
8693048Samaguire 	ravar_t	*v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
8703048Samaguire 	ravar_t	*v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
8713048Samaguire 
8723048Samaguire 	if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
8733048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1 ||
8743048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v4args->var_fmri, v4args)
8753048Samaguire 	    == -1 ||
8763048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6args->var_fmri, v6args)
8773048Samaguire 	    == -1 ||
8783048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v4stop->var_fmri, v4stop)
8793048Samaguire 	    == -1 ||
8803048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, v6stop->var_fmri, v6stop)
8813048Samaguire 	    == -1)
8823048Samaguire 		return (-1);
8833048Samaguire 
8843048Samaguire 	return (ra_smf_cb(ra_upgrade_legacy_daemons_cb, NULL, NULL));
8853048Samaguire }
8863048Samaguire 
8873048Samaguire /*
8883048Samaguire  * Determine if service runs the same daemon as that which is specified
8893048Samaguire  * in ipv4-routing-daemon or ipv6-routing-daemon.  If so, the associated
8903048Samaguire  * daemon arguments are transferred to the service.
8913048Samaguire  */
8923048Samaguire 
8933048Samaguire /* ARGSUSED0 */
8943048Samaguire static int
ra_upgrade_legacy_daemons_cb(void * data,scf_walkinfo_t * wip)8953048Samaguire ra_upgrade_legacy_daemons_cb(void *data, scf_walkinfo_t *wip)
8963048Samaguire {
8973048Samaguire 	const char	*inst_fmri = wip->fmri;
8983048Samaguire 	scf_instance_t	*inst = wip->inst;
8993048Samaguire 	scf_handle_t	*h = scf_instance_handle(inst);
9003048Samaguire 	char		*daemon, *l_daemon = NULL;
9013048Samaguire 	ravar_t		*v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
9023048Samaguire 	ravar_t		*v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
9033048Samaguire 	ravar_t		*v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
9043048Samaguire 	ravar_t		*v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
9053048Samaguire 	ravar_t		*v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
9063048Samaguire 	ravar_t		*v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
9073048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
9083048Samaguire 	boolean_t	mark, marked;
9093048Samaguire 	char		*new_routing_svcs;
9103048Samaguire 
9113048Samaguire 	/*
9123048Samaguire 	 * Ensure instance is a routing service, and not one of the
9133048Samaguire 	 * legacy instances - if it is, the daemon property is already
9143048Samaguire 	 * set to the legacy daemon.
9153048Samaguire 	 */
9163048Samaguire 	if (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
9173048Samaguire 	    RA_PROP_DAEMON, B_TRUE, B_FALSE, NULL, &daemon) == -1 ||
9183048Samaguire 	    strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV4, inst_fmri) == 0 ||
9193048Samaguire 	    strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV6, inst_fmri) == 0)
9203048Samaguire 		return (0);
9213048Samaguire 
9223048Samaguire 	/* A legacy daemon may be defined */
9233048Samaguire 	(void) ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
9243048Samaguire 	    RA_PROP_LEGACY_DAEMON, B_TRUE, B_FALSE, NULL, &l_daemon);
9253048Samaguire 
9263048Samaguire 	/*
9273048Samaguire 	 * If we match daemon/legacy_daemon with ipv4-routing-daemon or
9283048Samaguire 	 * ipv6-routing-daemon values, transfer daemon-args value
9293048Samaguire 	 * to the matching service.
9303048Samaguire 	 */
9313048Samaguire 	if (v4d->var_value != NULL && (strcmp(v4d->var_value, daemon) == 0 ||
9323048Samaguire 	    (l_daemon != NULL && strcmp(v4d->var_value, l_daemon) == 0))) {
9333048Samaguire 		(void) printf(gettext("%s: migrating daemon configuration "
9343048Samaguire 		    "for %s to %s\n"), myname, l_daemon != NULL ?
9353048Samaguire 		    l_daemon : daemon, inst_fmri);
9363048Samaguire 		/* Transfer daemon-args value, clear legacy v4 values */
9373048Samaguire 		if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
9383048Samaguire 		    RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
9393048Samaguire 		    (const char **)&(v4args->var_value)) == -1)
9403048Samaguire 			return (-1);
9413048Samaguire 		ra_resetvars(RA_PROPVAL_PROTO_IPV4);
9423048Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb,
9433048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4d) == -1 ||
9443048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
9453048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4args) == -1 ||
9463048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
9473048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV4, v4stop) == -1)
9483048Samaguire 			return (-1);
9493048Samaguire 	} else if (v6d->var_value != NULL && (strcmp(v6d->var_value, daemon)
9503048Samaguire 	    == 0 ||
9513048Samaguire 	    (l_daemon != NULL && strcmp(v6d->var_value, l_daemon) == 0))) {
9523048Samaguire 		(void) printf(gettext("%s: migrating daemon configuration "
9533048Samaguire 		    "for %s to %s\n"), myname, l_daemon != NULL ?
9543048Samaguire 		    l_daemon : daemon, inst_fmri);
9553048Samaguire 		/* Transfer daemon-args value, clear legacy v6 values */
9563048Samaguire 		if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
9573048Samaguire 		    RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
9583048Samaguire 		    (const char **)&(v6args->var_value)) == -1)
9593048Samaguire 			return (-1);
9603048Samaguire 		ra_resetvars(RA_PROPVAL_PROTO_IPV6);
9613048Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb,
9623048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6d) == -1 ||
9633048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
9643048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6args) == -1 ||
9653048Samaguire 		    ra_smf_cb(ra_set_persistent_var_cb,
9663048Samaguire 		    RA_INSTANCE_LEGACY_ROUTING_IPV6, v6stop) == -1)
9673048Samaguire 			return (-1);
9683048Samaguire 	} else
9693048Samaguire 		return (0);
9703048Samaguire 
9713048Samaguire 	/*
9723048Samaguire 	 * If service is unmarked at this point, add it to routing-svcs and
9733048Samaguire 	 * mark it.
9743048Samaguire 	 */
9753048Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
9763048Samaguire 	    RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE, &marked) == -1 ||
9773048Samaguire 	    marked == B_FALSE) {
9783048Samaguire 		mark = B_TRUE;
9793048Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, inst_fmri, &mark)
9803048Samaguire 		    == -1 ||
9813048Samaguire 		    ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
9823048Samaguire 		    routing_svcs) == -1)
9833048Samaguire 			return (-1);
9843048Samaguire 		if ((new_routing_svcs =
9853048Samaguire 		    malloc(strlen(routing_svcs->var_value) +
9863048Samaguire 		    strlen(inst_fmri) + 2)) == NULL) {
9873048Samaguire 			(void) fprintf(stderr, gettext(
9883048Samaguire 			    "%s: out of memory"), myname);
9893048Samaguire 			return (-1);
9903048Samaguire 		}
9913048Samaguire 		if (strlen(routing_svcs->var_value) == 0)
9923048Samaguire 			(void) snprintf(new_routing_svcs,
9933048Samaguire 			    strlen(inst_fmri) + 1, "%s", inst_fmri);
9943048Samaguire 		else
9953048Samaguire 			(void) snprintf(new_routing_svcs,
9963048Samaguire 			    strlen(routing_svcs->var_value) +
9973048Samaguire 			    strlen(inst_fmri) + 2, "%s %s",
9983048Samaguire 			    routing_svcs->var_value, inst_fmri);
9993048Samaguire 		free(routing_svcs->var_value);
10003048Samaguire 		routing_svcs->var_value = new_routing_svcs;
10013048Samaguire 		(void) smf_refresh_instance(inst_fmri);
10023048Samaguire 		return (ra_smf_cb(ra_set_persistent_var_cb,
10033048Samaguire 		    routing_svcs->var_fmri, routing_svcs));
10043048Samaguire 	}
10053048Samaguire 	(void) smf_refresh_instance(inst_fmri);
10063048Samaguire 	return (0);
10073048Samaguire }
10083048Samaguire 
10093048Samaguire /*
10103048Samaguire  * If we are upgrading,  append operation to <alt_root>/var/svc/profile/upgrade.
10113048Samaguire  */
10123048Samaguire static int
ra_upgrade_cmd(char opt,int argc,char ** argv)10133048Samaguire ra_upgrade_cmd(char opt, int argc, char **argv)
10143048Samaguire {
10153048Samaguire 	FILE	*fp;
10163048Samaguire 	int	i;
10173048Samaguire 
10183048Samaguire 	if ((fp = fopen(RA_SMF_UPGRADE_FILE, "a+")) == NULL) {
10193048Samaguire 		(void) fprintf(stderr, gettext(
10203048Samaguire 		    "%1$s: failed to open %2$s: %3$s\n"),
10213048Samaguire 		    myname, RA_SMF_UPGRADE_FILE, strerror(errno));
10223048Samaguire 		return (-1);
10233048Samaguire 	}
10243048Samaguire 	(void) fprintf(fp, "/sbin/routeadm -%c ", opt);
10253048Samaguire 	if (argv != NULL) {
10263048Samaguire 		for (i = 0; i < argc; i++)
10273048Samaguire 			(void) fprintf(fp, "%s ", argv[i]);
10283048Samaguire 	}
10293048Samaguire 	(void) fprintf(fp, "%s\n", RA_SMF_UPGRADE_MSG);
10303048Samaguire 	(void) fclose(fp);
10313048Samaguire 	return (0);
10323048Samaguire }
10333048Samaguire 
10343048Samaguire /*
10353048Samaguire  * Set current state to "next boot" state, i.e. if general/enabled
10363048Samaguire  * value is overlaid by a general_ovr/enabled value, set the current state
10373048Samaguire  * to the value of the latter.  Doing this applies "next boot" changes to
10383094Samaguire  * the current setup.  If any IPv6 interfaces are present, also start in.ndpd.
10393048Samaguire  */
10403048Samaguire static int
ra_update(void)10413048Samaguire ra_update(void)
10423048Samaguire {
10433094Samaguire 	int	i;
10443048Samaguire 
10453048Samaguire 	if (ra_check_legacy_daemons() == -1)
10463048Samaguire 		return (-1);
10473048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
10483094Samaguire 		if (ra_smf_cb(ra_set_current_opt_cb, ra_opts[i].opt_fmri,
10493094Samaguire 		    &ra_opts[i]) == -1) {
10503094Samaguire 			return (-1);
10513094Samaguire 		}
10523048Samaguire 	}
10533094Samaguire 	/*
10543094Samaguire 	 * If in.ndpd isn't already running, then we start it here, regardless
10553094Samaguire 	 * of global IPv6 routing status (provided there are IPv6 interfaces
10563094Samaguire 	 * present).
10573094Samaguire 	 */
10583094Samaguire 	if (ra_numv6intfs() > 0)
10593094Samaguire 		return (smf_enable_instance(RA_INSTANCE_NDP, SMF_TEMPORARY));
10603094Samaguire 	return (0);
10613048Samaguire }
10623048Samaguire 
10633048Samaguire /*
10643048Samaguire  * Here we catch the special case where ipv4/ipv6 routing was enabled,
10653048Samaguire  * and the user updates the routing-svcs list.  The problem is that
10663048Samaguire  * the enabled state is the result of services on the old routing-svcs list
10673048Samaguire  * being enabled, and we want to support users doing something like this:
10683048Samaguire  *
10693048Samaguire  * # routeadm -s routing-svcs=route -e ipv4-routing -u
10703048Samaguire  *
10713048Samaguire  * followed by
10723048Samaguire  *
10733048Samaguire  * # routeadm -s routing-svcs=rdisc -u
10743048Samaguire  *
10753048Samaguire  * To do this, we need to:
10763048Samaguire  *	- cache the old ipv4-routing/ipv6-routing values.
10773048Samaguire  *	- persistently disable the old routing-svcs list.
10783048Samaguire  *	- if ipv4-routing was enabled, mark and persistently enable all the new
10793048Samaguire  *	v4 routing-svcs
10803048Samaguire  *	- if ipv6-routing was enabled, mark and persistently enable all the new
10813048Samaguire  *	v6 routing-svcs.
10823048Samaguire  * This will result in the next "-u" switching on the new routing-svcs, and
10833048Samaguire  * switching off the old ones,  as the user would expect.
10843048Samaguire  */
10853048Samaguire static int
ra_update_routing_svcs(char * routing_svcs_new)10863048Samaguire ra_update_routing_svcs(char *routing_svcs_new)
10873048Samaguire {
10883048Samaguire 	raopt_t		*v4opt = ra_str2opt(RA_OPT_IPV4_ROUTING);
10893048Samaguire 	raopt_t		*v6opt = ra_str2opt(RA_OPT_IPV6_ROUTING);
10903048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
10913048Samaguire 	char		*routing_svcs_old, *fmri;
10923048Samaguire 	boolean_t	v4_old, v6_old, mark = B_FALSE;
10933048Samaguire 
10943048Samaguire 	ra_resetopts();
10953048Samaguire 	if (ra_smf_cb(ra_get_persistent_opt_cb, v4opt->opt_fmri, v4opt) == -1 ||
10963048Samaguire 	    ra_smf_cb(ra_get_persistent_opt_cb, v6opt->opt_fmri, v6opt) == -1 ||
10973048Samaguire 	    ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
10983048Samaguire 	    routing_svcs) == -1)
10993048Samaguire 		return (-1);
11003048Samaguire 	v4_old = v4opt->opt_enabled;
11013048Samaguire 	v6_old = v6opt->opt_enabled;
11023048Samaguire 	routing_svcs_old = routing_svcs->var_value;
11033048Samaguire 	routing_svcs->var_value = routing_svcs_new;
11043048Samaguire 
11053048Samaguire 	if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
11063048Samaguire 	    routing_svcs) == -1) {
11073048Samaguire 		free(routing_svcs_old);
11083048Samaguire 		return (-1);
11093048Samaguire 	}
11103048Samaguire 
11113048Samaguire 	if (!v4_old && !v6_old) {
11123048Samaguire 		/* We don`t need to do anything, since services were disabled */
11133048Samaguire 		free(routing_svcs_old);
11143048Samaguire 		return (0);
11153048Samaguire 	}
11163048Samaguire 	v4opt->opt_enabled = B_FALSE;
11173048Samaguire 	v6opt->opt_enabled = B_FALSE;
11183048Samaguire 
11193048Samaguire 	/* Persistently disable each old v4/v6 "routing-svc" */
11203048Samaguire 	for (fmri = strtok(routing_svcs_old, " \t"); fmri != NULL;
11213048Samaguire 	    fmri = strtok(NULL, " \t")) {
11223048Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1) {
11233048Samaguire 			free(routing_svcs_old);
11243048Samaguire 			return (-1);
11253048Samaguire 		}
11263048Samaguire 		if (v4_old &&
11273048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1) {
11283048Samaguire 			free(routing_svcs_old);
11293048Samaguire 			return (-1);
11303048Samaguire 		}
11313048Samaguire 		if (v6_old &&
11323048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1) {
11333048Samaguire 			free(routing_svcs_old);
11343048Samaguire 			return (-1);
11353048Samaguire 		}
11363048Samaguire 	}
11373048Samaguire 	free(routing_svcs_old);
11383048Samaguire 	v4opt->opt_enabled = v4_old;
11393048Samaguire 	v6opt->opt_enabled = v6_old;
11403048Samaguire 
11413048Samaguire 	/* Persistently enable each new v4/v6 "routing-svc" */
11423048Samaguire 	mark = B_TRUE;
11433048Samaguire 	for (fmri = strtok(routing_svcs_new, " \t"); fmri != NULL;
11443048Samaguire 	    fmri = strtok(NULL, " \t")) {
11453048Samaguire 		if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1)
11463048Samaguire 			return (-1);
11473048Samaguire 		if (v4_old &&
11483048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1)
11493048Samaguire 			return (-1);
11503048Samaguire 		if (v6_old &&
11513048Samaguire 		    ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1)
11523048Samaguire 			return (-1);
11533048Samaguire 	}
11543048Samaguire 	return (0);
11553048Samaguire }
11563048Samaguire 
11573048Samaguire /*
11583048Samaguire  * Display status,  in parseable form if required.  If param is
11593048Samaguire  * specified,  only the named option/variable is displayed  (this option is
11603048Samaguire  * for parseable display only).
11613048Samaguire  */
11623048Samaguire static int
ra_report(boolean_t parseable,const char * param)11633048Samaguire ra_report(boolean_t parseable, const char *param)
11643048Samaguire {
11653048Samaguire 	int		i;
11663048Samaguire 	char		*c_state, *d_state, *p_state, *p_var, *d_var;
11673048Samaguire 	char		*enabled = "enabled";
11683048Samaguire 	char		*disabled = "disabled";
11693048Samaguire 	boolean_t	param_found = B_FALSE;
11703048Samaguire 
11713048Samaguire 	if (!parseable) {
11723048Samaguire 		(void) printf(gettext(
11733048Samaguire 		    "              Configuration   Current              "
11743048Samaguire 		    "Current\n"
11753048Samaguire 		    "                     Option   Configuration        "
11763048Samaguire 		    "System State\n"
11773048Samaguire 		    "---------------------------------------------------"
11783048Samaguire 		    "------------\n"));
11793048Samaguire 	}
11803048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
11813048Samaguire 		if (param != NULL) {
11823048Samaguire 			if (strcmp(ra_opts[i].opt_name, param) == 0)
11833048Samaguire 				param_found = B_TRUE;
11843048Samaguire 			else
11853048Samaguire 				continue;
11863048Samaguire 		}
11873048Samaguire 		if (ra_smf_cb(ra_get_current_opt_cb,
11883048Samaguire 		    ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
11893048Samaguire 			return (-1);
11903048Samaguire 		c_state = ra_opts[i].opt_enabled ? enabled : disabled;
11913048Samaguire 		ra_resetopts();
11923048Samaguire 		if (ra_smf_cb(ra_get_persistent_opt_cb,
11933048Samaguire 		    ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
11943048Samaguire 			return (-1);
11953048Samaguire 		p_state = ra_opts[i].opt_enabled ? enabled : disabled;
11963048Samaguire 		ra_resetopts();
11973048Samaguire 		if (ra_smf_cb(ra_get_default_opt_cb,
11983048Samaguire 		    ra_opts[i].opt_default_fmri, &ra_opts[i]) == -1)
11993048Samaguire 			return (-1);
12003048Samaguire 		d_state = ra_opts[i].opt_default_enabled ? enabled : disabled;
12013048Samaguire 		ra_resetopts();
12023048Samaguire 		if (parseable) {
12033048Samaguire 			if (param == NULL)
12043048Samaguire 				(void) printf("%s ", ra_opts[i].opt_name);
12053048Samaguire 			(void) printf("persistent=%s default=%s "
12063048Samaguire 			    "current=%s\n", p_state, d_state, c_state);
12073048Samaguire 		} else {
12083048Samaguire 			(void) printf(gettext("%1$27s   %2$-21s%3$s\n"),
12093048Samaguire 			    ra_intloptname(ra_opts[i].opt_name),
12103048Samaguire 			    p_state, c_state);
12113048Samaguire 		}
12123048Samaguire 	}
12133048Samaguire 	if (!parseable)
12143048Samaguire 		(void) printf("\n");
12153048Samaguire 
12163048Samaguire 	ra_resetvars(NULL);
12173048Samaguire 
12183048Samaguire 	/* Gather persistent/default variable values */
12193048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
12203048Samaguire 		if (ra_smf_cb(ra_get_persistent_var_cb,
12213048Samaguire 		    ra_vars[i].var_fmri, &ra_vars[i]) == -1 ||
12223048Samaguire 		    ra_smf_cb(ra_get_default_var_cb,
12233048Samaguire 		    ra_vars[i].var_default_fmri, &ra_vars[i]) == -1)
12243048Samaguire 			return (-1);
12253048Samaguire 
12263048Samaguire 	}
12273048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
12283048Samaguire 		if (param != NULL) {
12293048Samaguire 			if (strcmp(ra_vars[i].var_name, param) == 0)
12303048Samaguire 				param_found = B_TRUE;
12313048Samaguire 			else
12323048Samaguire 				continue;
12333048Samaguire 		}
12343048Samaguire 		p_var = ra_vars[i].var_value == NULL ? "":
12353048Samaguire 		    ra_vars[i].var_value;
12363048Samaguire 		d_var = ra_vars[i].var_default_value == NULL ?
12373048Samaguire 		    "": ra_vars[i].var_default_value;
12383048Samaguire 		if (parseable) {
12393048Samaguire 			if (param == NULL)
12403048Samaguire 				(void) printf("%s ", ra_vars[i].var_name);
12413048Samaguire 			(void) printf("persistent=\"%s\" "
12423048Samaguire 			    "default=\"%s\" \n", p_var, d_var);
12433048Samaguire 		} else {
12443048Samaguire 			/* If daemon variables are not set, do not display. */
12453048Samaguire 			if ((IS_IPV4_VAR(ra_vars[i].var_name) &&
12463048Samaguire 			    IPV4_VARS_UNSET) ||
12473048Samaguire 			    (IS_IPV6_VAR(ra_vars[i].var_name) &&
12483048Samaguire 			    IPV6_VARS_UNSET))
12493048Samaguire 				continue;
12503048Samaguire 			(void) printf(gettext("%1$27s   \"%2$s\"\n"),
12513048Samaguire 			    ra_intloptname(ra_vars[i].var_name), p_var);
12523048Samaguire 		}
12533048Samaguire 	}
12543048Samaguire 
12553048Samaguire 	if (param != NULL && !param_found) {
12563048Samaguire 		(void) fprintf(stderr, gettext(
12573048Samaguire 		    "%s: no such option/variable %s\n"), myname, param);
12583048Samaguire 		return (-1);
12593048Samaguire 	}
12603048Samaguire 	if (parseable)
12613048Samaguire 		return (0);
12623048Samaguire 	(void) printf(gettext("\nRouting daemons:\n"));
12633048Samaguire 	(void) printf("\n                      %s   %s\n", "STATE", "FMRI");
12643048Samaguire 	if (ra_smf_cb(ra_print_state_cb, NULL, NULL) == -1)
12653048Samaguire 		return (-1);
12663048Samaguire 	return (0);
12673048Samaguire }
12683048Samaguire 
12693048Samaguire /*
12703048Samaguire  * Call scf_walk_fmri() with appropriate function, fmri, and data.
12713048Samaguire  * A NULL fmri causes scf_walk_fmri() to run on all instances.  We make
12723048Samaguire  * use of this many times in applying changes to the routing services.
12733048Samaguire  */
12743048Samaguire static int
ra_smf_cb(ra_smf_cb_t cbfunc,const char * fmri,void * data)12753048Samaguire ra_smf_cb(ra_smf_cb_t cbfunc, const char *fmri, void *data)
12763048Samaguire {
12773048Samaguire 	scf_handle_t	*h;
12783048Samaguire 	int		exit_status = 0;
12793048Samaguire 
12803048Samaguire 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
12813048Samaguire 	    scf_handle_bind(h) == -1) {
12823048Samaguire 		(void) fprintf(stderr, gettext(
12833048Samaguire 		    "%s: cannot connect to SMF repository\n"), myname);
12843048Samaguire 		return (-1);
12853048Samaguire 	}
12863048Samaguire 	return (scf_walk_fmri(h, fmri == NULL ? 0 : 1,
12873048Samaguire 	    fmri == NULL ? NULL : (char **)&fmri, 0,
12883048Samaguire 	    cbfunc, data, &exit_status, uu_die));
12893048Samaguire }
12903048Samaguire 
12913048Samaguire /*
12923048Samaguire  * Applies persistent configuration settings to current setup.
12933048Samaguire  */
12943048Samaguire static int
ra_set_current_opt_cb(void * data,scf_walkinfo_t * wip)12953048Samaguire ra_set_current_opt_cb(void *data, scf_walkinfo_t *wip)
12963048Samaguire {
12973048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_FALSE));
12983048Samaguire }
12993048Samaguire 
13003048Samaguire /*
13013048Samaguire  * Sets persistent value for option,  to be applied on next boot
13023048Samaguire  * or by "routeadm -u".
13033048Samaguire  */
13043048Samaguire static int
ra_set_persistent_opt_cb(void * data,scf_walkinfo_t * wip)13053048Samaguire ra_set_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
13063048Samaguire {
13073048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_FALSE));
13083048Samaguire }
13093048Samaguire 
13103048Samaguire static int
ra_get_current_opt_cb(void * data,scf_walkinfo_t * wip)13113048Samaguire ra_get_current_opt_cb(void *data, scf_walkinfo_t *wip)
13123048Samaguire {
13133048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_TRUE));
13143048Samaguire }
13153048Samaguire 
13163048Samaguire static int
ra_get_persistent_opt_cb(void * data,scf_walkinfo_t * wip)13173048Samaguire ra_get_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
13183048Samaguire {
13193048Samaguire 	return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_TRUE));
13203048Samaguire }
13213048Samaguire 
1322*3294Samaguire static int
ra_routing_opt_set_cb(void * data,scf_walkinfo_t * wip)1323*3294Samaguire ra_routing_opt_set_cb(void *data, scf_walkinfo_t *wip)
1324*3294Samaguire {
1325*3294Samaguire 	return (ra_routing_opt_set_unset_cb(data, wip, B_TRUE));
1326*3294Samaguire }
1327*3294Samaguire 
1328*3294Samaguire static int
ra_routing_opt_unset_cb(void * data,scf_walkinfo_t * wip)1329*3294Samaguire ra_routing_opt_unset_cb(void *data, scf_walkinfo_t *wip)
1330*3294Samaguire {
1331*3294Samaguire 	return (ra_routing_opt_set_unset_cb(data, wip, B_FALSE));
1332*3294Samaguire }
1333*3294Samaguire 
1334*3294Samaguire /*
1335*3294Samaguire  * Notify network/routing-setup service that administrator has explicitly
1336*3294Samaguire  * set/reset ipv4(6)-routing value.  If no explicit setting of this value is
1337*3294Samaguire  * done,  ipv4-routing can be enabled in the situation when no default route can
1338*3294Samaguire  * be determined.
1339*3294Samaguire  */
1340*3294Samaguire static int
ra_routing_opt_set_unset_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t set)1341*3294Samaguire ra_routing_opt_set_unset_cb(raopt_t *raopt, scf_walkinfo_t *wip, boolean_t set)
1342*3294Samaguire {
1343*3294Samaguire 	scf_instance_t	*inst = wip->inst;
1344*3294Samaguire 	scf_handle_t	*h = scf_instance_handle(inst);
1345*3294Samaguire 
1346*3294Samaguire 	return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1347*3294Samaguire 	    raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING ?
1348*3294Samaguire 	    RA_PROP_IPV4_ROUTING_SET : RA_PROP_IPV6_ROUTING_SET,
1349*3294Samaguire 	    B_FALSE, set));
1350*3294Samaguire }
1351*3294Samaguire 
13523048Samaguire /*
13533048Samaguire  * Shared function that either sets or determines persistent or current
13543048Samaguire  * state. Setting persistent state (for next boot) involves setting
13553048Samaguire  * the general_ovr/enabled value to the current service state, and
13563048Samaguire  * the general/enabled value to the desired (next-boot) state.
13573048Samaguire  * Setting current state involves removing the temporary state
13583048Samaguire  * setting so the persistent state has effect.
13593048Samaguire  *
13603048Samaguire  * Persistent state is reported as being enabled if any of the
13613048Samaguire  * candidate services have a general/enabled value set to true,
13623048Samaguire  * while current state is reported as being enabled if any of the
13633048Samaguire  * candidate services has a general_ovr/enabled or general/enabled
13643048Samaguire  * value set to true.
13653048Samaguire  */
13663048Samaguire static int
ra_get_set_opt_common_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t persistent,boolean_t get)13673048Samaguire ra_get_set_opt_common_cb(raopt_t *raopt, scf_walkinfo_t *wip,
13683048Samaguire     boolean_t persistent, boolean_t get)
13693048Samaguire {
13703048Samaguire 	const char		*inst_fmri = wip->fmri;
13713048Samaguire 	scf_instance_t		*inst = wip->inst;
13723048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
13733048Samaguire 	scf_propertygroup_t	*routeadm_pg;
13743048Samaguire 	boolean_t		persistent_state_enabled;
13753048Samaguire 	boolean_t		temporary_state_enabled;
13763048Samaguire 	boolean_t		current_state_enabled;
13773048Samaguire 	boolean_t		curr_svc = B_TRUE;
13783048Samaguire 	boolean_t		found_proto;
13793048Samaguire 	char			**protolist = NULL;
13803048Samaguire 	int			i, ret, numvalues = 0;
13813048Samaguire 
13823048Samaguire 	/*
13833048Samaguire 	 * Ensure we are dealing with a routeadm-managed service.  If
13843048Samaguire 	 * the FMRI used for walking instances is NULL,  it is reasonable
13853048Samaguire 	 * that a service not have a routeadm property group as we will
13863048Samaguire 	 * check all services in this case.
13873048Samaguire 	 */
13883048Samaguire 	if (ra_get_pg(h, inst, RA_PG_ROUTEADM, B_TRUE, raopt->opt_fmri != NULL,
13893048Samaguire 	    &routeadm_pg) == -1) {
13903048Samaguire 			/* Not a routing service, not an error. */
13913048Samaguire 			if (scf_error() == SCF_ERROR_NOT_FOUND &&
13923048Samaguire 			    raopt->opt_fmri == NULL)
13933048Samaguire 				return (0);
13943048Samaguire 			return (-1);
13953048Samaguire 	}
13963048Samaguire 	scf_pg_destroy(routeadm_pg);
13973048Samaguire 
13983048Samaguire 	/* Services with no "protocol" property are not routing daemons */
13993048Samaguire 	if (raopt->opt_fmri == NULL && ra_get_prop_as_string(h, inst,
14003048Samaguire 	    RA_PG_ROUTEADM, RA_PROP_PROTO, B_TRUE, B_FALSE, NULL, &numvalues,
14013048Samaguire 	    &protolist) == -1) {
14023048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14033048Samaguire 			return (0);
14043048Samaguire 		return (-1);
14053048Samaguire 	}
14063048Samaguire 
14073048Samaguire 	/*
14083048Samaguire 	 * Skip invalid services based on flag settings.  Flags are used when
14093048Samaguire 	 * we run callback functions on all instances to identify
14103048Samaguire 	 * the correct instances to operate on.
14113048Samaguire 	 */
14123048Samaguire 	if (raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING) {
14133048Samaguire 		found_proto = B_FALSE;
14143048Samaguire 		if (protolist != NULL) {
14153048Samaguire 			/* Check if protolist contains "ipv4" */
14163048Samaguire 			for (i = 0; i < numvalues; i++) {
14173048Samaguire 				if (protolist[i] != NULL && strcmp(
14183048Samaguire 				    protolist[i], RA_PROPVAL_PROTO_IPV4) == 0)
14193048Samaguire 					found_proto = B_TRUE;
14203048Samaguire 			}
14213048Samaguire 		}
14223048Samaguire 		/* If not an ipv4 routing service, skip. */
14233048Samaguire 		if (protolist == NULL || !found_proto) {
14243048Samaguire 			ra_free_prop_values(numvalues, protolist);
14253048Samaguire 			return (0);
14263048Samaguire 		}
14273048Samaguire 	}
14283048Samaguire 	if (raopt->opt_flags & RA_SVC_FLAG_IPV6_ROUTING) {
14293048Samaguire 		found_proto = B_FALSE;
14303048Samaguire 		if (protolist != NULL) {
14313048Samaguire 			/* Check if protolist contains "ipv6" */
14323048Samaguire 			for (i = 0; i < numvalues; i++) {
14333048Samaguire 				if (protolist[i] != NULL && strcmp(
14343048Samaguire 				    protolist[i], RA_PROPVAL_PROTO_IPV6) == 0)
14353048Samaguire 					found_proto = B_TRUE;
14363048Samaguire 			}
14373048Samaguire 		}
14383048Samaguire 		/* If not an ipv6 routing service, skip. */
14393048Samaguire 		if (protolist == NULL || !found_proto) {
14403048Samaguire 			ra_free_prop_values(numvalues, protolist);
14413048Samaguire 			return (0);
14423048Samaguire 		}
14433094Samaguire 		/*
14443094Samaguire 		 * If no IPv6 interfaces are configured, do not apply
14453094Samaguire 		 * the "enable" state change to this IPv6 routing service.
14463094Samaguire 		 */
14473094Samaguire 		if (raopt->opt_enabled && ra_numv6intfs() < 1)
14483094Samaguire 			return (0);
14493048Samaguire 	}
14503048Samaguire 	ra_free_prop_values(numvalues, protolist);
14513048Samaguire 
14523048Samaguire 	/* If enabling routing services, select only current routing services */
14533048Samaguire 	if (raopt->opt_fmri == NULL && !get && raopt->opt_enabled) {
14543048Samaguire 		if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
14553048Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE,
14563048Samaguire 		    &curr_svc) == -1)
14573048Samaguire 			return (0);
14583048Samaguire 		else if (!curr_svc && persistent) {
14593048Samaguire 			/*
14603048Samaguire 			 * We apply "current" routing changes to all routing
14613048Samaguire 			 * daemons, whether current or not, so bail if
14623048Samaguire 			 * we are trying to make a persistent update to a
14633048Samaguire 			 * non-"routing-svc".
14643048Samaguire 			 */
14653048Samaguire 			return (0);
14663048Samaguire 		}
14673048Samaguire 	}
14683048Samaguire 	if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
14693048Samaguire 	    B_FALSE, B_TRUE, &persistent_state_enabled) == -1)
14703048Samaguire 		return (-1);
14713048Samaguire 
14723048Samaguire 	current_state_enabled = persistent_state_enabled;
14733048Samaguire 
14743048Samaguire 	if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL_OVR,
14753048Samaguire 	    SCF_PROPERTY_ENABLED, B_FALSE, B_FALSE, &temporary_state_enabled)
14763048Samaguire 	    == 0)
14773048Samaguire 		current_state_enabled = temporary_state_enabled;
14783048Samaguire 
14793048Samaguire 	if (get) {
14803048Samaguire 		/*
14813048Samaguire 		 * Persistent state is enabled if any services are
14823048Samaguire 		 * persistently enabled, i.e. general/enabled == true).
14833048Samaguire 		 * current state is enabled if any services
14843048Samaguire 		 * services are currently enabled, i.e. if defined,
14853048Samaguire 		 * general_ovr/enabled == true, if not, general/enabled == true.
14863048Samaguire 		 */
14873048Samaguire 		if (persistent)
14883048Samaguire 			raopt->opt_enabled = raopt->opt_enabled ||
14893048Samaguire 			    persistent_state_enabled;
14903048Samaguire 		else
14913048Samaguire 			raopt->opt_enabled = raopt->opt_enabled ||
14923048Samaguire 			    current_state_enabled;
14933048Samaguire 	} else {
14943048Samaguire 		if (persistent) {
14953048Samaguire 			/*
14963048Samaguire 			 * For peristent state changes, from -e/-d,
14973048Samaguire 			 * we set the general_ovr/enabled value to the
14983048Samaguire 			 * current state (to ensure it is preserved),
14993048Samaguire 			 * while setting the general/enabled value to
15003048Samaguire 			 * the desired value.  This has the effect of
15013048Samaguire 			 * the desired value coming into effect on next boot.
15023048Samaguire 			 */
15033048Samaguire 			ret = current_state_enabled ?
15043048Samaguire 			    smf_enable_instance(inst_fmri, SMF_TEMPORARY) :
15053048Samaguire 			    smf_disable_instance(inst_fmri, SMF_TEMPORARY);
15063048Samaguire 			if (ret != 0) {
15073048Samaguire 				(void) fprintf(stderr, gettext(
15083048Samaguire 				    "%s: unexpected libscf error: %s\n"),
15093048Samaguire 				    myname, scf_strerror(scf_error()));
15103048Samaguire 				return (-1);
15113048Samaguire 			}
15123048Samaguire 			/*
15133048Samaguire 			 * Refresh here so general_ovr/enabled state overrides
15143048Samaguire 			 * general/enabled state.
15153048Samaguire 			 */
15163048Samaguire 			(void) smf_refresh_instance(inst_fmri);
15173048Samaguire 			/*
15183048Samaguire 			 * Now we can safely set the general/enabled value
15193048Samaguire 			 * to the value we require on next boot (or
15203048Samaguire 			 * "routeadm -u").
15213048Samaguire 			 */
15223048Samaguire 			ret = ra_set_boolean_prop(h, inst, SCF_PG_GENERAL,
15233048Samaguire 			    SCF_PROPERTY_ENABLED, B_FALSE, raopt->opt_enabled);
15243048Samaguire 			if (ret != 0)
15253048Samaguire 				return (-1);
15263048Samaguire 			/*
15273048Samaguire 			 * Refresh here so general/enabled value is set.
15283048Samaguire 			 */
15293048Samaguire 			(void) smf_refresh_instance(inst_fmri);
15303048Samaguire 			if (raopt->opt_fmri != NULL)
15313048Samaguire 				return (0);
15323048Samaguire 			(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
15333048Samaguire 		} else {
15343048Samaguire 			/*
15353157Samaguire 			 * Refresh here to get latest property values prior
15363157Samaguire 			 * to starting daemon.
15373157Samaguire 			 */
15383157Samaguire 			(void) smf_refresh_instance(inst_fmri);
15393157Samaguire 			/*
15403048Samaguire 			 * For current changes (result of -u), we
15413048Samaguire 			 * enable/disable depending on persistent value
15423048Samaguire 			 * stored in general/enabled.  Here we disable
15433048Samaguire 			 * old routing-svcs (identified by a current-routing-svc
15443048Samaguire 			 * value of false) also.
15453048Samaguire 			 */
15463048Samaguire 			ret = persistent_state_enabled && curr_svc ?
15473048Samaguire 			    smf_enable_instance(inst_fmri, 0) :
15483048Samaguire 			    smf_disable_instance(inst_fmri, 0);
15493048Samaguire 			if (ret != 0) {
15503048Samaguire 				(void) fprintf(stderr, gettext(
15513048Samaguire 				    "%s: unexpected libscf error: %s\n"),
15523048Samaguire 				    myname, scf_strerror(scf_error()));
15533048Samaguire 				return (-1);
15543048Samaguire 			}
15553157Samaguire 			if (current_state_enabled && persistent_state_enabled) {
15563157Samaguire 				/*
15573157Samaguire 				 * Instance was already enabled, so we restart
15583157Samaguire 				 * to get latest property values.  This covers
15593157Samaguire 				 * the case where users update properties
15603157Samaguire 				 * via routeadm -m, and issue an update.  The
15613157Samaguire 				 * daemon should be running with the latest
15623157Samaguire 				 * property values.
15633157Samaguire 				 */
15643157Samaguire 				(void) smf_restart_instance(inst_fmri);
15653157Samaguire 			}
15663048Samaguire 		}
15673048Samaguire 	}
15683048Samaguire 	return (0);
15693048Samaguire }
15703048Samaguire 
15713048Samaguire static int
ra_set_default_opt_cb(void * data,scf_walkinfo_t * wip)15723048Samaguire ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip)
15733048Samaguire {
15743048Samaguire 	scf_instance_t		*inst = wip->inst;
15753048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
15763048Samaguire 	raopt_t			*raopt = data;
15773048Samaguire 
15783048Samaguire 	return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
15793048Samaguire 	    raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled));
15803048Samaguire }
15813048Samaguire 
15823048Samaguire static int
ra_get_default_opt_cb(void * data,scf_walkinfo_t * wip)15833048Samaguire ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip)
15843048Samaguire {
15853048Samaguire 	scf_instance_t		*inst = wip->inst;
15863048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
15873048Samaguire 	raopt_t			*raopt = data;
15883048Samaguire 
15893048Samaguire 	return (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
15903048Samaguire 	    raopt->opt_default_prop, B_TRUE, B_TRUE,
15913048Samaguire 	    &(raopt->opt_default_enabled)));
15923048Samaguire }
15933048Samaguire 
15943048Samaguire /*
15953048Samaguire  * Callbacks to set/retrieve persistent/default routing variable values.
15963048Samaguire  * The set functions use the value stored in the var_value/var_default_value
15973048Samaguire  * field of the associated ra_var_t, while the retrieval functions store
15983048Samaguire  * the value retrieved in that field.
15993048Samaguire  */
16003048Samaguire static int
ra_get_persistent_var_cb(void * data,scf_walkinfo_t * wip)16013048Samaguire ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip)
16023048Samaguire {
16033048Samaguire 	scf_instance_t		*inst = wip->inst;
16043048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
16053048Samaguire 	ravar_t			*ravar = data;
16063048Samaguire 
16073048Samaguire 	return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
16083048Samaguire 	    ravar->var_prop, B_TRUE, B_TRUE, NULL, &ravar->var_value));
16093048Samaguire }
16103048Samaguire 
16113048Samaguire static int
ra_set_persistent_var_cb(void * data,scf_walkinfo_t * wip)16123048Samaguire ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip)
16133048Samaguire {
16143048Samaguire 	scf_instance_t		*inst = wip->inst;
16153048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
16163048Samaguire 	ravar_t			*ravar = data;
16173048Samaguire 
16183048Samaguire 	return (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
16193048Samaguire 	    ravar->var_prop, SCF_TYPE_INVALID, B_FALSE, 1,
16203048Samaguire 	    (const char **)&ravar->var_value));
16213048Samaguire }
16223048Samaguire 
16233048Samaguire static int
ra_get_default_var_cb(void * data,scf_walkinfo_t * wip)16243048Samaguire ra_get_default_var_cb(void *data, scf_walkinfo_t *wip)
16253048Samaguire {
16263048Samaguire 	scf_instance_t		*inst = wip->inst;
16273048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
16283048Samaguire 	ravar_t			*ravar = data;
16293048Samaguire 
16303048Samaguire 	return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
16313048Samaguire 	    ravar->var_default_prop, B_TRUE, B_TRUE, NULL,
16323048Samaguire 	    &ravar->var_default_value));
16333048Samaguire }
16343048Samaguire 
16353048Samaguire /*
16363048Samaguire  * Depending on the value of the boolean_t * passed in,  this callback
16373048Samaguire  * either marks the relevant service(s) as current-routing-svcs (or unmarking)
16383048Samaguire  * by setting that property to true or false.  When routing services
16393048Samaguire  * are to be enabled,  the a current-routing-svc value of true flags the
16403048Samaguire  * service as one to be enabled.
16413048Samaguire  */
16423048Samaguire static int
ra_mark_routing_svcs_cb(void * data,scf_walkinfo_t * wip)16433048Samaguire ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip)
16443048Samaguire {
16453048Samaguire 	scf_instance_t		*inst = wip->inst;
16463048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
16473048Samaguire 	boolean_t		*mark = data;
16483048Samaguire 	boolean_t		marked;
16493048Samaguire 	int			numvalues = 0;
16503048Samaguire 	char			**protolist = NULL;
16513048Samaguire 
16523048Samaguire 	/* Check we are dealing with a routing daemon service */
16533048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
16543048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
16553048Samaguire 		return (0);
16563048Samaguire 	ra_free_prop_values(numvalues, protolist);
16573048Samaguire 	if (*mark)
16583048Samaguire 		return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
16593048Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_TRUE));
16603048Samaguire 	/* Unmark service. */
16613048Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
16623048Samaguire 	    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE, &marked) == 0 && marked)
16633048Samaguire 		return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
16643048Samaguire 		    RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE));
16653048Samaguire 	return (0);
16663048Samaguire }
16673048Samaguire 
16683048Samaguire /*
16693048Samaguire  * List property values for all properties in the "routing" property
16703048Samaguire  * group of the routing service instance.
16713048Samaguire  */
16723048Samaguire 
16733048Samaguire /* ARGSUSED0 */
16743048Samaguire static int
ra_list_props_cb(void * data,scf_walkinfo_t * wip)16753048Samaguire ra_list_props_cb(void *data, scf_walkinfo_t *wip)
16763048Samaguire {
16773048Samaguire 	const char		*inst_fmri = wip->fmri;
16783048Samaguire 	scf_instance_t		*inst = wip->inst;
16793048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
16803048Samaguire 	scf_iter_t		*propiter, *valiter;
16813048Samaguire 	scf_propertygroup_t	*pg;
16823048Samaguire 	scf_property_t		*prop;
16833048Samaguire 	scf_value_t		*val;
16843048Samaguire 	char			**protolist = NULL, *pnamebuf, *valbuf;
16853048Samaguire 	ssize_t			pnamelen, vallen;
16863048Samaguire 	int			numvalues = 0;
16873048Samaguire 	int			propiterret, valiterret, retval = 0;
16883048Samaguire 
16893048Samaguire 	/* Services with no "protocol" property are not routing daemons */
16903048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
16913048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
16923048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
16933048Samaguire 			(void) fprintf(stderr,
16943048Samaguire 			    gettext("%s: %s is not a routing daemon service\n"),
16953048Samaguire 			    myname, inst_fmri);
16963048Samaguire 		else
16973048Samaguire 			(void) fprintf(stderr,
16983048Samaguire 			    gettext("%s: unexpected libscf error: %s\n"),
16993048Samaguire 			    myname, scf_strerror(scf_error()));
17003048Samaguire 		ra_free_prop_values(numvalues, protolist);
17013048Samaguire 		return (-1);
17023048Samaguire 	}
17033048Samaguire 	ra_free_prop_values(numvalues, protolist);
17043048Samaguire 
17053048Samaguire 	if (ra_get_pg(h, inst, RA_PG_ROUTING, B_TRUE, B_FALSE, &pg) == -1) {
17063048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
17073048Samaguire 			(void) printf("%s: no %s property group for %s\n",
17083048Samaguire 			    myname, RA_PG_ROUTING, inst_fmri);
17093048Samaguire 			return (0);
17103048Samaguire 		}
17113048Samaguire 		(void) fprintf(stderr,
17123048Samaguire 		    gettext("%s: unexpected libscf error: %s\n"),
17133048Samaguire 		    myname, scf_strerror(scf_error()));
17143048Samaguire 		return (-1);
17153048Samaguire 	}
17163048Samaguire 
17173048Samaguire 	(void) printf("%s:\n", inst_fmri);
17183048Samaguire 
17193048Samaguire 	/* Create an iterator to walk through all properties */
17203048Samaguire 	if ((propiter = scf_iter_create(h)) == NULL ||
17213048Samaguire 	    (prop = scf_property_create(h)) == NULL ||
17223048Samaguire 	    scf_iter_pg_properties(propiter, pg) != 0) {
17233048Samaguire 		(void) fprintf(stderr, gettext
17243048Samaguire 		    ("%s: could not iterate through properties for %s: %s\n"),
17253048Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
17263048Samaguire 	}
17273048Samaguire 	while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) {
17283048Samaguire 		if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1)
17293048Samaguire 		    == 0) {
17303048Samaguire 			(void) fprintf(stderr, gettext("%s: could not retrieve "
17313048Samaguire 			    "property name for instance %s: %s\n"), myname,
17323048Samaguire 			    inst_fmri, scf_strerror(scf_error()));
17333048Samaguire 			retval = -1;
17343048Samaguire 			break;
17353048Samaguire 		}
17363048Samaguire 		if ((pnamebuf = malloc(pnamelen)) == NULL) {
17373048Samaguire 			(void) fprintf(stderr,
17383048Samaguire 			    gettext("%s: out of memory\n"), myname);
17393048Samaguire 			retval = -1;
17403048Samaguire 			break;
17413048Samaguire 		}
17423048Samaguire 		(void) scf_property_get_name(prop, pnamebuf,
17433048Samaguire 		    pnamelen);
17443048Samaguire 		(void) printf("\t%s = ", pnamebuf);
17453048Samaguire 		if ((valiter = scf_iter_create(h)) == NULL ||
17463048Samaguire 		    (val = scf_value_create(h)) == NULL ||
17473048Samaguire 		    scf_iter_property_values(valiter, prop)
17483048Samaguire 		    != 0) {
17493048Samaguire 			(void) fprintf(stderr, gettext
17503048Samaguire 			    ("%s: could not iterate through "
17513048Samaguire 			    "properties for %s: %s\n"), myname, inst_fmri,
17523048Samaguire 			    scf_strerror(scf_error()));
17533048Samaguire 			scf_value_destroy(val);
17543048Samaguire 			scf_iter_destroy(valiter);
17553048Samaguire 			free(pnamebuf);
17563048Samaguire 			retval = -1;
17573048Samaguire 			break;
17583048Samaguire 		}
17593048Samaguire 		while ((valiterret = scf_iter_next_value(valiter, val)) == 1) {
17603048Samaguire 			if ((vallen = scf_value_get_as_string
17613048Samaguire 			    (val, NULL, 0) + 1) == 0) {
17623048Samaguire 				(void) fprintf(stderr, gettext
17633048Samaguire 				    ("%s: could not retrieve "
17643048Samaguire 				    "property value for instance %s, "
17653048Samaguire 				    "property %s: %s\n"), myname, inst_fmri,
17663048Samaguire 				    pnamebuf, scf_strerror(scf_error()));
17673048Samaguire 				retval = -1;
17683048Samaguire 			} else if ((valbuf = malloc(vallen)) == NULL) {
17693048Samaguire 				(void) fprintf(stderr,
17703048Samaguire 				    gettext("%s: out of memory\n"), myname);
17713048Samaguire 				retval = -1;
17723048Samaguire 			}
17733048Samaguire 			if (retval == -1) {
17743048Samaguire 				scf_iter_destroy(valiter);
17753048Samaguire 				scf_value_destroy(val);
17763048Samaguire 				free(pnamebuf);
17773048Samaguire 				goto out;
17783048Samaguire 			}
17793048Samaguire 			(void) scf_value_get_as_string(val, valbuf, vallen);
17803048Samaguire 			(void) printf("%s ", valbuf);
17813048Samaguire 			free(valbuf);
17823048Samaguire 		}
17833048Samaguire 		(void) printf("\n");
17843048Samaguire 		scf_iter_destroy(valiter);
17853048Samaguire 		scf_value_destroy(val);
17863048Samaguire 		free(pnamebuf);
17873048Samaguire 		if (valiterret == -1) {
17883048Samaguire 			(void) fprintf(stderr,
17893048Samaguire 			    gettext("%s: could not iterate through"
17903048Samaguire 			    "properties for %s: %s\n"), myname, inst_fmri,
17913048Samaguire 			    scf_strerror(scf_error()));
17923048Samaguire 			retval = -1;
17933048Samaguire 			break;
17943048Samaguire 		}
17953048Samaguire 	}
17963048Samaguire out:
17973048Samaguire 	scf_iter_destroy(propiter);
17983048Samaguire 	scf_property_destroy(prop);
17993048Samaguire 	scf_pg_destroy(pg);
18003048Samaguire 	if (propiterret == -1)
18013048Samaguire 		(void) fprintf(stderr, gettext
18023048Samaguire 		    ("%s: could not iterate through properties for %s: %s\n"),
18033048Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
18043048Samaguire 	return (retval);
18053048Samaguire }
18063048Samaguire 
18073048Samaguire /*
18083048Samaguire  * Modify property with name stored in passed-in ra_prop_t to have
18093048Samaguire  * the assocatied values.  Only works for existing properties in
18103048Samaguire  * the "routing" property group for routing daemon services,  so all
18113048Samaguire  * routing daemons should place configurable options in that group.
18123048Samaguire  */
18133048Samaguire static int
ra_modify_props_cb(void * data,scf_walkinfo_t * wip)18143048Samaguire ra_modify_props_cb(void *data, scf_walkinfo_t *wip)
18153048Samaguire {
18163048Samaguire 	const char		*inst_fmri = wip->fmri;
18173048Samaguire 	scf_instance_t		*inst = wip->inst;
18183048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
18193048Samaguire 	ra_prop_t		*raprop = data;
18203048Samaguire 	int			numvalues = 0;
18213048Samaguire 	char			**protolist = NULL;
18223048Samaguire 
18233048Samaguire 	/* Services with no "protocol" property are not routing daemons */
18243048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
18253048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
18263048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
18273048Samaguire 			(void) fprintf(stderr,
18283048Samaguire 			    gettext("%s: %s is not a routing daemon service\n"),
18293048Samaguire 			    myname, inst_fmri);
18303048Samaguire 		else
18313048Samaguire 			(void) fprintf(stderr,
18323048Samaguire 			    gettext("%s: unexpected libscf error: %s\n"),
18333048Samaguire 			    myname, scf_strerror(scf_error()));
18343048Samaguire 		ra_free_prop_values(numvalues, protolist);
18353048Samaguire 		return (-1);
18363048Samaguire 	}
18373048Samaguire 	ra_free_prop_values(numvalues, protolist);
18383048Samaguire 
18393048Samaguire 	if (ra_set_prop_from_string(h, inst, RA_PG_ROUTING, raprop->prop_name,
18403048Samaguire 	    SCF_TYPE_INVALID, B_FALSE, raprop->prop_numvalues,
18413048Samaguire 	    (const char **)raprop->prop_values) == -1)
18423048Samaguire 		return (-1);
18433048Samaguire 
18443048Samaguire 	(void) smf_refresh_instance(inst_fmri);
18453048Samaguire 	return (0);
18463048Samaguire }
18473048Samaguire 
18483048Samaguire /*
18493048Samaguire  * Display FMRI, state for each routing daemon service.
18503048Samaguire  */
18513048Samaguire 
18523048Samaguire /* ARGSUSED0 */
18533048Samaguire static int
ra_print_state_cb(void * data,scf_walkinfo_t * wip)18543048Samaguire ra_print_state_cb(void *data, scf_walkinfo_t *wip)
18553048Samaguire {
18563048Samaguire 	const char		*inst_fmri = wip->fmri;
18573048Samaguire 	scf_instance_t		*inst = wip->inst;
18583048Samaguire 	scf_handle_t		*h = scf_instance_handle(inst);
18593048Samaguire 	char			*inst_state, **protolist = NULL;
18603048Samaguire 	int			numvalues = 0;
18613048Samaguire 
18623048Samaguire 	/* Ensure service is a routing daemon */
18633048Samaguire 	if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
18643048Samaguire 	    B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
18653048Samaguire 		return (0);
18663048Samaguire 	ra_free_prop_values(numvalues, protolist);
18673048Samaguire 
18683048Samaguire 	if ((inst_state = smf_get_state(inst_fmri)) == NULL) {
18693048Samaguire 		(void) fprintf(stderr,
18703048Samaguire 		    gettext("%s: could not retrieve state for %s: %s\n"),
18713048Samaguire 		    myname, inst_fmri, scf_strerror(scf_error()));
18723048Samaguire 		return (-1);
18733048Samaguire 	}
18743048Samaguire 	(void) printf("%27s   %2s\n", inst_state, inst_fmri);
18753048Samaguire 	free(inst_state);
18763048Samaguire 
18773048Samaguire 	return (0);
18783048Samaguire }
18793048Samaguire 
18803048Samaguire static int
ra_get_pg(scf_handle_t * h,scf_instance_t * inst,const char * pgname,boolean_t composed,boolean_t required,scf_propertygroup_t ** pg)18813048Samaguire ra_get_pg(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
18823048Samaguire     boolean_t composed, boolean_t required, scf_propertygroup_t **pg)
18833048Samaguire {
18843048Samaguire 	/* Retrieve (possibly composed) property group for instance */
18853048Samaguire 	if ((*pg = scf_pg_create(h)) == NULL || (composed &&
18863048Samaguire 	    scf_instance_get_pg_composed(inst, NULL, pgname, *pg) != 0) ||
18873048Samaguire 	    (!composed && scf_instance_get_pg(inst, pgname, *pg) != 0)) {
18883048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
18893048Samaguire 			if (required)
18903048Samaguire 				(void) fprintf(stderr, gettext(
18913048Samaguire 				    "%s: no such property group %s\n"),
18923048Samaguire 				    myname, pgname);
18933048Samaguire 			return (-1);
18943048Samaguire 		}
18953048Samaguire 		if (required)
18963048Samaguire 			(void) fprintf(stderr, gettext(
18973048Samaguire 			    "%s: unexpected libscf error: %s\n"), myname,
18983048Samaguire 			    scf_strerror(scf_error()));
18993048Samaguire 		return (-1);
19003048Samaguire 	}
19013048Samaguire 	return (0);
19023048Samaguire }
19033048Samaguire 
19043048Samaguire static int
ra_get_boolean_prop(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,boolean_t * val)19053048Samaguire ra_get_boolean_prop(scf_handle_t *h, scf_instance_t *inst,
19063048Samaguire     const char *pgname, const char *propname, boolean_t composed,
19073048Samaguire     boolean_t required, boolean_t *val)
19083048Samaguire {
19093048Samaguire 	char	*valstr;
19103048Samaguire 
19113048Samaguire 	if (ra_get_single_prop_as_string(h, inst, pgname, propname,
19123048Samaguire 	    composed, required, NULL, &valstr) != 0)
19133048Samaguire 		return (-1);
19143048Samaguire 	*val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0;
19153048Samaguire 	free(valstr);
19163048Samaguire 	return (0);
19173048Samaguire }
19183048Samaguire 
19193048Samaguire static int
ra_get_single_prop_as_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,scf_type_t * type,char ** value)19203048Samaguire ra_get_single_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
19213048Samaguire     const char *pgname, const char *propname, boolean_t composed,
19223048Samaguire     boolean_t required, scf_type_t *type, char **value)
19233048Samaguire {
19243048Samaguire 	char	**values;
19253048Samaguire 	int	numvalues = 1;
19263048Samaguire 
19273048Samaguire 	if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required,
19283048Samaguire 	    type, &numvalues, &values) == -1)
19293048Samaguire 		return (-1);
19303048Samaguire 	*value = values[0];
19313048Samaguire 	free(values);
19323048Samaguire 	return (0);
19333048Samaguire }
19343048Samaguire 
19353048Samaguire /*
19363048Samaguire  * Retrieve property named in propname,  possibly using the composed
19373048Samaguire  * property group view (union of instance and service-level properties,
19383048Samaguire  * where instance-level properties override service-level values).
19393048Samaguire  */
19403048Samaguire static int
ra_get_prop_as_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,scf_type_t * type,int * numvalues,char *** values)19413048Samaguire ra_get_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
19423048Samaguire     const char *pgname, const char *propname, boolean_t composed,
19433048Samaguire     boolean_t required, scf_type_t *type, int *numvalues, char ***values)
19443048Samaguire {
19453048Samaguire 	scf_propertygroup_t	*pg = NULL;
19463048Samaguire 	scf_property_t		*prop = NULL;
19473048Samaguire 	scf_iter_t		*valiter = NULL;
19483048Samaguire 	scf_value_t		*val = NULL;
19493048Samaguire 	ssize_t			vallen = 0;
19503048Samaguire 	int			valiterret, i, numvalues_retrieved, ret = 0;
19513048Samaguire 
19523048Samaguire 	if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1)
19533048Samaguire 		return (-1);
19543048Samaguire 
19553048Samaguire 	*values = NULL;
19563048Samaguire 	/*
19573048Samaguire 	 * Retrieve values. All values routeadm needs to retrieve
19583048Samaguire 	 * (bar those gathered by routeadm -l), are known to be single-valued.
19593048Samaguire 	 */
19603048Samaguire 	if ((prop = scf_property_create(h)) == NULL)
19613048Samaguire 		goto error;
19623048Samaguire 	if (scf_pg_get_property(pg, propname, prop) != 0) {
19633048Samaguire 		*numvalues = 0;
19643048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
19653048Samaguire 			if (required)
19663048Samaguire 				(void) fprintf(stderr, gettext(
19673048Samaguire 				    "%s: property %s/%s not found\n"),
19683048Samaguire 				    myname, pgname, propname);
19693048Samaguire 			ret = -1;
19703048Samaguire 			goto out;
19713048Samaguire 		}
19723048Samaguire 		goto error;
19733048Samaguire 	}
19743048Samaguire 	if ((val = scf_value_create(h)) == NULL &&
19753048Samaguire 	    scf_property_get_value(prop, val) != 0 ||
19763048Samaguire 	    (valiter = scf_iter_create(h)) == NULL ||
19773048Samaguire 	    scf_iter_property_values(valiter, prop) != 0)
19783048Samaguire 		goto error;
19793048Samaguire 	/* retrieve each value */
19803048Samaguire 	for (numvalues_retrieved = 0;
19813048Samaguire 	    (valiterret = scf_iter_next_value(valiter, val)) == 1;
19823048Samaguire 	    numvalues_retrieved++) {
19833048Samaguire 		if ((vallen = scf_value_get_as_string
19843048Samaguire 		    (val, NULL, 0) + 1) == 0)
19853048Samaguire 			goto error;
19863048Samaguire 		if ((*values = realloc(*values,
19873048Samaguire 		    sizeof (*values) + sizeof (char *))) == NULL ||
19883048Samaguire 		    ((*values)[numvalues_retrieved] = malloc(vallen)) == NULL) {
19893048Samaguire 			(void) fprintf(stderr, gettext(
19903048Samaguire 			    "%s: out of memory\n"), myname);
19913048Samaguire 			ret = -1;
19923048Samaguire 			goto out;
19933048Samaguire 		}
19943048Samaguire 		(void) scf_value_get_as_string(val,
19953048Samaguire 		    (*values)[numvalues_retrieved], vallen);
19963048Samaguire 	}
19973048Samaguire 	if (valiterret == -1)
19983048Samaguire 		goto error;
19993048Samaguire 	/*
20003048Samaguire 	 * if *numvalues != 0, it holds expected number of values.  If a
20013048Samaguire 	 * different number are found, it is an error.
20023048Samaguire 	 */
20033048Samaguire 	if (*numvalues != 0 && *numvalues != numvalues_retrieved) {
20043048Samaguire 		(void) fprintf(stderr, gettext(
20053048Samaguire 		    "%s: got %d values for property %s/%s, expected %d\n"),
20063048Samaguire 		    myname, numvalues_retrieved, pgname, propname, *numvalues);
20073048Samaguire 		ret = -1;
20083048Samaguire 		goto out;
20093048Samaguire 	}
20103048Samaguire 	*numvalues = numvalues_retrieved;
20113048Samaguire 
20123048Samaguire 	/* Retrieve property type if required. */
20133048Samaguire 	if (type != NULL)
20143048Samaguire 		(void) scf_property_type(prop, type);
20153048Samaguire 
20163048Samaguire 	goto out;
20173048Samaguire error:
20183048Samaguire 	if (scf_error() == SCF_ERROR_NOT_FOUND) {
20193048Samaguire 		(void) fprintf(stderr, gettext(
20203048Samaguire 		    "%s: property %s not found"), myname, propname);
20213048Samaguire 	} else {
20223048Samaguire 		(void) fprintf(stderr, gettext(
20233048Samaguire 		    "%s: unexpected libscf error: %s, "), myname);
20243048Samaguire 	}
20253048Samaguire 	for (i = 0; i < numvalues_retrieved; i++)
20263048Samaguire 		free((*values)[i]);
20273048Samaguire 	if (*values != NULL)
20283048Samaguire 		free(*values);
20293048Samaguire 
20303048Samaguire 	ret = -1;
20313048Samaguire out:
20323048Samaguire 	if (val != NULL)
20333048Samaguire 		scf_value_destroy(val);
20343048Samaguire 	if (valiter != NULL)
20353048Samaguire 		scf_iter_destroy(valiter);
20363048Samaguire 	if (prop != NULL)
20373048Samaguire 		scf_property_destroy(prop);
20383048Samaguire 	if (pg != NULL)
20393048Samaguire 		scf_pg_destroy(pg);
20403048Samaguire 	return (ret);
20413048Samaguire }
20423048Samaguire 
20433048Samaguire static void
ra_free_prop_values(int numvalues,char ** values)20443048Samaguire ra_free_prop_values(int numvalues, char **values)
20453048Samaguire {
20463048Samaguire 	int	i;
20473048Samaguire 	if (values != NULL) {
20483048Samaguire 		for (i = 0; i < numvalues; i++)
20493048Samaguire 			free(values[i]);
20503048Samaguire 		free(values);
20513048Samaguire 	}
20523048Samaguire }
20533048Samaguire 
20543048Samaguire static int
ra_set_boolean_prop(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * prop,boolean_t create,boolean_t propval)20553048Samaguire ra_set_boolean_prop(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
20563048Samaguire     const char *prop, boolean_t create, boolean_t propval)
20573048Samaguire {
20583048Samaguire 	const char	*val = propval ? RA_PROPVAL_BOOLEAN_TRUE :
20593048Samaguire 	    RA_PROPVAL_BOOLEAN_FALSE;
20603048Samaguire 
20613048Samaguire 	return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN,
20623048Samaguire 	    create, 1, &val));
20633048Samaguire }
20643048Samaguire 
20653048Samaguire /*
20663048Samaguire  * Set the property named in propname to the values passed in in the propvals
20673048Samaguire  * array.  Only create a new property if "create" is true.
20683048Samaguire  */
20693048Samaguire static int
ra_set_prop_from_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,scf_type_t proptype,boolean_t create,int numpropvals,const char ** propvals)20703048Samaguire ra_set_prop_from_string(scf_handle_t *h, scf_instance_t *inst,
20713048Samaguire     const char *pgname, const char *propname, scf_type_t proptype,
20723048Samaguire     boolean_t create, int numpropvals, const char **propvals)
20733048Samaguire {
20743048Samaguire 	scf_propertygroup_t	*instpg = NULL, *cpg = NULL;
20753048Samaguire 	scf_type_t		oldproptype, newproptype = proptype;
20763048Samaguire 	scf_property_t		*prop = NULL;
20773048Samaguire 	scf_value_t		**values = NULL;
20783048Samaguire 	scf_transaction_t	*tx = NULL;
20793048Samaguire 	scf_transaction_entry_t	*ent = NULL;
20803048Samaguire 	boolean_t		new = B_FALSE;
20813048Samaguire 	int			i, retval, numvalues = 0, ret = 0;
20823048Samaguire 	char			*pgtype = NULL, **ovalues;
20833048Samaguire 	ssize_t			typelen;
20843048Samaguire 
20853048Samaguire 	/* Firstly, does property exist? If not, and create is false, bail */
20863048Samaguire 	if (ra_get_prop_as_string(h, inst, pgname, propname, B_TRUE,
20873048Samaguire 	    B_FALSE, &oldproptype, &numvalues, &ovalues) == -1) {
20883048Samaguire 		if (scf_error() != SCF_ERROR_NOT_FOUND)
20893048Samaguire 			goto error;
20903048Samaguire 		if (!create) {
20913048Samaguire 			(void) fprintf(stderr, gettext(
20923048Samaguire 			    "%s: no such property %s/%s\n"), myname, pgname,
20933048Samaguire 			    propname);
20943048Samaguire 			return (-1);
20953048Samaguire 		}
20963048Samaguire 	} else
20973048Samaguire 		ra_free_prop_values(numvalues, ovalues);
20983048Samaguire 
20993048Samaguire 	/* Use old property type */
21003048Samaguire 	if (proptype == SCF_TYPE_INVALID)
21013048Samaguire 		newproptype = oldproptype;
21023048Samaguire 
21033048Samaguire 	/*
21043048Samaguire 	 * Does property group exist at instance level?  If not, we need to
21053048Samaguire 	 * create it,  since the composed view of the property group did
21063048Samaguire 	 * contain the property.  We never modify properties at the service
21073048Samaguire 	 * level,  as it`s possible that multiple instances will inherit those
21083048Samaguire 	 * settings.
21093048Samaguire 	 */
21103048Samaguire 	if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) {
21113048Samaguire 		if (scf_error() != SCF_ERROR_NOT_FOUND)
21123048Samaguire 			goto error;
21133048Samaguire 		/* Ensure pg exists at service level, get composed pg */
21143048Samaguire 		if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1)
21153048Samaguire 			goto error;
21163048Samaguire 
21173048Samaguire 		/* Create instance-level property group */
21183048Samaguire 		if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0)
21193048Samaguire 			goto error;
21203048Samaguire 		if ((pgtype = malloc(typelen)) == NULL) {
21213048Samaguire 			(void) fprintf(stderr, gettext(
21223048Samaguire 			    "%s: out of memory\n"), myname);
21233048Samaguire 			goto error;
21243048Samaguire 		}
21253048Samaguire 		(void) scf_pg_get_type(cpg, pgtype, typelen);
21263048Samaguire 		if ((instpg = scf_pg_create(h)) == NULL ||
21273048Samaguire 		    scf_instance_add_pg(inst, pgname, pgtype, 0, instpg)
21283048Samaguire 		    == -1) {
21293048Samaguire 			(void) fprintf(stderr, gettext(
21303048Samaguire 			    "%s: could not create property group %s\n"),
21313048Samaguire 			    myname, pgname);
21323048Samaguire 			goto error;
21333048Samaguire 		}
21343048Samaguire 	}
21353048Samaguire 	if ((prop = scf_property_create(h)) == NULL)
21363048Samaguire 		goto error;
21373048Samaguire 	if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) {
21383048Samaguire 		(void) fprintf(stderr, gettext("%s: out of memory"), myname);
21393048Samaguire 		goto error;
21403048Samaguire 	}
21413048Samaguire 	if (scf_pg_get_property(instpg, propname, prop) != 0) {
21423048Samaguire 		/* New property? */
21433048Samaguire 		if (scf_error() == SCF_ERROR_NOT_FOUND)
21443048Samaguire 			new = B_TRUE;
21453048Samaguire 		else
21463048Samaguire 			goto error;
21473048Samaguire 	}
21483048Samaguire 	if ((tx = scf_transaction_create(h)) == NULL ||
21493048Samaguire 	    (ent = scf_entry_create(h)) == NULL)
21503048Samaguire 		goto error;
21513048Samaguire retry:
21523048Samaguire 	if (scf_transaction_start(tx, instpg) == -1)
21533048Samaguire 		goto error;
21543048Samaguire 	if (new) {
21553048Samaguire 		if (scf_transaction_property_new(tx, ent, propname,
21563048Samaguire 		    newproptype) == -1)
21573048Samaguire 			goto error;
21583048Samaguire 	} else if (scf_transaction_property_change(tx, ent, propname,
21593048Samaguire 	    newproptype) == -1)
21603048Samaguire 		goto error;
21613048Samaguire 	for (i = 0; i < numpropvals; i++) {
21623048Samaguire 		if ((values[i] = scf_value_create(h)) == NULL ||
21633048Samaguire 		    scf_value_set_from_string(values[i], newproptype,
21643048Samaguire 		    propvals[i] == NULL ? "": propvals[i]) == -1 ||
21653048Samaguire 		    scf_entry_add_value(ent, values[i]) != 0)
21663048Samaguire 			goto error;
21673048Samaguire 	}
21683048Samaguire 	retval = scf_transaction_commit(tx);
21693048Samaguire 	if (retval == 0) {
21703048Samaguire 		scf_transaction_reset(tx);
21713048Samaguire 		if (scf_pg_update(instpg) == -1)
21723048Samaguire 			goto error;
21733048Samaguire 		goto retry;
21743048Samaguire 	}
21753048Samaguire 	if (retval == -1)
21763048Samaguire 		goto error;
21773048Samaguire 	goto out;
21783048Samaguire error:
21793048Samaguire 	switch (scf_error()) {
21803048Samaguire 	case SCF_ERROR_INVALID_ARGUMENT:
21813048Samaguire 		(void) fprintf(stderr, gettext(
21823048Samaguire 		    "%s: invalid value for property %s/%s\n"), myname,
21833048Samaguire 		    pgname, propname);
21843048Samaguire 		break;
21853048Samaguire 	case SCF_ERROR_NOT_FOUND:
21863048Samaguire 		(void) fprintf(stderr, gettext(
21873048Samaguire 		    "%s: no such property %s/%s\n"), myname,
21883048Samaguire 		    pgname, propname);
21893048Samaguire 		break;
21903048Samaguire 	default:
21913048Samaguire 		(void) fprintf(stderr, gettext(
21923048Samaguire 		    "%s: unexpected libscf error: %s\n"), myname,
21933048Samaguire 		    scf_strerror(scf_error()));
21943048Samaguire 		break;
21953048Samaguire 	}
21963048Samaguire 	ret = -1;
21973048Samaguire out:
21983048Samaguire 	if (tx != NULL)
21993048Samaguire 		scf_transaction_destroy(tx);
22003048Samaguire 	if (ent != NULL)
22013048Samaguire 		scf_entry_destroy(ent);
22023048Samaguire 	if (values != NULL) {
22033048Samaguire 		for (i = 0; i < numpropvals; i++) {
22043048Samaguire 			if (values[i] != NULL)
22053048Samaguire 				scf_value_destroy(values[i]);
22063048Samaguire 		}
22073048Samaguire 		free(values);
22083048Samaguire 	}
22093048Samaguire 	if (prop != NULL)
22103048Samaguire 		scf_property_destroy(prop);
22113048Samaguire 	if (cpg != NULL)
22123048Samaguire 		scf_pg_destroy(cpg);
22133048Samaguire 	if (instpg != NULL)
22143048Samaguire 		scf_pg_destroy(instpg);
22153048Samaguire 	if (pgtype != NULL)
22163048Samaguire 		free(pgtype);
22173048Samaguire 	return (ret);
22183048Samaguire }
22193048Samaguire 
22203048Samaguire /*
22213048Samaguire  * This function gathers configuration from the legacy /etc/inet/routing.conf,
22223048Samaguire  * if any, and sets the appropriate variable values accordingly.  Once
22233048Samaguire  * these are set,  the legacy daemons are checked to see if they have
22243048Samaguire  * SMF counterparts (ra_check_legacy_daemons()).  If they do, the
22253048Samaguire  * configuration is upgraded.  Finally,  the legacy option settings are
22263048Samaguire  * applied,  enabling/disabling the routing/forwarding services as
22273048Samaguire  * appropriate.
22283048Samaguire  */
22293048Samaguire static int
ra_upgrade_from_legacy_conf(void)22303048Samaguire ra_upgrade_from_legacy_conf(void)
22313048Samaguire {
22323048Samaguire 	scf_handle_t	*h = NULL;
22333048Samaguire 	scf_instance_t	*inst = NULL;
22343048Samaguire 	int		ret = 0, i, r;
22353048Samaguire 	boolean_t	old_conf_read;
22363048Samaguire 	ravar_t		*routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
22373048Samaguire 
22383048Samaguire 	/*
22393048Samaguire 	 * First, determine if we have already upgraded - if "routing-conf-read"
22403048Samaguire 	 * is true, we bail.  The use of a boolean property indicating if
22413048Samaguire 	 * routing.conf has been read and applied might seem a lot more
22423048Samaguire 	 * work than simply copying routing.conf aside,  but leaving the
22433048Samaguire 	 * file in place allows users to downgrade and have their old
22443048Samaguire 	 * routing configuration still in place.
22453048Samaguire 	 */
22463048Samaguire 	if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
22473048Samaguire 	    scf_handle_bind(h) == -1) {
22483048Samaguire 		(void) fprintf(stderr, gettext(
22493048Samaguire 		    "%s: cannot connect to SMF repository\n"), myname);
22503048Samaguire 		ret = -1;
22513048Samaguire 		goto out;
22523048Samaguire 	}
22533048Samaguire 	if ((inst = scf_instance_create(h)) == NULL ||
22543048Samaguire 	    scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP,
22553048Samaguire 	    NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
22563048Samaguire 		(void) fprintf(stderr, gettext(
22573048Samaguire 		    "%s: unexpected libscf error: %s\n"), myname,
22583048Samaguire 		    scf_strerror(scf_error()));
22593048Samaguire 		ret = -1;
22603048Samaguire 		goto out;
22613048Samaguire 	}
22623048Samaguire 	if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
22633048Samaguire 	    RA_PROP_ROUTING_CONF_READ, B_TRUE, B_TRUE, &old_conf_read) == -1) {
22643048Samaguire 		ret = -1;
22653048Samaguire 		goto out;
22663048Samaguire 	}
22673048Samaguire 
22683048Samaguire 	if (old_conf_read)
22693048Samaguire 		goto out;
22703048Samaguire 
22713048Samaguire 	/*
22723048Samaguire 	 * Now set "routing-conf-read" to true so we don`t reimport legacy
22733048Samaguire 	 * configuration again.
22743048Samaguire 	 */
22753048Samaguire 	if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
22763048Samaguire 	    RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1)
22773048Samaguire 		return (-1);
22783048Samaguire 	(void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
22793048Samaguire 
22803048Samaguire 	ra_resetvars(NULL);
22813048Samaguire 
22823048Samaguire 	/* First, gather values from routing.conf */
22833048Samaguire 	if ((r = ra_parseconf()) == -1) {
22843048Samaguire 		ret = -1;
22853048Samaguire 		goto out;
22863048Samaguire 	}
22873048Samaguire 	/* No routing.conf file found */
22883048Samaguire 	if (r == 0)
22893048Samaguire 		goto out;
22903048Samaguire 	/*
22913048Samaguire 	 * Now, set the options/variables gathered.  We set variables first,
22923048Samaguire 	 * as we cannot enable routing before we determine the daemons
22933048Samaguire 	 * to enable.
22943048Samaguire 	 */
22953048Samaguire 
22963048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
22973048Samaguire 		/* Skip routing-svcs var, not featured in legacy config */
22983048Samaguire 		if (strcmp(ra_vars[i].var_name, RA_VAR_ROUTING_SVCS) == 0)
22993048Samaguire 			continue;
23003048Samaguire 		if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri,
23013048Samaguire 		    &(ra_vars[i])) == -1) {
23023048Samaguire 			ret = -1;
23033048Samaguire 			goto out;
23043048Samaguire 		}
23053048Samaguire 	}
23063048Samaguire 	/* Clear routing-svcs value */
23073048Samaguire 	if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
23083048Samaguire 	    routing_svcs) == -1) {
23093048Samaguire 		ret = -1;
23103048Samaguire 		goto out;
23113048Samaguire 	}
23123048Samaguire 
23133048Samaguire 	if (ra_check_legacy_daemons() == -1) {
23143048Samaguire 		ret = -1;
23153048Samaguire 		goto out;
23163048Samaguire 	}
23173048Samaguire 
23183048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
23193048Samaguire 		if (ra_smf_cb(ra_set_persistent_opt_cb, ra_opts[i].opt_fmri,
23203048Samaguire 		    &(ra_opts[i])) == -1 ||
23213048Samaguire 		    ra_smf_cb(ra_set_default_opt_cb,
23223048Samaguire 		    ra_opts[i].opt_default_fmri, &(ra_opts[i])) == -1) {
23233048Samaguire 			ret = -1;
23243048Samaguire 			break;
23253048Samaguire 		}
23263048Samaguire 	}
23273048Samaguire out:
23283048Samaguire 	if (inst != NULL)
23293048Samaguire 		scf_instance_destroy(inst);
23303048Samaguire 	if (h != NULL)
23313048Samaguire 		scf_handle_destroy(h);
23323048Samaguire 
23333048Samaguire 	return (ret);
23343048Samaguire }
23353048Samaguire 
23363048Samaguire /*
23373094Samaguire  *
23383094Samaguire  * Return the number of IPv6 addresses configured.  This answers the
23393094Samaguire  * generic question, "is IPv6 configured?".  We only start in.ndpd if IPv6
23403094Samaguire  * is configured, and we also only enable IPv6 routing daemons if IPv6 is
23413094Samaguire  * enabled.
23423094Samaguire  */
23433094Samaguire static int
ra_numv6intfs(void)23443094Samaguire ra_numv6intfs(void)
23453094Samaguire {
23463094Samaguire 	static int	num = -1;
23473094Samaguire 	int		ipsock;
23483094Samaguire 	struct lifnum	lifn;
23493094Samaguire 
23503094Samaguire 	if (num != -1)
23513094Samaguire 		return (num);
23523094Samaguire 
23533094Samaguire 	if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
23543094Samaguire 		(void) fprintf(stderr,
23553094Samaguire 		    gettext("%1$s: unable to open %2$s: %3$s\n"),
23563094Samaguire 		    myname, IP_DEV_NAME, strerror(errno));
23573094Samaguire 		return (0);
23583094Samaguire 	}
23593094Samaguire 	lifn.lifn_family = AF_INET6;
23603094Samaguire 	lifn.lifn_flags = 0;
23613094Samaguire 
23623094Samaguire 	if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
23633094Samaguire 		(void) close(ipsock);
23643094Samaguire 		return (0);
23653094Samaguire 	}
23663094Samaguire 	(void) close(ipsock);
23673094Samaguire 
23683094Samaguire 	return (num = lifn.lifn_count);
23693094Samaguire }
23703094Samaguire 
23713094Samaguire /*
23723048Samaguire  * Parse the configuration file and fill the ra_opts array with opt_value
23733048Samaguire  * and opt_default_value values, and the ra_vars array with var_value and
23743048Samaguire  * var_default_value values.  Then copy aside routing.conf so it will not
23753048Samaguire  * be read by future invokations of routeadm.
23763048Samaguire  */
23773048Samaguire static int
ra_parseconf(void)23783048Samaguire ra_parseconf(void)
23793048Samaguire {
23803048Samaguire 	FILE	*fp;
23813048Samaguire 	uint_t	lineno;
23823048Samaguire 	char	line[RA_MAX_CONF_LINE];
23833048Samaguire 	char	*cp, *confstr;
23843048Samaguire 	raopt_t	*raopt;
23853048Samaguire 	ravar_t *ravar;
23863048Samaguire 
23873048Samaguire 	if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) {
23883048Samaguire 		/*
23893048Samaguire 		 * There's no config file, so we simply return as there
23903048Samaguire 		 * is no work to do.
23913048Samaguire 		 */
23923048Samaguire 		return (0);
23933048Samaguire 	}
23943048Samaguire 
23953048Samaguire 	for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) {
23963048Samaguire 		if (line[strlen(line) - 1] == '\n')
23973048Samaguire 			line[strlen(line) - 1] = '\0';
23983048Samaguire 
23993048Samaguire 		cp = line;
24003048Samaguire 
24013048Samaguire 		/* Skip leading whitespace */
24023048Samaguire 		while (isspace(*cp))
24033048Samaguire 			cp++;
24043048Samaguire 
24053048Samaguire 		/* Skip comment lines and empty lines */
24063048Samaguire 		if (*cp == '#' || *cp == '\0')
24073048Samaguire 			continue;
24083048Samaguire 
24093048Samaguire 		/*
24103048Samaguire 		 * Anything else must be of the form:
24113048Samaguire 		 * <option> <value> <default_value>
24123048Samaguire 		 */
24133048Samaguire 		if ((confstr = strtok(cp, " ")) == NULL) {
24143048Samaguire 			(void) fprintf(stderr,
24153048Samaguire 			    gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
24163048Samaguire 			    myname, RA_CONF_FILE, lineno);
24173048Samaguire 			continue;
24183048Samaguire 		}
24193048Samaguire 
24203048Samaguire 		if ((raopt = ra_str2opt(confstr)) != NULL) {
24213048Samaguire 			if (ra_parseopt(confstr, lineno, raopt) != 0) {
24223048Samaguire 				(void) fclose(fp);
24233048Samaguire 				return (-1);
24243048Samaguire 			}
24253048Samaguire 		} else if ((ravar = ra_str2var(confstr)) != NULL) {
24263048Samaguire 			if (ra_parsevar(confstr, ravar) != 0) {
24273048Samaguire 				(void) fclose(fp);
24283048Samaguire 				return (-1);
24293048Samaguire 			}
24303048Samaguire 		} else {
24313048Samaguire 			(void) fprintf(stderr,
24323048Samaguire 			    gettext("%1$s: %2$s: invalid option name on "
24333048Samaguire 				"line %3$d\n"),
24343048Samaguire 			    myname, RA_CONF_FILE, lineno);
24353048Samaguire 			continue;
24363048Samaguire 		}
24373048Samaguire 	}
24383048Samaguire 
24393048Samaguire 	(void) fclose(fp);
24403048Samaguire 
24413048Samaguire 	return (1);
24423048Samaguire }
24433048Samaguire 
24443048Samaguire static int
ra_parseopt(char * confstr,int lineno,raopt_t * raopt)24453048Samaguire ra_parseopt(char *confstr, int lineno, raopt_t *raopt)
24463048Samaguire {
24473048Samaguire 	oval_t oval, d_oval;
24483048Samaguire 
24493048Samaguire 	if ((confstr = strtok(NULL, " ")) == NULL) {
24503048Samaguire 		(void) fprintf(stderr,
24513048Samaguire 		    gettext("%1$s: %2$s: missing value on line %3$d\n"),
24523048Samaguire 		    myname, RA_CONF_FILE, lineno);
24533048Samaguire 		return (0);
24543048Samaguire 	}
24553048Samaguire 	if ((oval = ra_str2oval(confstr)) == OPT_INVALID) {
24563048Samaguire 		(void) fprintf(stderr,
24573048Samaguire 		    gettext("%1$s: %2$s: invalid option "
24583048Samaguire 			"value on line %3$d\n"),
24593048Samaguire 		    myname, RA_CONF_FILE, lineno);
24603048Samaguire 		return (0);
24613048Samaguire 	}
24623048Samaguire 	if (oval != OPT_DEFAULT)
24633048Samaguire 		raopt->opt_enabled = oval == OPT_ENABLED;
24643048Samaguire 
24653048Samaguire 	if ((confstr = strtok(NULL, " ")) == NULL) {
24663048Samaguire 		(void) fprintf(stderr,
24673048Samaguire 		    gettext("%1$s: %2$s: missing revert "
24683048Samaguire 			"value on line %3$d\n"),
24693048Samaguire 		    myname, RA_CONF_FILE, lineno);
24703048Samaguire 		return (0);
24713048Samaguire 	}
24723048Samaguire 	if ((d_oval = ra_str2oval(confstr)) == OPT_INVALID) {
24733048Samaguire 		(void) fprintf(stderr,
24743048Samaguire 		    gettext("%1$s: %2$s: invalid revert "
24753048Samaguire 			"value on line %3$d\n"),
24763048Samaguire 		    myname, RA_CONF_FILE, lineno, confstr);
24773048Samaguire 		return (0);
24783048Samaguire 	}
24793048Samaguire 	raopt->opt_default_enabled = d_oval == OPT_ENABLED;
24803048Samaguire 	if (oval == OPT_DEFAULT)
24813048Samaguire 		raopt->opt_enabled = d_oval == OPT_ENABLED;
2482*3294Samaguire 
2483*3294Samaguire 	/*
2484*3294Samaguire 	 * Set ipv4(6)-routing-set property as appropriate on upgrading
2485*3294Samaguire 	 * routing.conf.  If option was default, set this value to false,
2486*3294Samaguire 	 * as this indicates the administrator has not explicitly enabled
2487*3294Samaguire 	 * or disabled ipv4(6)-routing.  The ipv4-routing-set value is used
2488*3294Samaguire 	 * in the routing-setup service, and if it is false, ipv4-routing
2489*3294Samaguire 	 * is enabled in the case where no default route can be determined.
2490*3294Samaguire 	 */
2491*3294Samaguire 	if (raopt->opt_flags & (RA_SVC_FLAG_IPV4_ROUTING |
2492*3294Samaguire 	    RA_SVC_FLAG_IPV6_ROUTING)) {
2493*3294Samaguire 		if (ra_smf_cb(oval == OPT_DEFAULT ? ra_routing_opt_unset_cb :
2494*3294Samaguire 		    ra_routing_opt_set_cb, raopt->opt_default_fmri, raopt)
2495*3294Samaguire 		    == -1)
2496*3294Samaguire 			return (-1);
2497*3294Samaguire 	}
24983048Samaguire 	return (0);
24993048Samaguire }
25003048Samaguire 
25013048Samaguire static int
ra_parsevar(char * confstr,ravar_t * ravar)25023048Samaguire ra_parsevar(char *confstr, ravar_t *ravar)
25033048Samaguire {
25043048Samaguire 	confstr = strtok(NULL, "=");
25053048Samaguire 	if (confstr == NULL) {
25063048Samaguire 		/*
25073048Samaguire 		 * This isn't an error condition, it simply means that the
25083048Samaguire 		 * variable has no value.
25093048Samaguire 		 */
25103048Samaguire 		ravar->var_value = NULL;
25113048Samaguire 		return (0);
25123048Samaguire 	}
25133048Samaguire 
25143048Samaguire 	if ((ravar->var_value = strdup(confstr)) == NULL) {
25153048Samaguire 		(void) fprintf(stderr, gettext("%s: "
25163048Samaguire 		    "unable to allocate memory\n"), myname);
25173048Samaguire 		return (-1);
25183048Samaguire 	}
25193048Samaguire 	return (0);
25203048Samaguire }
25213048Samaguire 
25223048Samaguire /* Convert a string to an option value. */
25233048Samaguire static oval_t
ra_str2oval(const char * valstr)25243048Samaguire ra_str2oval(const char *valstr)
25253048Samaguire {
25263048Samaguire 	if (strcmp(valstr, "enabled") == 0)
25273048Samaguire 		return (OPT_ENABLED);
25283048Samaguire 	else if (strcmp(valstr, "disabled") == 0)
25293048Samaguire 		return (OPT_DISABLED);
25303048Samaguire 	else if (strcmp(valstr, "default") == 0)
25313048Samaguire 		return (OPT_DEFAULT);
25323048Samaguire 	return (OPT_INVALID);
25333048Samaguire }
25343048Samaguire 
25353048Samaguire static raopt_t *
ra_str2opt(const char * optnamestr)25363048Samaguire ra_str2opt(const char *optnamestr)
25373048Samaguire {
25383048Samaguire 	int	i;
25393048Samaguire 
25403048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
25413048Samaguire 		if (strcmp(optnamestr, ra_opts[i].opt_name) == 0)
25423048Samaguire 			break;
25433048Samaguire 	}
25443048Samaguire 	if (ra_opts[i].opt_name == NULL)
25453048Samaguire 		return (NULL);
25463048Samaguire 	return (&ra_opts[i]);
25473048Samaguire }
25483048Samaguire 
25493048Samaguire /*
25503048Samaguire  * Reset all option values previously gathered to B_FALSE.
25513048Samaguire  */
25523048Samaguire static void
ra_resetopts(void)25533048Samaguire ra_resetopts(void)
25543048Samaguire {
25553048Samaguire 	int	i;
25563048Samaguire 
25573048Samaguire 	for (i = 0; ra_opts[i].opt_name != NULL; i++) {
25583048Samaguire 		ra_opts[i].opt_enabled = B_FALSE;
25593048Samaguire 		ra_opts[i].opt_default_enabled = B_FALSE;
25603048Samaguire 	}
25613048Samaguire }
25623048Samaguire 
25633048Samaguire static ravar_t *
ra_str2var(const char * varnamestr)25643048Samaguire ra_str2var(const char *varnamestr)
25653048Samaguire {
25663048Samaguire 	int	i;
25673048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
25683048Samaguire 		if (strcmp(varnamestr, ra_vars[i].var_name) == 0)
25693048Samaguire 			break;
25703048Samaguire 	}
25713048Samaguire 	if (ra_vars[i].var_name == NULL)
25723048Samaguire 		return (NULL);
25733048Samaguire 	return (&ra_vars[i]);
25743048Samaguire }
25753048Samaguire 
25763048Samaguire /*
25773048Samaguire  * Reset variable values previously gathered to NULL.
25783048Samaguire  */
25793048Samaguire static void
ra_resetvars(const char * proto)25803048Samaguire ra_resetvars(const char *proto)
25813048Samaguire {
25823048Samaguire 	int	i;
25833048Samaguire 	for (i = 0; ra_vars[i].var_name != NULL; i++) {
25843048Samaguire 		if (proto != NULL &&
25853048Samaguire 		    !VAR_PROTO_MATCH(ra_vars[i].var_name, proto))
25863048Samaguire 			continue;
25873048Samaguire 		if (ra_vars[i].var_value != NULL)
25883048Samaguire 			free(ra_vars[i].var_value);
25893048Samaguire 		ra_vars[i].var_value = NULL;
25903048Samaguire 		if (ra_vars[i].var_default_value != NULL)
25913048Samaguire 			free(ra_vars[i].var_default_value);
25923048Samaguire 		ra_vars[i].var_default_value = NULL;
25933048Samaguire 	}
25943048Samaguire }
25953048Samaguire 
25963048Samaguire /*
25973048Samaguire  * Given an option name, this function provides an internationalized, human
25983048Samaguire  * readable version of the option name.
25993048Samaguire  */
26003048Samaguire static char *
ra_intloptname(const char * optname)26013048Samaguire ra_intloptname(const char *optname)
26023048Samaguire {
26033048Samaguire 	if (strcmp(optname, RA_OPT_IPV4_FORWARDING) == 0)
26043048Samaguire 		return (gettext("IPv4 forwarding"));
26053048Samaguire 	else if (strcmp(optname, RA_OPT_IPV4_ROUTING) == 0)
26063048Samaguire 		return (gettext("IPv4 routing"));
26073048Samaguire 	else if (strcmp(optname, RA_OPT_IPV6_FORWARDING) == 0)
26083048Samaguire 		return (gettext("IPv6 forwarding"));
26093048Samaguire 	else if (strcmp(optname, RA_OPT_IPV6_ROUTING) == 0)
26103048Samaguire 		return (gettext("IPv6 routing"));
26113048Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON) == 0)
26123048Samaguire 		return (gettext("IPv4 routing daemon"));
26133048Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON_ARGS) == 0)
26143048Samaguire 		return (gettext("IPv4 routing daemon args"));
26153048Samaguire 	else if (strcmp(optname, RA_VAR_IPV4_ROUTING_STOP_CMD) == 0)
26163048Samaguire 		return (gettext("IPv4 routing daemon stop"));
26173048Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON) == 0)
26183048Samaguire 		return (gettext("IPv6 routing daemon"));
26193048Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON_ARGS) == 0)
26203048Samaguire 		return (gettext("IPv6 routing daemon args"));
26213048Samaguire 	else if (strcmp(optname, RA_VAR_IPV6_ROUTING_STOP_CMD) == 0)
26223048Samaguire 		return (gettext("IPv6 routing daemon stop"));
26233048Samaguire 	else if (strcmp(optname, RA_VAR_ROUTING_SVCS) == 0)
26243048Samaguire 		return (gettext("Routing services"));
26253048Samaguire 	/*
26263048Samaguire 	 * If we get here, there's a bug and someone should trip over this
26273048Samaguire 	 * NULL pointer.
26283048Samaguire 	 */
26293048Samaguire 	return (NULL);
26303048Samaguire }
2631