d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * CDDL HEADER START
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * The contents of this file are subject to the terms of the
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * Common Development and Distribution License (the "License").
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * You may not use this file except in compliance with the License.
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * See the License for the specific language governing permissions
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * and limitations under the License.
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * When distributing Covered Code, include this CDDL HEADER in each
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * If applicable, add the following below this CDDL HEADER, with the
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * fields enclosed by brackets "[]" replaced with your own identifying
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * information: Portions Copyright [yyyy] [name of copyright owner]
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * CDDL HEADER END
71ed50cf049ab14d8e0ef8d48ba17d91223e81e7Anurag S. Maskey * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * nwamd - NetWork Auto-Magic Daemon
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskeystatic void nwamd_refresh(void);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskeystatic void graceful_shutdown(void);
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * This is the Network Auto-Magic daemon. For further high level information
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * see the Network Auto-Magic project and the Approachability communities
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * on opensolaris.org, nwamd(1M), and the README in the source directory.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * The general structure of the code is as a set of event source threads
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * which feed events into the event handling thread. Some of these events
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * are internal-only (e.g UPGRADE), but some also involve propogation
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * to external listeners (who register via a door call into the daemon).
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * signal management
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * Due to being threaded, a simple set of signal handlers would not work
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * very well for nwamd. Instead nwamd blocks signals in all but the
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * signal handling thread at startup.
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * In this file there are several utility functions which might otherwise
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * belong in util.c, but since they are only called from main(), they can
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * live here as static functions:
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * - nlog set-up
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * - daemonizing
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * - looking up SMF(5) properties
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * - signal handling
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * - managing privileges(5)
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * A little bit of magic here. By the first fork+setsid, we
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * disconnect from our current controlling terminal and become
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * a session group leader. By forking again without calling
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * setsid again, we make certain that we are not the session
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck * group leader and can never reacquire a controlling terminal.
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck if (pid != 0) {
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_DEBUG, "child %ld exited, daemonizing", pid);
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck if (pid != 0) {
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck/* ARGSUSED */
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeckstatic void *
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_DEBUG, "signal %s caught", strsignal(sig));
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck switch (sig) {
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Resumed from suspend or refresh. Clear up all
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * objects so their states start from scratch;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * then refresh().
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Undocumented "log ncu list" signal.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_DEBUG, "%s received, shutting down",
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_DEBUG, "unexpected signal %s received, "
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck if (err = pthread_create(&sighand, &attr, sighandler, NULL)) {
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_ERR, "pthread_create system: %s", strerror(err));
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_DEBUG, "signal handler thread: %d", sighand);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Construct the set of signals that we explicitly want to deal with.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * We block these while we're still single-threaded; this block will
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * be inherited by all the threads we create. When we are ready to
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * start handling signals, we will start the signal handling thread,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * which will sigwait() this same set of signals, and will thus receive
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * and handle any that are sent to the process.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_sigmask(SIG_BLOCK, &sigwaitset, &original_sigmask);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Look up nwamd property values and set daemon variables appropriately.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * This function will be called on startup and via the signal handling
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * thread on receiving a HUP (which occurs when the nwam service is
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * refreshed).
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey OUR_AUTOCONF_PROP_NAME, &wireless_autoconf);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey OUR_STRICT_BSSID_PROP_NAME, &wireless_strict_bssid);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if ((active_ncp_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey OUR_ACTIVE_NCP_PROP_NAME, active_ncp_tmp, NWAM_MAX_NAME_LEN) != 0) {
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) strlcpy(active_ncp, NWAM_NCP_NAME_AUTOMATIC,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) strlcpy(active_ncp, active_ncp_tmp, NWAM_MAX_NAME_LEN);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey condition_check_interval = CONDITION_CHECK_INTERVAL_DEFAULT;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if ((scan_level_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey OUR_WIRELESS_SCAN_LEVEL_PROP_NAME, scan_level_tmp,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey wireless_scan_level = WIRELESS_SCAN_LEVEL_DEFAULT;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if (dladm_wlan_str2strength(scan_level_tmp,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey wireless_scan_level = DLADM_WLAN_STRENGTH_VERY_WEAK;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey OUR_WIRELESS_SCAN_INTERVAL_PROP_NAME, &wireless_scan_interval) != 0)
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey OUR_NCU_WAIT_TIME_PROP_NAME, &ncu_wait_time) != 0)
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_DEBUG, "Read daemon configuration properties.");
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Re-read the SMF properties.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Reset ncu priority group (since the NCUs will have to walk
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * through their state machines again) and schedule a check
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Re-read objects from libnwam.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Also, run condition checking for locations and ENMs.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey current_ncu_priority_group = INVALID_PRIORITY_GROUP;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nwamd_create_triggered_condition_check_event(0);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey pfail("nwamd could not create shutdown event, exiting");
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Block the signals we care about (and which might cause us to
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * exit based on default disposition) until we're ready to start
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * handling them properly...see init_signalhandling() below.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * This shouldn't happen normally. On upgrade the service might
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * need reloading.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey pfail("nwamd should run as uid %d, not uid %d\n", UID_NETADM,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nlog(LOG_INFO, "nwamd pid %d started", getpid());
d71dbb732372504daff1f1783bc0d8864ce9bd50jbeck switch (c) {
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * The dladm handle *must* be opened before privileges are dropped.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * The device privilege requirements, which are stored in
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * /etc/security/device_policy, may not be loaded yet, as that's
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * done by svc:/system/filesystem/root. If they are not loaded,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * then one must have *all* privs in order to open /dev/dld, which
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * is one of the steps performed in dladm_open().
f6da83d4178694e7113b71d1e452f15b296f73d8Anurag S. Maskey pfail("failed to open ipadm handle: %s", ipadm_status2str(irc));
71ed50cf049ab14d8e0ef8d48ba17d91223e81e7Anurag S. Maskey * Create the event queue before starting event sources, including
71ed50cf049ab14d8e0ef8d48ba17d91223e81e7Anurag S. Maskey * signal handling, so we are ready to handle incoming events. Also
71ed50cf049ab14d8e0ef8d48ba17d91223e81e7Anurag S. Maskey * start before attempting to upgrade, in case there's a problem
71ed50cf049ab14d8e0ef8d48ba17d91223e81e7Anurag S. Maskey * upgrading and we need to retry (in which case we schedule an event
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Handle upgrade of legacy config. Absence of version property
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * (which did not exist in phase 0 or 0.5) is the indication that
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * we need to upgrade to phase 1 (version 1).
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG, OUR_VERSION_PROP_NAME,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Initialize lists handling internal representations of objects.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey /* Enqueue init event */
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey pfail("nwamd could not create init event, exiting");
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Collect initial user configuration.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Walk the physical interfaces and update the Automatic NCP to
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * contain the IP and link NCUs for the interfaces that exist in
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * the system.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * We should initialize the door at the point that we can respond to
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * user requests about the system but before we start actually process
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * state changes or effecting the system.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Initialize data objects.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Enabling an NCP involves refreshing nwam, which initializes the
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * objects (ncu, enm, loc, known wlan). Thus, no need to
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * explicitly initialize these objects here. The refresh also
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * enqueues and NCU activation checking event. Location and ENM
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * condition checking are triggered by changes in NCU states.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_mutex_lock(&active_ncp_mutex);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey if (nwamd_ncp_action(active_ncp, NWAM_ACTION_ENABLE) != 0)
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey pfail("Initial enable failed for active NCP %s", active_ncp);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey (void) pthread_mutex_unlock(&active_ncp_mutex);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Enqueue an event to start periodic checking of activation conditions.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey nwamd_create_timed_condition_check_event();
38f140aaa4a32508dc5318744dd8d51ab84b23a5Michael Hunter * These two routines safely minimize our privilege set. They
38f140aaa4a32508dc5318744dd8d51ab84b23a5Michael Hunter * use reference counting to be safe in a threaded program. It is
38f140aaa4a32508dc5318744dd8d51ab84b23a5Michael Hunter * gross that we escalate/deescalate to initialize this functionality
38f140aaa4a32508dc5318744dd8d51ab84b23a5Michael Hunter * but a real fix is to add functionality to do fine grained privs
38f140aaa4a32508dc5318744dd8d51ab84b23a5Michael Hunter * (and if necessary set uid to 0) in this threaded daemon.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Start the various agents (hooks on fds, threads) which collect events
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * nwamd_event_handler() only returns on shutdown.