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 /*
2371ed50cfSAnurag S. Maskey * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24d71dbb73Sjbeck */
25d71dbb73Sjbeck
266ba597c5SAnurag S. Maskey #include <errno.h>
276ba597c5SAnurag S. Maskey #include <fcntl.h>
286ba597c5SAnurag S. Maskey #include <libdllink.h>
296ba597c5SAnurag S. Maskey #include <libintl.h>
306ba597c5SAnurag S. Maskey #include <libnwam.h>
316ba597c5SAnurag S. Maskey #include <locale.h>
326ba597c5SAnurag S. Maskey #include <priv.h>
336ba597c5SAnurag S. Maskey #include <pthread.h>
346ba597c5SAnurag S. Maskey #include <signal.h>
356ba597c5SAnurag S. Maskey #include <stdio.h>
366ba597c5SAnurag S. Maskey #include <stdlib.h>
376ba597c5SAnurag S. Maskey #include <string.h>
386ba597c5SAnurag S. Maskey #include <sys/stat.h>
396ba597c5SAnurag S. Maskey #include <sys/types.h>
406ba597c5SAnurag S. Maskey #include <sys/wait.h>
416ba597c5SAnurag S. Maskey #include <unistd.h>
426ba597c5SAnurag S. Maskey
436ba597c5SAnurag S. Maskey #include <libnwam.h>
446ba597c5SAnurag S. Maskey #include "conditions.h"
456ba597c5SAnurag S. Maskey #include "events.h"
466ba597c5SAnurag S. Maskey #include "llp.h"
476ba597c5SAnurag S. Maskey #include "ncp.h"
486ba597c5SAnurag S. Maskey #include "objects.h"
496ba597c5SAnurag S. Maskey #include "util.h"
506ba597c5SAnurag S. Maskey
51d71dbb73Sjbeck /*
52d71dbb73Sjbeck * nwamd - NetWork Auto-Magic Daemon
53d71dbb73Sjbeck */
54d71dbb73Sjbeck
55d71dbb73Sjbeck boolean_t fg = B_FALSE;
566ba597c5SAnurag S. Maskey dladm_handle_t dld_handle = NULL;
57*f6da83d4SAnurag S. Maskey ipadm_handle_t ipadm_handle = NULL;
586ba597c5SAnurag S. Maskey boolean_t shutting_down = B_FALSE;
596ba597c5SAnurag S. Maskey
60d71dbb73Sjbeck sigset_t original_sigmask;
618b2954c8SRenee Danson Sommerfeld static sigset_t sigwaitset;
626ba597c5SAnurag S. Maskey
636ba597c5SAnurag S. Maskey static void nwamd_refresh(void);
646ba597c5SAnurag S. Maskey static void graceful_shutdown(void);
65d71dbb73Sjbeck
66d71dbb73Sjbeck /*
67d71dbb73Sjbeck * nwamd
68d71dbb73Sjbeck *
69d71dbb73Sjbeck * This is the Network Auto-Magic daemon. For further high level information
70d71dbb73Sjbeck * see the Network Auto-Magic project and the Approachability communities
716ba597c5SAnurag S. Maskey * on opensolaris.org, nwamd(1M), and the README in the source directory.
72d71dbb73Sjbeck *
736ba597c5SAnurag S. Maskey * The general structure of the code is as a set of event source threads
746ba597c5SAnurag S. Maskey * which feed events into the event handling thread. Some of these events
756ba597c5SAnurag S. Maskey * are internal-only (e.g UPGRADE), but some also involve propogation
766ba597c5SAnurag S. Maskey * to external listeners (who register via a door call into the daemon).
77d71dbb73Sjbeck *
78d71dbb73Sjbeck * signal management
79d71dbb73Sjbeck * Due to being threaded, a simple set of signal handlers would not work
806ba597c5SAnurag S. Maskey * very well for nwamd. Instead nwamd blocks signals in all but the
816ba597c5SAnurag S. Maskey * signal handling thread at startup.
82d71dbb73Sjbeck *
83d71dbb73Sjbeck */
84d71dbb73Sjbeck
85d71dbb73Sjbeck /*
86d71dbb73Sjbeck * In this file there are several utility functions which might otherwise
87d71dbb73Sjbeck * belong in util.c, but since they are only called from main(), they can
88d71dbb73Sjbeck * live here as static functions:
896ba597c5SAnurag S. Maskey * - nlog set-up
90d71dbb73Sjbeck * - daemonizing
91d71dbb73Sjbeck * - looking up SMF(5) properties
92d71dbb73Sjbeck * - signal handling
93d71dbb73Sjbeck * - managing privileges(5)
94d71dbb73Sjbeck */
95d71dbb73Sjbeck
96d71dbb73Sjbeck static void
start_logging(void)97d71dbb73Sjbeck start_logging(void)
98d71dbb73Sjbeck {
99d71dbb73Sjbeck openlog("nwamd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
100d71dbb73Sjbeck }
101d71dbb73Sjbeck
102d71dbb73Sjbeck static void
daemonize(void)103d71dbb73Sjbeck daemonize(void)
104d71dbb73Sjbeck {
105d71dbb73Sjbeck pid_t pid;
106d71dbb73Sjbeck
107d71dbb73Sjbeck /*
108d71dbb73Sjbeck * A little bit of magic here. By the first fork+setsid, we
109d71dbb73Sjbeck * disconnect from our current controlling terminal and become
110d71dbb73Sjbeck * a session group leader. By forking again without calling
111d71dbb73Sjbeck * setsid again, we make certain that we are not the session
112d71dbb73Sjbeck * group leader and can never reacquire a controlling terminal.
113d71dbb73Sjbeck */
1146ba597c5SAnurag S. Maskey if ((pid = fork()) == (pid_t)-1)
1156ba597c5SAnurag S. Maskey pfail("fork 1 failed");
116d71dbb73Sjbeck if (pid != 0) {
117d71dbb73Sjbeck (void) wait(NULL);
1186ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "child %ld exited, daemonizing", pid);
119d71dbb73Sjbeck _exit(0);
120d71dbb73Sjbeck }
1216ba597c5SAnurag S. Maskey if (setsid() == (pid_t)-1)
1226ba597c5SAnurag S. Maskey pfail("setsid");
1236ba597c5SAnurag S. Maskey if ((pid = fork()) == (pid_t)-1)
1246ba597c5SAnurag S. Maskey pfail("fork 2 failed");
125d71dbb73Sjbeck if (pid != 0) {
126d71dbb73Sjbeck _exit(0);
127d71dbb73Sjbeck }
128d71dbb73Sjbeck (void) chdir("/");
129d71dbb73Sjbeck (void) umask(022);
130d71dbb73Sjbeck }
131d71dbb73Sjbeck
132d71dbb73Sjbeck /* ARGSUSED */
133d71dbb73Sjbeck static void *
sighandler(void * arg)134d71dbb73Sjbeck sighandler(void *arg)
135d71dbb73Sjbeck {
1366ba597c5SAnurag S. Maskey int sig;
137d71dbb73Sjbeck
138b00044a2SJames Carlson while (!shutting_down) {
1398b2954c8SRenee Danson Sommerfeld sig = sigwait(&sigwaitset);
1406ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "signal %s caught", strsignal(sig));
1416ba597c5SAnurag S. Maskey
1426ba597c5SAnurag S. Maskey switch (sig) {
1436ba597c5SAnurag S. Maskey case SIGTHAW:
144d71dbb73Sjbeck case SIGHUP:
145d71dbb73Sjbeck /*
1466ba597c5SAnurag S. Maskey * Resumed from suspend or refresh. Clear up all
1476ba597c5SAnurag S. Maskey * objects so their states start from scratch;
1486ba597c5SAnurag S. Maskey * then refresh().
149d71dbb73Sjbeck */
1506ba597c5SAnurag S. Maskey nwamd_fini_enms();
1516ba597c5SAnurag S. Maskey nwamd_fini_ncus();
1526ba597c5SAnurag S. Maskey nwamd_fini_locs();
1536ba597c5SAnurag S. Maskey nwamd_refresh();
154d71dbb73Sjbeck break;
1556ba597c5SAnurag S. Maskey case SIGUSR1:
156b00044a2SJames Carlson /*
1576ba597c5SAnurag S. Maskey * Undocumented "log ncu list" signal.
158b00044a2SJames Carlson */
1596ba597c5SAnurag S. Maskey nwamd_log_ncus();
160ab32bdf2SJames Carlson break;
1618b2954c8SRenee Danson Sommerfeld case SIGTERM:
1626ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "%s received, shutting down",
163d71dbb73Sjbeck strsignal(sig));
1646ba597c5SAnurag S. Maskey graceful_shutdown();
165d71dbb73Sjbeck break;
1668b2954c8SRenee Danson Sommerfeld default:
1676ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "unexpected signal %s received, "
1688b2954c8SRenee Danson Sommerfeld "ignoring", strsignal(sig));
1698b2954c8SRenee Danson Sommerfeld break;
170d71dbb73Sjbeck }
171d71dbb73Sjbeck }
172b00044a2SJames Carlson return (NULL);
173d71dbb73Sjbeck }
174d71dbb73Sjbeck
175d71dbb73Sjbeck static void
init_signalhandling(void)176d71dbb73Sjbeck init_signalhandling(void)
177d71dbb73Sjbeck {
178d71dbb73Sjbeck pthread_attr_t attr;
179d71dbb73Sjbeck pthread_t sighand;
180d71dbb73Sjbeck int err;
181d71dbb73Sjbeck
182d71dbb73Sjbeck (void) pthread_attr_init(&attr);
183d71dbb73Sjbeck (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
184d71dbb73Sjbeck if (err = pthread_create(&sighand, &attr, sighandler, NULL)) {
1856ba597c5SAnurag S. Maskey nlog(LOG_ERR, "pthread_create system: %s", strerror(err));
186d71dbb73Sjbeck exit(EXIT_FAILURE);
187d71dbb73Sjbeck } else {
1886ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "signal handler thread: %d", sighand);
189d71dbb73Sjbeck }
190d71dbb73Sjbeck (void) pthread_attr_destroy(&attr);
191d71dbb73Sjbeck }
192d71dbb73Sjbeck
1936ba597c5SAnurag S. Maskey /*
1946ba597c5SAnurag S. Maskey * Construct the set of signals that we explicitly want to deal with.
1956ba597c5SAnurag S. Maskey * We block these while we're still single-threaded; this block will
1966ba597c5SAnurag S. Maskey * be inherited by all the threads we create. When we are ready to
1976ba597c5SAnurag S. Maskey * start handling signals, we will start the signal handling thread,
1986ba597c5SAnurag S. Maskey * which will sigwait() this same set of signals, and will thus receive
1996ba597c5SAnurag S. Maskey * and handle any that are sent to the process.
2006ba597c5SAnurag S. Maskey */
201d71dbb73Sjbeck static void
block_signals(void)2026ba597c5SAnurag S. Maskey block_signals(void)
203d71dbb73Sjbeck {
2046ba597c5SAnurag S. Maskey (void) sigemptyset(&sigwaitset);
2056ba597c5SAnurag S. Maskey (void) sigaddset(&sigwaitset, SIGHUP);
2066ba597c5SAnurag S. Maskey (void) sigaddset(&sigwaitset, SIGUSR1);
2076ba597c5SAnurag S. Maskey (void) sigaddset(&sigwaitset, SIGUSR2);
2086ba597c5SAnurag S. Maskey (void) sigaddset(&sigwaitset, SIGTERM);
2096ba597c5SAnurag S. Maskey (void) sigaddset(&sigwaitset, SIGTHAW);
2106ba597c5SAnurag S. Maskey (void) pthread_sigmask(SIG_BLOCK, &sigwaitset, &original_sigmask);
2116ba597c5SAnurag S. Maskey }
212d71dbb73Sjbeck
2136ba597c5SAnurag S. Maskey /*
2146ba597c5SAnurag S. Maskey * Look up nwamd property values and set daemon variables appropriately.
2156ba597c5SAnurag S. Maskey * This function will be called on startup and via the signal handling
2166ba597c5SAnurag S. Maskey * thread on receiving a HUP (which occurs when the nwam service is
2176ba597c5SAnurag S. Maskey * refreshed).
2186ba597c5SAnurag S. Maskey */
2196ba597c5SAnurag S. Maskey static void
lookup_daemon_properties(void)2206ba597c5SAnurag S. Maskey lookup_daemon_properties(void)
2216ba597c5SAnurag S. Maskey {
2226ba597c5SAnurag S. Maskey char *active_ncp_tmp;
2236ba597c5SAnurag S. Maskey char *scan_level_tmp;
2246ba597c5SAnurag S. Maskey
2256ba597c5SAnurag S. Maskey (void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
2266ba597c5SAnurag S. Maskey OUR_DEBUG_PROP_NAME, &debug);
2276ba597c5SAnurag S. Maskey (void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
2286ba597c5SAnurag S. Maskey OUR_AUTOCONF_PROP_NAME, &wireless_autoconf);
2296ba597c5SAnurag S. Maskey (void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
2306ba597c5SAnurag S. Maskey OUR_STRICT_BSSID_PROP_NAME, &wireless_strict_bssid);
2316ba597c5SAnurag S. Maskey
2326ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
2336ba597c5SAnurag S. Maskey if ((active_ncp_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
2346ba597c5SAnurag S. Maskey nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
2356ba597c5SAnurag S. Maskey OUR_ACTIVE_NCP_PROP_NAME, active_ncp_tmp, NWAM_MAX_NAME_LEN) != 0) {
2366ba597c5SAnurag S. Maskey (void) strlcpy(active_ncp, NWAM_NCP_NAME_AUTOMATIC,
2376ba597c5SAnurag S. Maskey NWAM_MAX_NAME_LEN);
238d71dbb73Sjbeck } else {
2396ba597c5SAnurag S. Maskey (void) strlcpy(active_ncp, active_ncp_tmp, NWAM_MAX_NAME_LEN);
2406ba597c5SAnurag S. Maskey }
2416ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
2426ba597c5SAnurag S. Maskey free(active_ncp_tmp);
243d71dbb73Sjbeck
2446ba597c5SAnurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
2456ba597c5SAnurag S. Maskey OUR_CONDITION_CHECK_INTERVAL_PROP_NAME,
2466ba597c5SAnurag S. Maskey &condition_check_interval) != 0)
2476ba597c5SAnurag S. Maskey condition_check_interval = CONDITION_CHECK_INTERVAL_DEFAULT;
2486ba597c5SAnurag S. Maskey
2496ba597c5SAnurag S. Maskey if ((scan_level_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
2506ba597c5SAnurag S. Maskey nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
2516ba597c5SAnurag S. Maskey OUR_WIRELESS_SCAN_LEVEL_PROP_NAME, scan_level_tmp,
2526ba597c5SAnurag S. Maskey NWAM_MAX_NAME_LEN) != 0) {
2536ba597c5SAnurag S. Maskey wireless_scan_level = WIRELESS_SCAN_LEVEL_DEFAULT;
2546ba597c5SAnurag S. Maskey } else {
2556ba597c5SAnurag S. Maskey if (dladm_wlan_str2strength(scan_level_tmp,
2566ba597c5SAnurag S. Maskey &wireless_scan_level) != DLADM_STATUS_OK)
2576ba597c5SAnurag S. Maskey wireless_scan_level = DLADM_WLAN_STRENGTH_VERY_WEAK;
2586ba597c5SAnurag S. Maskey }
2596ba597c5SAnurag S. Maskey free(scan_level_tmp);
2606ba597c5SAnurag S. Maskey
2616ba597c5SAnurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
2626ba597c5SAnurag S. Maskey OUR_WIRELESS_SCAN_INTERVAL_PROP_NAME, &wireless_scan_interval) != 0)
2636ba597c5SAnurag S. Maskey wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
2646ba597c5SAnurag S. Maskey
2656ba597c5SAnurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
2666ba597c5SAnurag S. Maskey OUR_NCU_WAIT_TIME_PROP_NAME, &ncu_wait_time) != 0)
2676ba597c5SAnurag S. Maskey ncu_wait_time = NCU_WAIT_TIME_DEFAULT;
2686ba597c5SAnurag S. Maskey
2696ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "Read daemon configuration properties.");
270d71dbb73Sjbeck }
271d71dbb73Sjbeck
2726ba597c5SAnurag S. Maskey /*
2736ba597c5SAnurag S. Maskey * Re-read the SMF properties.
2746ba597c5SAnurag S. Maskey * Reset ncu priority group (since the NCUs will have to walk
2756ba597c5SAnurag S. Maskey * through their state machines again) and schedule a check
2766ba597c5SAnurag S. Maskey * Re-read objects from libnwam.
2776ba597c5SAnurag S. Maskey * Also, run condition checking for locations and ENMs.
2786ba597c5SAnurag S. Maskey */
2796ba597c5SAnurag S. Maskey static void
nwamd_refresh(void)2806ba597c5SAnurag S. Maskey nwamd_refresh(void)
2816ba597c5SAnurag S. Maskey {
2826ba597c5SAnurag S. Maskey lookup_daemon_properties();
283d71dbb73Sjbeck
2846ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
2856ba597c5SAnurag S. Maskey current_ncu_priority_group = INVALID_PRIORITY_GROUP;
2866ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
287d71dbb73Sjbeck
2886ba597c5SAnurag S. Maskey nwamd_init_ncus();
2896ba597c5SAnurag S. Maskey nwamd_init_enms();
2906ba597c5SAnurag S. Maskey nwamd_init_locs();
291d71dbb73Sjbeck
2926ba597c5SAnurag S. Maskey nwamd_create_ncu_check_event(0);
2936ba597c5SAnurag S. Maskey nwamd_create_triggered_condition_check_event(0);
294d71dbb73Sjbeck }
295d71dbb73Sjbeck
296b00044a2SJames Carlson static void
graceful_shutdown(void)2976ba597c5SAnurag S. Maskey graceful_shutdown(void)
298b00044a2SJames Carlson {
2996ba597c5SAnurag S. Maskey nwamd_event_t event;
300b00044a2SJames Carlson
3016ba597c5SAnurag S. Maskey shutting_down = B_TRUE;
3026ba597c5SAnurag S. Maskey nwamd_event_sources_fini();
3036ba597c5SAnurag S. Maskey nwamd_door_fini();
3046ba597c5SAnurag S. Maskey nwamd_fini_enms();
3056ba597c5SAnurag S. Maskey nwamd_fini_ncus();
3066ba597c5SAnurag S. Maskey nwamd_fini_locs();
3076ba597c5SAnurag S. Maskey
3086ba597c5SAnurag S. Maskey event = nwamd_event_init_shutdown();
3096ba597c5SAnurag S. Maskey if (event == NULL)
3106ba597c5SAnurag S. Maskey pfail("nwamd could not create shutdown event, exiting");
3116ba597c5SAnurag S. Maskey nwamd_event_enqueue(event);
312b00044a2SJames Carlson }
313b00044a2SJames Carlson
314d71dbb73Sjbeck int
main(int argc,char * argv[])315d71dbb73Sjbeck main(int argc, char *argv[])
316d71dbb73Sjbeck {
317d71dbb73Sjbeck int c;
3186ba597c5SAnurag S. Maskey uint64_t version;
3196ba597c5SAnurag S. Maskey nwamd_event_t event;
320*f6da83d4SAnurag S. Maskey dladm_status_t drc;
321*f6da83d4SAnurag S. Maskey ipadm_status_t irc;
3226ba597c5SAnurag S. Maskey uid_t uid = getuid();
3236ba597c5SAnurag S. Maskey
3246ba597c5SAnurag S. Maskey /*
3256ba597c5SAnurag S. Maskey * Block the signals we care about (and which might cause us to
3266ba597c5SAnurag S. Maskey * exit based on default disposition) until we're ready to start
3276ba597c5SAnurag S. Maskey * handling them properly...see init_signalhandling() below.
3286ba597c5SAnurag S. Maskey */
3296ba597c5SAnurag S. Maskey block_signals();
3306ba597c5SAnurag S. Maskey
33169b43529SMichael Hunter if (uid != UID_NETADM && uid != 0) {
3326ba597c5SAnurag S. Maskey /*
3336ba597c5SAnurag S. Maskey * This shouldn't happen normally. On upgrade the service might
3346ba597c5SAnurag S. Maskey * need reloading.
3356ba597c5SAnurag S. Maskey */
3366ba597c5SAnurag S. Maskey pfail("nwamd should run as uid %d, not uid %d\n", UID_NETADM,
3376ba597c5SAnurag S. Maskey uid);
3386ba597c5SAnurag S. Maskey }
339d71dbb73Sjbeck
340d71dbb73Sjbeck (void) setlocale(LC_ALL, "");
341d71dbb73Sjbeck (void) textdomain(TEXT_DOMAIN);
342d71dbb73Sjbeck
343d71dbb73Sjbeck start_logging();
3446ba597c5SAnurag S. Maskey nlog(LOG_INFO, "nwamd pid %d started", getpid());
345d71dbb73Sjbeck
346d71dbb73Sjbeck while ((c = getopt(argc, argv, "fs:")) != -1) {
347d71dbb73Sjbeck switch (c) {
348d71dbb73Sjbeck case 'f':
349d71dbb73Sjbeck fg = B_TRUE;
350d71dbb73Sjbeck break;
351d71dbb73Sjbeck default:
3526ba597c5SAnurag S. Maskey nlog(LOG_ERR, "unrecognized option %c",
353d71dbb73Sjbeck optopt);
354d71dbb73Sjbeck break;
355d71dbb73Sjbeck }
356d71dbb73Sjbeck }
357d71dbb73Sjbeck
358d71dbb73Sjbeck lookup_daemon_properties();
359d71dbb73Sjbeck
360d71dbb73Sjbeck if (!fg)
361d71dbb73Sjbeck daemonize();
362d71dbb73Sjbeck
3636ba597c5SAnurag S. Maskey /*
3646ba597c5SAnurag S. Maskey * The dladm handle *must* be opened before privileges are dropped.
3656ba597c5SAnurag S. Maskey * The device privilege requirements, which are stored in
3666ba597c5SAnurag S. Maskey * /etc/security/device_policy, may not be loaded yet, as that's
3676ba597c5SAnurag S. Maskey * done by svc:/system/filesystem/root. If they are not loaded,
3686ba597c5SAnurag S. Maskey * then one must have *all* privs in order to open /dev/dld, which
3696ba597c5SAnurag S. Maskey * is one of the steps performed in dladm_open().
3706ba597c5SAnurag S. Maskey */
371*f6da83d4SAnurag S. Maskey drc = dladm_open(&dld_handle);
372*f6da83d4SAnurag S. Maskey if (drc != DLADM_STATUS_OK) {
3736ba597c5SAnurag S. Maskey char status_str[DLADM_STRSIZE];
374*f6da83d4SAnurag S. Maskey pfail("failed to open dladm handle: %s",
375*f6da83d4SAnurag S. Maskey dladm_status2str(drc, status_str));
3766ba597c5SAnurag S. Maskey }
3776ba597c5SAnurag S. Maskey
378*f6da83d4SAnurag S. Maskey irc = ipadm_open(&ipadm_handle, 0);
379*f6da83d4SAnurag S. Maskey if (irc != IPADM_SUCCESS)
380*f6da83d4SAnurag S. Maskey pfail("failed to open ipadm handle: %s", ipadm_status2str(irc));
381*f6da83d4SAnurag S. Maskey
3826ba597c5SAnurag S. Maskey /*
38371ed50cfSAnurag S. Maskey * Create the event queue before starting event sources, including
38471ed50cfSAnurag S. Maskey * signal handling, so we are ready to handle incoming events. Also
38571ed50cfSAnurag S. Maskey * start before attempting to upgrade, in case there's a problem
38671ed50cfSAnurag S. Maskey * upgrading and we need to retry (in which case we schedule an event
38771ed50cfSAnurag S. Maskey * to do so).
38871ed50cfSAnurag S. Maskey */
38971ed50cfSAnurag S. Maskey nwamd_event_queue_init();
39071ed50cfSAnurag S. Maskey
39171ed50cfSAnurag S. Maskey /*
3926ba597c5SAnurag S. Maskey * Handle upgrade of legacy config. Absence of version property
3936ba597c5SAnurag S. Maskey * (which did not exist in phase 0 or 0.5) is the indication that
3946ba597c5SAnurag S. Maskey * we need to upgrade to phase 1 (version 1).
3956ba597c5SAnurag S. Maskey */
3966ba597c5SAnurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG, OUR_VERSION_PROP_NAME,
3976ba597c5SAnurag S. Maskey &version) != 0)
3986ba597c5SAnurag S. Maskey nwamd_handle_upgrade(NULL);
3996ba597c5SAnurag S. Maskey
4006ba597c5SAnurag S. Maskey /*
4016ba597c5SAnurag S. Maskey * Initialize lists handling internal representations of objects.
4026ba597c5SAnurag S. Maskey */
4036ba597c5SAnurag S. Maskey nwamd_object_lists_init();
4046ba597c5SAnurag S. Maskey
405d71dbb73Sjbeck init_signalhandling();
406d71dbb73Sjbeck
4076ba597c5SAnurag S. Maskey /* Enqueue init event */
4086ba597c5SAnurag S. Maskey event = nwamd_event_init_init();
4096ba597c5SAnurag S. Maskey if (event == NULL)
4106ba597c5SAnurag S. Maskey pfail("nwamd could not create init event, exiting");
4116ba597c5SAnurag S. Maskey nwamd_event_enqueue(event);
41271ed50cfSAnurag S. Maskey
4136ba597c5SAnurag S. Maskey /*
4146ba597c5SAnurag S. Maskey * Collect initial user configuration.
4156ba597c5SAnurag S. Maskey */
416d71dbb73Sjbeck
4176ba597c5SAnurag S. Maskey /*
4186ba597c5SAnurag S. Maskey * Walk the physical interfaces and update the Automatic NCP to
4196ba597c5SAnurag S. Maskey * contain the IP and link NCUs for the interfaces that exist in
4206ba597c5SAnurag S. Maskey * the system.
4216ba597c5SAnurag S. Maskey */
4226ba597c5SAnurag S. Maskey nwamd_walk_physical_configuration();
423d71dbb73Sjbeck
4246ba597c5SAnurag S. Maskey /*
4256ba597c5SAnurag S. Maskey * We should initialize the door at the point that we can respond to
4266ba597c5SAnurag S. Maskey * user requests about the system but before we start actually process
4276ba597c5SAnurag S. Maskey * state changes or effecting the system.
4286ba597c5SAnurag S. Maskey */
4296ba597c5SAnurag S. Maskey nwamd_door_init();
430b00044a2SJames Carlson
4316ba597c5SAnurag S. Maskey /*
4326ba597c5SAnurag S. Maskey * Initialize data objects.
4336ba597c5SAnurag S. Maskey *
4346ba597c5SAnurag S. Maskey * Enabling an NCP involves refreshing nwam, which initializes the
4356ba597c5SAnurag S. Maskey * objects (ncu, enm, loc, known wlan). Thus, no need to
4366ba597c5SAnurag S. Maskey * explicitly initialize these objects here. The refresh also
4376ba597c5SAnurag S. Maskey * enqueues and NCU activation checking event. Location and ENM
4386ba597c5SAnurag S. Maskey * condition checking are triggered by changes in NCU states.
4396ba597c5SAnurag S. Maskey */
4406ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
4416ba597c5SAnurag S. Maskey if (nwamd_ncp_action(active_ncp, NWAM_ACTION_ENABLE) != 0)
4426ba597c5SAnurag S. Maskey pfail("Initial enable failed for active NCP %s", active_ncp);
4436ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
444d71dbb73Sjbeck
4456ba597c5SAnurag S. Maskey /*
4466ba597c5SAnurag S. Maskey * Enqueue an event to start periodic checking of activation conditions.
4476ba597c5SAnurag S. Maskey */
4486ba597c5SAnurag S. Maskey nwamd_create_timed_condition_check_event();
449d71dbb73Sjbeck
45038f140aaSMichael Hunter /*
45138f140aaSMichael Hunter * These two routines safely minimize our privilege set. They
45238f140aaSMichael Hunter * use reference counting to be safe in a threaded program. It is
45338f140aaSMichael Hunter * gross that we escalate/deescalate to initialize this functionality
45438f140aaSMichael Hunter * but a real fix is to add functionality to do fine grained privs
45538f140aaSMichael Hunter * (and if necessary set uid to 0) in this threaded daemon.
45638f140aaSMichael Hunter */
45738f140aaSMichael Hunter nwamd_escalate();
45838f140aaSMichael Hunter nwamd_deescalate();
45938f140aaSMichael Hunter
4606ba597c5SAnurag S. Maskey /*
4616ba597c5SAnurag S. Maskey * Start the various agents (hooks on fds, threads) which collect events
4626ba597c5SAnurag S. Maskey */
4636ba597c5SAnurag S. Maskey nwamd_event_sources_init();
464b00044a2SJames Carlson
4656ba597c5SAnurag S. Maskey /*
4666ba597c5SAnurag S. Maskey * nwamd_event_handler() only returns on shutdown.
4676ba597c5SAnurag S. Maskey */
4686ba597c5SAnurag S. Maskey nwamd_event_handler();
469d71dbb73Sjbeck
470*f6da83d4SAnurag S. Maskey ipadm_close(ipadm_handle);
4714ac67f02SAnurag S. Maskey dladm_close(dld_handle);
4726ba597c5SAnurag S. Maskey
473b00044a2SJames Carlson return (EXIT_SUCCESS);
474d71dbb73Sjbeck }
475