xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/main.c (revision 38f140aaa4a32508dc5318744dd8d51ab84b23a5)
1d71dbb73Sjbeck /*
2d71dbb73Sjbeck  * CDDL HEADER START
3d71dbb73Sjbeck  *
4d71dbb73Sjbeck  * The contents of this file are subject to the terms of the
5d71dbb73Sjbeck  * Common Development and Distribution License (the "License").
6d71dbb73Sjbeck  * You may not use this file except in compliance with the License.
7d71dbb73Sjbeck  *
8d71dbb73Sjbeck  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d71dbb73Sjbeck  * or http://www.opensolaris.org/os/licensing.
10d71dbb73Sjbeck  * See the License for the specific language governing permissions
11d71dbb73Sjbeck  * and limitations under the License.
12d71dbb73Sjbeck  *
13d71dbb73Sjbeck  * When distributing Covered Code, include this CDDL HEADER in each
14d71dbb73Sjbeck  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d71dbb73Sjbeck  * If applicable, add the following below this CDDL HEADER, with the
16d71dbb73Sjbeck  * fields enclosed by brackets "[]" replaced with your own identifying
17d71dbb73Sjbeck  * information: Portions Copyright [yyyy] [name of copyright owner]
18d71dbb73Sjbeck  *
19d71dbb73Sjbeck  * CDDL HEADER END
20d71dbb73Sjbeck  */
21d71dbb73Sjbeck 
22d71dbb73Sjbeck /*
23634e26ecSCasper H.S. Dik  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24d71dbb73Sjbeck  * Use is subject to license terms.
25d71dbb73Sjbeck  */
26d71dbb73Sjbeck 
276ba597c5SAnurag S. Maskey #include <errno.h>
286ba597c5SAnurag S. Maskey #include <fcntl.h>
296ba597c5SAnurag S. Maskey #include <inetcfg.h>
306ba597c5SAnurag S. Maskey #include <libdllink.h>
316ba597c5SAnurag S. Maskey #include <libintl.h>
326ba597c5SAnurag S. Maskey #include <libnwam.h>
336ba597c5SAnurag S. Maskey #include <locale.h>
346ba597c5SAnurag S. Maskey #include <priv.h>
356ba597c5SAnurag S. Maskey #include <pthread.h>
366ba597c5SAnurag S. Maskey #include <signal.h>
376ba597c5SAnurag S. Maskey #include <stdio.h>
386ba597c5SAnurag S. Maskey #include <stdlib.h>
396ba597c5SAnurag S. Maskey #include <string.h>
406ba597c5SAnurag S. Maskey #include <sys/stat.h>
416ba597c5SAnurag S. Maskey #include <sys/types.h>
426ba597c5SAnurag S. Maskey #include <sys/wait.h>
436ba597c5SAnurag S. Maskey #include <unistd.h>
446ba597c5SAnurag S. Maskey 
456ba597c5SAnurag S. Maskey #include <libnwam.h>
466ba597c5SAnurag S. Maskey #include "conditions.h"
476ba597c5SAnurag S. Maskey #include "events.h"
486ba597c5SAnurag S. Maskey #include "llp.h"
496ba597c5SAnurag S. Maskey #include "ncp.h"
506ba597c5SAnurag S. Maskey #include "objects.h"
516ba597c5SAnurag S. Maskey #include "util.h"
526ba597c5SAnurag S. Maskey 
53d71dbb73Sjbeck /*
54d71dbb73Sjbeck  * nwamd - NetWork Auto-Magic Daemon
55d71dbb73Sjbeck  */
56d71dbb73Sjbeck 
57d71dbb73Sjbeck boolean_t fg = B_FALSE;
586ba597c5SAnurag S. Maskey dladm_handle_t dld_handle = NULL;
596ba597c5SAnurag S. Maskey boolean_t shutting_down = B_FALSE;
606ba597c5SAnurag S. Maskey 
61d71dbb73Sjbeck sigset_t original_sigmask;
628b2954c8SRenee Danson Sommerfeld static sigset_t sigwaitset;
636ba597c5SAnurag S. Maskey 
646ba597c5SAnurag S. Maskey static void nwamd_refresh(void);
656ba597c5SAnurag S. Maskey static void graceful_shutdown(void);
66d71dbb73Sjbeck 
67d71dbb73Sjbeck /*
68d71dbb73Sjbeck  * nwamd
69d71dbb73Sjbeck  *
70d71dbb73Sjbeck  * This is the Network Auto-Magic daemon.  For further high level information
71d71dbb73Sjbeck  * see the Network Auto-Magic project and the Approachability communities
726ba597c5SAnurag S. Maskey  * on opensolaris.org, nwamd(1M), and the README in the source directory.
73d71dbb73Sjbeck  *
746ba597c5SAnurag S. Maskey  * The general structure of the code is as a set of event source threads
756ba597c5SAnurag S. Maskey  * which feed events into the event handling thread. Some of these events
766ba597c5SAnurag S. Maskey  * are internal-only (e.g UPGRADE), but some also involve propogation
776ba597c5SAnurag S. Maskey  * to external listeners (who register via a door call into the daemon).
78d71dbb73Sjbeck  *
79d71dbb73Sjbeck  * signal management
80d71dbb73Sjbeck  * Due to being threaded, a simple set of signal handlers would not work
816ba597c5SAnurag S. Maskey  * very well for nwamd.  Instead nwamd blocks signals in all but the
826ba597c5SAnurag S. Maskey  * signal handling thread at startup.
83d71dbb73Sjbeck  *
84d71dbb73Sjbeck  */
85d71dbb73Sjbeck 
86d71dbb73Sjbeck /*
87d71dbb73Sjbeck  * In this file there are several utility functions which might otherwise
88d71dbb73Sjbeck  * belong in util.c, but since they are only called from main(), they can
89d71dbb73Sjbeck  * live here as static functions:
906ba597c5SAnurag S. Maskey  * - nlog set-up
91d71dbb73Sjbeck  * - daemonizing
92d71dbb73Sjbeck  * - looking up SMF(5) properties
93d71dbb73Sjbeck  * - signal handling
94d71dbb73Sjbeck  * - managing privileges(5)
95d71dbb73Sjbeck  */
96d71dbb73Sjbeck 
97d71dbb73Sjbeck static void
98d71dbb73Sjbeck start_logging(void)
99d71dbb73Sjbeck {
100d71dbb73Sjbeck 	openlog("nwamd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
101d71dbb73Sjbeck }
102d71dbb73Sjbeck 
103d71dbb73Sjbeck static void
104d71dbb73Sjbeck daemonize(void)
105d71dbb73Sjbeck {
106d71dbb73Sjbeck 	pid_t pid;
107d71dbb73Sjbeck 
108d71dbb73Sjbeck 	/*
109d71dbb73Sjbeck 	 * A little bit of magic here.  By the first fork+setsid, we
110d71dbb73Sjbeck 	 * disconnect from our current controlling terminal and become
111d71dbb73Sjbeck 	 * a session group leader.  By forking again without calling
112d71dbb73Sjbeck 	 * setsid again, we make certain that we are not the session
113d71dbb73Sjbeck 	 * group leader and can never reacquire a controlling terminal.
114d71dbb73Sjbeck 	 */
1156ba597c5SAnurag S. Maskey 	if ((pid = fork()) == (pid_t)-1)
1166ba597c5SAnurag S. Maskey 		pfail("fork 1 failed");
117d71dbb73Sjbeck 	if (pid != 0) {
118d71dbb73Sjbeck 		(void) wait(NULL);
1196ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "child %ld exited, daemonizing", pid);
120d71dbb73Sjbeck 		_exit(0);
121d71dbb73Sjbeck 	}
1226ba597c5SAnurag S. Maskey 	if (setsid() == (pid_t)-1)
1236ba597c5SAnurag S. Maskey 		pfail("setsid");
1246ba597c5SAnurag S. Maskey 	if ((pid = fork()) == (pid_t)-1)
1256ba597c5SAnurag S. Maskey 		pfail("fork 2 failed");
126d71dbb73Sjbeck 	if (pid != 0) {
127d71dbb73Sjbeck 		_exit(0);
128d71dbb73Sjbeck 	}
129d71dbb73Sjbeck 	(void) chdir("/");
130d71dbb73Sjbeck 	(void) umask(022);
131d71dbb73Sjbeck }
132d71dbb73Sjbeck 
133d71dbb73Sjbeck /* ARGSUSED */
134d71dbb73Sjbeck static void *
135d71dbb73Sjbeck sighandler(void *arg)
136d71dbb73Sjbeck {
1376ba597c5SAnurag S. Maskey 	uint64_t propval;
1386ba597c5SAnurag S. Maskey 	int sig;
1396ba597c5SAnurag S. Maskey 	uid_t uid = getuid();
140d71dbb73Sjbeck 
141b00044a2SJames Carlson 	while (!shutting_down) {
1428b2954c8SRenee Danson Sommerfeld 		sig = sigwait(&sigwaitset);
1436ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "signal %s caught", strsignal(sig));
1446ba597c5SAnurag S. Maskey 
145d71dbb73Sjbeck 		/*
1466ba597c5SAnurag S. Maskey 		 * Signal handling is different if the Phase 1 manifest
1476ba597c5SAnurag S. Maskey 		 * have not been yet been imported.  The two if-statements
1486ba597c5SAnurag S. Maskey 		 * below highlight this.  Signals must be handled
1496ba597c5SAnurag S. Maskey 		 * differently because there is no event handling thread
1506ba597c5SAnurag S. Maskey 		 * and event queue.
1516ba597c5SAnurag S. Maskey 		 *
1526ba597c5SAnurag S. Maskey 		 * When manifest-import imports the Phase 1 manifest, it
1536ba597c5SAnurag S. Maskey 		 * refreshes NWAM.  The NWAM Phase 1 properties must be
1546ba597c5SAnurag S. Maskey 		 * available.  If not, NWAM receveid a signal too soon.
1556ba597c5SAnurag S. Maskey 		 * "ncu_wait_time" is a Phase 1 SMF property that did not
1566ba597c5SAnurag S. Maskey 		 * exist in Phase 0/0.5.
157d71dbb73Sjbeck 		 */
1586ba597c5SAnurag S. Maskey 		if (uid == 0 &&
1596ba597c5SAnurag S. Maskey 		    nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
1606ba597c5SAnurag S. Maskey 		    OUR_NCU_WAIT_TIME_PROP_NAME, &propval) != 0) {
1616ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "WARN: Phase 1 properties not available. "
1626ba597c5SAnurag S. Maskey 			    "Ignoring signal ...");
1636ba597c5SAnurag S. Maskey 			continue;
1646ba597c5SAnurag S. Maskey 		}
1656ba597c5SAnurag S. Maskey 
1666ba597c5SAnurag S. Maskey 		/*
1676ba597c5SAnurag S. Maskey 		 *  The Phase 1 manifest has been imported.  If the
1686ba597c5SAnurag S. Maskey 		 *  "version" property exists (it is added by nwamd upon
1696ba597c5SAnurag S. Maskey 		 *  upgrade to Phase 1), then it means that we have already
1706ba597c5SAnurag S. Maskey 		 *  successfully run nwam before.  If it doesn't, then we
1716ba597c5SAnurag S. Maskey 		 *  arrived here just after the new manifest was imported.
1726ba597c5SAnurag S. Maskey 		 *  manifest-import refreshes nwam after the import.  Exit
1736ba597c5SAnurag S. Maskey 		 *  nwamd so that svc.startd(1M) can start nwamd correctly
1746ba597c5SAnurag S. Maskey 		 *  as specified in the imported manifest.
1756ba597c5SAnurag S. Maskey 		 */
1766ba597c5SAnurag S. Maskey 		if (uid == 0 &&
1776ba597c5SAnurag S. Maskey 		    nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
1786ba597c5SAnurag S. Maskey 		    OUR_VERSION_PROP_NAME, &propval) != 0) {
1796ba597c5SAnurag S. Maskey 			if (sig == SIGHUP) {
1806ba597c5SAnurag S. Maskey 				pfail("WARN: Phase 1 properties available, "
1816ba597c5SAnurag S. Maskey 				    "but NWAM has not been upgraded.  "
1826ba597c5SAnurag S. Maskey 				    "Exiting to let svc.startd restart NWAM");
1836ba597c5SAnurag S. Maskey 			} else {
1846ba597c5SAnurag S. Maskey 				nlog(LOG_ERR, "WARN: Ignoring signal as NWAM "
1856ba597c5SAnurag S. Maskey 				    "has not been upgraded yet");
1866ba597c5SAnurag S. Maskey 				continue;
1876ba597c5SAnurag S. Maskey 			}
1886ba597c5SAnurag S. Maskey 		}
1896ba597c5SAnurag S. Maskey 
1906ba597c5SAnurag S. Maskey 		switch (sig) {
1916ba597c5SAnurag S. Maskey 		case SIGTHAW:
192d71dbb73Sjbeck 		case SIGHUP:
193d71dbb73Sjbeck 			/*
1946ba597c5SAnurag S. Maskey 			 * Resumed from suspend or refresh.  Clear up all
1956ba597c5SAnurag S. Maskey 			 * objects so their states start from scratch;
1966ba597c5SAnurag S. Maskey 			 * then refresh().
197d71dbb73Sjbeck 			 */
1986ba597c5SAnurag S. Maskey 			nwamd_fini_enms();
1996ba597c5SAnurag S. Maskey 			nwamd_fini_ncus();
2006ba597c5SAnurag S. Maskey 			nwamd_fini_locs();
2016ba597c5SAnurag S. Maskey 			nwamd_refresh();
202d71dbb73Sjbeck 			break;
2036ba597c5SAnurag S. Maskey 		case SIGUSR1:
204b00044a2SJames Carlson 			/*
2056ba597c5SAnurag S. Maskey 			 * Undocumented "log ncu list" signal.
206b00044a2SJames Carlson 			 */
2076ba597c5SAnurag S. Maskey 			nwamd_log_ncus();
208ab32bdf2SJames Carlson 			break;
2098b2954c8SRenee Danson Sommerfeld 		case SIGTERM:
2106ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "%s received, shutting down",
211d71dbb73Sjbeck 			    strsignal(sig));
2126ba597c5SAnurag S. Maskey 			graceful_shutdown();
213d71dbb73Sjbeck 			break;
2148b2954c8SRenee Danson Sommerfeld 		default:
2156ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "unexpected signal %s received, "
2168b2954c8SRenee Danson Sommerfeld 			    "ignoring", strsignal(sig));
2178b2954c8SRenee Danson Sommerfeld 			break;
218d71dbb73Sjbeck 		}
219d71dbb73Sjbeck 	}
220b00044a2SJames Carlson 	return (NULL);
221d71dbb73Sjbeck }
222d71dbb73Sjbeck 
223d71dbb73Sjbeck static void
224d71dbb73Sjbeck init_signalhandling(void)
225d71dbb73Sjbeck {
226d71dbb73Sjbeck 	pthread_attr_t attr;
227d71dbb73Sjbeck 	pthread_t sighand;
228d71dbb73Sjbeck 	int err;
229d71dbb73Sjbeck 
230d71dbb73Sjbeck 	(void) pthread_attr_init(&attr);
231d71dbb73Sjbeck 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
232d71dbb73Sjbeck 	if (err = pthread_create(&sighand, &attr, sighandler, NULL)) {
2336ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "pthread_create system: %s", strerror(err));
234d71dbb73Sjbeck 		exit(EXIT_FAILURE);
235d71dbb73Sjbeck 	} else {
2366ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "signal handler thread: %d", sighand);
237d71dbb73Sjbeck 	}
238d71dbb73Sjbeck 	(void) pthread_attr_destroy(&attr);
239d71dbb73Sjbeck }
240d71dbb73Sjbeck 
2416ba597c5SAnurag S. Maskey /*
2426ba597c5SAnurag S. Maskey  * Construct the set of signals that we explicitly want to deal with.
2436ba597c5SAnurag S. Maskey  * We block these while we're still single-threaded; this block will
2446ba597c5SAnurag S. Maskey  * be inherited by all the threads we create.  When we are ready to
2456ba597c5SAnurag S. Maskey  * start handling signals, we will start the signal handling thread,
2466ba597c5SAnurag S. Maskey  * which will sigwait() this same set of signals, and will thus receive
2476ba597c5SAnurag S. Maskey  * and handle any that are sent to the process.
2486ba597c5SAnurag S. Maskey  */
249d71dbb73Sjbeck static void
2506ba597c5SAnurag S. Maskey block_signals(void)
251d71dbb73Sjbeck {
2526ba597c5SAnurag S. Maskey 	(void) sigemptyset(&sigwaitset);
2536ba597c5SAnurag S. Maskey 	(void) sigaddset(&sigwaitset, SIGHUP);
2546ba597c5SAnurag S. Maskey 	(void) sigaddset(&sigwaitset, SIGUSR1);
2556ba597c5SAnurag S. Maskey 	(void) sigaddset(&sigwaitset, SIGUSR2);
2566ba597c5SAnurag S. Maskey 	(void) sigaddset(&sigwaitset, SIGTERM);
2576ba597c5SAnurag S. Maskey 	(void) sigaddset(&sigwaitset, SIGTHAW);
2586ba597c5SAnurag S. Maskey 	(void) pthread_sigmask(SIG_BLOCK, &sigwaitset, &original_sigmask);
2596ba597c5SAnurag S. Maskey }
260d71dbb73Sjbeck 
2616ba597c5SAnurag S. Maskey /*
2626ba597c5SAnurag S. Maskey  * Look up nwamd property values and set daemon variables appropriately.
2636ba597c5SAnurag S. Maskey  * This function will be called on startup and via the signal handling
2646ba597c5SAnurag S. Maskey  * thread on receiving a HUP (which occurs when the nwam service is
2656ba597c5SAnurag S. Maskey  * refreshed).
2666ba597c5SAnurag S. Maskey  */
2676ba597c5SAnurag S. Maskey static void
2686ba597c5SAnurag S. Maskey lookup_daemon_properties(void)
2696ba597c5SAnurag S. Maskey {
2706ba597c5SAnurag S. Maskey 	char *active_ncp_tmp;
2716ba597c5SAnurag S. Maskey 	char *scan_level_tmp;
2726ba597c5SAnurag S. Maskey 
2736ba597c5SAnurag S. Maskey 	(void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
2746ba597c5SAnurag S. Maskey 	    OUR_DEBUG_PROP_NAME, &debug);
2756ba597c5SAnurag S. Maskey 	(void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
2766ba597c5SAnurag S. Maskey 	    OUR_AUTOCONF_PROP_NAME, &wireless_autoconf);
2776ba597c5SAnurag S. Maskey 	(void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
2786ba597c5SAnurag S. Maskey 	    OUR_STRICT_BSSID_PROP_NAME, &wireless_strict_bssid);
2796ba597c5SAnurag S. Maskey 
2806ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
2816ba597c5SAnurag S. Maskey 	if ((active_ncp_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
2826ba597c5SAnurag S. Maskey 	    nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
2836ba597c5SAnurag S. Maskey 	    OUR_ACTIVE_NCP_PROP_NAME, active_ncp_tmp, NWAM_MAX_NAME_LEN) != 0) {
2846ba597c5SAnurag S. Maskey 		(void) strlcpy(active_ncp, NWAM_NCP_NAME_AUTOMATIC,
2856ba597c5SAnurag S. Maskey 		    NWAM_MAX_NAME_LEN);
286d71dbb73Sjbeck 	} else {
2876ba597c5SAnurag S. Maskey 		(void) strlcpy(active_ncp, active_ncp_tmp, NWAM_MAX_NAME_LEN);
2886ba597c5SAnurag S. Maskey 	}
2896ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
2906ba597c5SAnurag S. Maskey 	free(active_ncp_tmp);
291d71dbb73Sjbeck 
2926ba597c5SAnurag S. Maskey 	if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
2936ba597c5SAnurag S. Maskey 	    OUR_CONDITION_CHECK_INTERVAL_PROP_NAME,
2946ba597c5SAnurag S. Maskey 	    &condition_check_interval) != 0)
2956ba597c5SAnurag S. Maskey 		condition_check_interval = CONDITION_CHECK_INTERVAL_DEFAULT;
2966ba597c5SAnurag S. Maskey 
2976ba597c5SAnurag S. Maskey 	if ((scan_level_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
2986ba597c5SAnurag S. Maskey 	    nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
2996ba597c5SAnurag S. Maskey 	    OUR_WIRELESS_SCAN_LEVEL_PROP_NAME, scan_level_tmp,
3006ba597c5SAnurag S. Maskey 	    NWAM_MAX_NAME_LEN) != 0) {
3016ba597c5SAnurag S. Maskey 		wireless_scan_level = WIRELESS_SCAN_LEVEL_DEFAULT;
3026ba597c5SAnurag S. Maskey 	} else {
3036ba597c5SAnurag S. Maskey 		if (dladm_wlan_str2strength(scan_level_tmp,
3046ba597c5SAnurag S. Maskey 		    &wireless_scan_level) != DLADM_STATUS_OK)
3056ba597c5SAnurag S. Maskey 			wireless_scan_level = DLADM_WLAN_STRENGTH_VERY_WEAK;
3066ba597c5SAnurag S. Maskey 	}
3076ba597c5SAnurag S. Maskey 	free(scan_level_tmp);
3086ba597c5SAnurag S. Maskey 
3096ba597c5SAnurag S. Maskey 	if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
3106ba597c5SAnurag S. Maskey 	    OUR_WIRELESS_SCAN_INTERVAL_PROP_NAME, &wireless_scan_interval) != 0)
3116ba597c5SAnurag S. Maskey 		wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
3126ba597c5SAnurag S. Maskey 
3136ba597c5SAnurag S. Maskey 	if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
3146ba597c5SAnurag S. Maskey 	    OUR_NCU_WAIT_TIME_PROP_NAME, &ncu_wait_time) != 0)
3156ba597c5SAnurag S. Maskey 		ncu_wait_time = NCU_WAIT_TIME_DEFAULT;
3166ba597c5SAnurag S. Maskey 
3176ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "Read daemon configuration properties.");
318d71dbb73Sjbeck }
319d71dbb73Sjbeck 
3206ba597c5SAnurag S. Maskey /*
3216ba597c5SAnurag S. Maskey  * Re-read the SMF properties.
3226ba597c5SAnurag S. Maskey  * Reset ncu priority group (since the NCUs will have to walk
3236ba597c5SAnurag S. Maskey  *   through their state machines again) and schedule a check
3246ba597c5SAnurag S. Maskey  * Re-read objects from libnwam.
3256ba597c5SAnurag S. Maskey  * Also, run condition checking for locations and ENMs.
3266ba597c5SAnurag S. Maskey  */
3276ba597c5SAnurag S. Maskey static void
3286ba597c5SAnurag S. Maskey nwamd_refresh(void)
3296ba597c5SAnurag S. Maskey {
3306ba597c5SAnurag S. Maskey 	lookup_daemon_properties();
331d71dbb73Sjbeck 
3326ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
3336ba597c5SAnurag S. Maskey 	current_ncu_priority_group = INVALID_PRIORITY_GROUP;
3346ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
335d71dbb73Sjbeck 
3366ba597c5SAnurag S. Maskey 	nwamd_init_ncus();
3376ba597c5SAnurag S. Maskey 	nwamd_init_enms();
3386ba597c5SAnurag S. Maskey 	nwamd_init_locs();
339d71dbb73Sjbeck 
3406ba597c5SAnurag S. Maskey 	nwamd_create_ncu_check_event(0);
3416ba597c5SAnurag S. Maskey 	nwamd_create_triggered_condition_check_event(0);
342d71dbb73Sjbeck }
343d71dbb73Sjbeck 
344b00044a2SJames Carlson static void
3456ba597c5SAnurag S. Maskey graceful_shutdown(void)
346b00044a2SJames Carlson {
3476ba597c5SAnurag S. Maskey 	nwamd_event_t event;
348b00044a2SJames Carlson 
3496ba597c5SAnurag S. Maskey 	shutting_down = B_TRUE;
3506ba597c5SAnurag S. Maskey 	nwamd_event_sources_fini();
3516ba597c5SAnurag S. Maskey 	nwamd_door_fini();
3526ba597c5SAnurag S. Maskey 	nwamd_fini_enms();
3536ba597c5SAnurag S. Maskey 	nwamd_fini_ncus();
3546ba597c5SAnurag S. Maskey 	nwamd_fini_locs();
3556ba597c5SAnurag S. Maskey 
3566ba597c5SAnurag S. Maskey 	event = nwamd_event_init_shutdown();
3576ba597c5SAnurag S. Maskey 	if (event == NULL)
3586ba597c5SAnurag S. Maskey 		pfail("nwamd could not create shutdown event, exiting");
3596ba597c5SAnurag S. Maskey 	nwamd_event_enqueue(event);
360b00044a2SJames Carlson }
361b00044a2SJames Carlson 
362d71dbb73Sjbeck int
363d71dbb73Sjbeck main(int argc, char *argv[])
364d71dbb73Sjbeck {
365d71dbb73Sjbeck 	int c;
3666ba597c5SAnurag S. Maskey 	uint64_t version;
3676ba597c5SAnurag S. Maskey 	nwamd_event_t event;
3686ba597c5SAnurag S. Maskey 	dladm_status_t rc;
3696ba597c5SAnurag S. Maskey 	uid_t uid = getuid();
3706ba597c5SAnurag S. Maskey 
3716ba597c5SAnurag S. Maskey 	/*
3726ba597c5SAnurag S. Maskey 	 * Block the signals we care about (and which might cause us to
3736ba597c5SAnurag S. Maskey 	 * exit based on default disposition) until we're ready to start
3746ba597c5SAnurag S. Maskey 	 * handling them properly...see init_signalhandling() below.
3756ba597c5SAnurag S. Maskey 	 */
3766ba597c5SAnurag S. Maskey 	block_signals();
3776ba597c5SAnurag S. Maskey 
3786ba597c5SAnurag S. Maskey 	/*
3796ba597c5SAnurag S. Maskey 	 * In the first boot after upgrade, manifest-import hasn't run yet.
3806ba597c5SAnurag S. Maskey 	 * Thus, the NWAM Phase 1 SMF properties are not available yet.  In
3816ba597c5SAnurag S. Maskey 	 * Phase 0/0.5, nwamd ran as root.  Thus in this case, just
3826ba597c5SAnurag S. Maskey 	 * daemonize() nwamd.  When manifest-import imports the Phase 1
3836ba597c5SAnurag S. Maskey 	 * manifest, NWAM is refreshed.  Also, setup signal handling to
3846ba597c5SAnurag S. Maskey 	 * catch the refresh signal.  Kill nwamd then and let svc.startd(1M)
3856ba597c5SAnurag S. Maskey 	 * start nwamd again (this time correctly as netadm).
3866ba597c5SAnurag S. Maskey 	 */
3876ba597c5SAnurag S. Maskey 	if (uid == 0) {
3886ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "Warning: Phase 1 properties not available yet");
3896ba597c5SAnurag S. Maskey 
3906ba597c5SAnurag S. Maskey 		daemonize();
3916ba597c5SAnurag S. Maskey 		init_signalhandling();
3926ba597c5SAnurag S. Maskey 		(void) pause();
3936ba597c5SAnurag S. Maskey 
3946ba597c5SAnurag S. Maskey 		return (EXIT_SUCCESS);
3956ba597c5SAnurag S. Maskey 	}
3966ba597c5SAnurag S. Maskey 
3976ba597c5SAnurag S. Maskey 	if (uid != UID_NETADM) {
3986ba597c5SAnurag S. Maskey 		/*
3996ba597c5SAnurag S. Maskey 		 * This shouldn't happen normally.  On upgrade the service might
4006ba597c5SAnurag S. Maskey 		 * need reloading.
4016ba597c5SAnurag S. Maskey 		 */
4026ba597c5SAnurag S. Maskey 		pfail("nwamd should run as uid %d, not uid %d\n", UID_NETADM,
4036ba597c5SAnurag S. Maskey 		    uid);
4046ba597c5SAnurag S. Maskey 	}
405d71dbb73Sjbeck 
406d71dbb73Sjbeck 	(void) setlocale(LC_ALL, "");
407d71dbb73Sjbeck 	(void) textdomain(TEXT_DOMAIN);
408d71dbb73Sjbeck 
409d71dbb73Sjbeck 	start_logging();
4106ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "nwamd pid %d started", getpid());
411d71dbb73Sjbeck 
412d71dbb73Sjbeck 	while ((c = getopt(argc, argv, "fs:")) != -1) {
413d71dbb73Sjbeck 		switch (c) {
414d71dbb73Sjbeck 			case 'f':
415d71dbb73Sjbeck 				fg = B_TRUE;
416d71dbb73Sjbeck 				break;
417d71dbb73Sjbeck 			default:
4186ba597c5SAnurag S. Maskey 				nlog(LOG_ERR, "unrecognized option %c",
419d71dbb73Sjbeck 				    optopt);
420d71dbb73Sjbeck 				break;
421d71dbb73Sjbeck 		}
422d71dbb73Sjbeck 	}
423d71dbb73Sjbeck 
424d71dbb73Sjbeck 	lookup_daemon_properties();
425d71dbb73Sjbeck 
426d71dbb73Sjbeck 	if (!fg)
427d71dbb73Sjbeck 		daemonize();
428d71dbb73Sjbeck 
4296ba597c5SAnurag S. Maskey 	/*
4306ba597c5SAnurag S. Maskey 	 * The dladm handle *must* be opened before privileges are dropped.
4316ba597c5SAnurag S. Maskey 	 * The device privilege requirements, which are stored in
4326ba597c5SAnurag S. Maskey 	 * /etc/security/device_policy, may not be loaded yet, as that's
4336ba597c5SAnurag S. Maskey 	 * done by svc:/system/filesystem/root.  If they are not loaded,
4346ba597c5SAnurag S. Maskey 	 * then one must have *all* privs in order to open /dev/dld, which
4356ba597c5SAnurag S. Maskey 	 * is one of the steps performed in dladm_open().
4366ba597c5SAnurag S. Maskey 	 */
4376ba597c5SAnurag S. Maskey 	rc = dladm_open(&dld_handle);
4386ba597c5SAnurag S. Maskey 	if (rc != DLADM_STATUS_OK) {
4396ba597c5SAnurag S. Maskey 		char status_str[DLADM_STRSIZE];
4406ba597c5SAnurag S. Maskey 		(void) dladm_status2str(rc, status_str);
4416ba597c5SAnurag S. Maskey 		pfail("failed to open dladm handle: %s", status_str);
4426ba597c5SAnurag S. Maskey 	}
4436ba597c5SAnurag S. Maskey 
4446ba597c5SAnurag S. Maskey 	/*
4456ba597c5SAnurag S. Maskey 	 * Handle upgrade of legacy config.  Absence of version property
4466ba597c5SAnurag S. Maskey 	 * (which did not exist in phase 0 or 0.5) is the indication that
4476ba597c5SAnurag S. Maskey 	 * we need to upgrade to phase 1 (version 1).
4486ba597c5SAnurag S. Maskey 	 */
4496ba597c5SAnurag S. Maskey 	if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG, OUR_VERSION_PROP_NAME,
4506ba597c5SAnurag S. Maskey 	    &version) != 0)
4516ba597c5SAnurag S. Maskey 		nwamd_handle_upgrade(NULL);
4526ba597c5SAnurag S. Maskey 
4536ba597c5SAnurag S. Maskey 	/*
4546ba597c5SAnurag S. Maskey 	 * Initialize lists handling internal representations of objects.
4556ba597c5SAnurag S. Maskey 	 */
4566ba597c5SAnurag S. Maskey 	nwamd_object_lists_init();
4576ba597c5SAnurag S. Maskey 
4586ba597c5SAnurag S. Maskey 	/*
4596ba597c5SAnurag S. Maskey 	 * Start the event handling thread before starting event sources,
4606ba597c5SAnurag S. Maskey 	 * including signal handling, so we are ready to handle incoming
4616ba597c5SAnurag S. Maskey 	 * events.
4626ba597c5SAnurag S. Maskey 	 */
4636ba597c5SAnurag S. Maskey 	nwamd_event_queue_init();
464b00044a2SJames Carlson 
465d71dbb73Sjbeck 	init_signalhandling();
466d71dbb73Sjbeck 
4676ba597c5SAnurag S. Maskey 	/* Enqueue init event */
4686ba597c5SAnurag S. Maskey 	event = nwamd_event_init_init();
4696ba597c5SAnurag S. Maskey 	if (event == NULL)
4706ba597c5SAnurag S. Maskey 		pfail("nwamd could not create init event, exiting");
4716ba597c5SAnurag S. Maskey 	nwamd_event_enqueue(event);
4726ba597c5SAnurag S. Maskey 	/*
4736ba597c5SAnurag S. Maskey 	 * Collect initial user configuration.
4746ba597c5SAnurag S. Maskey 	 */
475d71dbb73Sjbeck 
4766ba597c5SAnurag S. Maskey 	/*
4776ba597c5SAnurag S. Maskey 	 * Walk the physical interfaces and update the Automatic NCP to
4786ba597c5SAnurag S. Maskey 	 * contain the IP and link NCUs for the interfaces that exist in
4796ba597c5SAnurag S. Maskey 	 * the system.
4806ba597c5SAnurag S. Maskey 	 */
4816ba597c5SAnurag S. Maskey 	nwamd_walk_physical_configuration();
482d71dbb73Sjbeck 
4836ba597c5SAnurag S. Maskey 	/*
4846ba597c5SAnurag S. Maskey 	 * We should initialize the door at the point that we can respond to
4856ba597c5SAnurag S. Maskey 	 * user requests about the system but before we start actually process
4866ba597c5SAnurag S. Maskey 	 * state changes or effecting the system.
4876ba597c5SAnurag S. Maskey 	 */
4886ba597c5SAnurag S. Maskey 	nwamd_door_init();
489b00044a2SJames Carlson 
4906ba597c5SAnurag S. Maskey 	/*
4916ba597c5SAnurag S. Maskey 	 * Initialize data objects.
4926ba597c5SAnurag S. Maskey 	 *
4936ba597c5SAnurag S. Maskey 	 * Enabling an NCP involves refreshing nwam, which initializes the
4946ba597c5SAnurag S. Maskey 	 * objects (ncu, enm, loc, known wlan).  Thus, no need to
4956ba597c5SAnurag S. Maskey 	 * explicitly initialize these objects here.  The refresh also
4966ba597c5SAnurag S. Maskey 	 * enqueues and NCU activation checking event.  Location and ENM
4976ba597c5SAnurag S. Maskey 	 * condition checking are triggered by changes in NCU states.
4986ba597c5SAnurag S. Maskey 	 */
4996ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&active_ncp_mutex);
5006ba597c5SAnurag S. Maskey 	if (nwamd_ncp_action(active_ncp, NWAM_ACTION_ENABLE) != 0)
5016ba597c5SAnurag S. Maskey 		pfail("Initial enable failed for active NCP %s", active_ncp);
5026ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&active_ncp_mutex);
503d71dbb73Sjbeck 
5046ba597c5SAnurag S. Maskey 	/*
5056ba597c5SAnurag S. Maskey 	 * Enqueue an event to start periodic checking of activation conditions.
5066ba597c5SAnurag S. Maskey 	 */
5076ba597c5SAnurag S. Maskey 	nwamd_create_timed_condition_check_event();
508d71dbb73Sjbeck 
509*38f140aaSMichael Hunter 	/*
510*38f140aaSMichael Hunter 	 * These two routines safely minimize our privilege set.  They
511*38f140aaSMichael Hunter 	 * use reference counting to be safe in a threaded program.  It is
512*38f140aaSMichael Hunter 	 * gross that we escalate/deescalate to initialize this functionality
513*38f140aaSMichael Hunter 	 * but a real fix is to add functionality to do fine grained privs
514*38f140aaSMichael Hunter 	 * (and if necessary set uid to 0) in this threaded daemon.
515*38f140aaSMichael Hunter 	 */
516*38f140aaSMichael Hunter 	nwamd_escalate();
517*38f140aaSMichael Hunter 	nwamd_deescalate();
518*38f140aaSMichael Hunter 
5196ba597c5SAnurag S. Maskey 	/*
5206ba597c5SAnurag S. Maskey 	 * Start the various agents (hooks on fds, threads) which collect events
5216ba597c5SAnurag S. Maskey 	 */
5226ba597c5SAnurag S. Maskey 	nwamd_event_sources_init();
523b00044a2SJames Carlson 
5246ba597c5SAnurag S. Maskey 	/*
5256ba597c5SAnurag S. Maskey 	 * nwamd_event_handler() only returns on shutdown.
5266ba597c5SAnurag S. Maskey 	 */
5276ba597c5SAnurag S. Maskey 	nwamd_event_handler();
528d71dbb73Sjbeck 
5294ac67f02SAnurag S. Maskey 	dladm_close(dld_handle);
5306ba597c5SAnurag S. Maskey 
531b00044a2SJames Carlson 	return (EXIT_SUCCESS);
532d71dbb73Sjbeck }
533