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