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 /* 237c2ac481SAnurag S. Maskey * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24d71dbb73Sjbeck * Use is subject to license terms. 25d71dbb73Sjbeck */ 26d71dbb73Sjbeck 27d71dbb73Sjbeck /* 28d71dbb73Sjbeck * nwamd - NetWork Auto-Magic Daemon 29d71dbb73Sjbeck */ 30d71dbb73Sjbeck 31d71dbb73Sjbeck #include <fcntl.h> 32d71dbb73Sjbeck #include <priv.h> 33d71dbb73Sjbeck #include <pthread.h> 34d71dbb73Sjbeck #include <pwd.h> 35d71dbb73Sjbeck #include <stdio.h> 36d71dbb73Sjbeck #include <stdlib.h> 37d71dbb73Sjbeck #include <string.h> 38d71dbb73Sjbeck #include <signal.h> 39d71dbb73Sjbeck #include <sys/stat.h> 40d71dbb73Sjbeck #include <sys/types.h> 41d71dbb73Sjbeck #include <sys/wait.h> 42d71dbb73Sjbeck #include <syslog.h> 43d71dbb73Sjbeck #include <unistd.h> 44d71dbb73Sjbeck #include <locale.h> 45d71dbb73Sjbeck #include <libintl.h> 46d71dbb73Sjbeck #include <errno.h> 47d71dbb73Sjbeck 48d71dbb73Sjbeck #include "defines.h" 49d71dbb73Sjbeck #include "structures.h" 50d71dbb73Sjbeck #include "functions.h" 51d71dbb73Sjbeck #include "variables.h" 52d71dbb73Sjbeck 53d71dbb73Sjbeck #define TIMESPECGT(x, y) ((x.tv_sec > y.tv_sec) || \ 54d71dbb73Sjbeck ((x.tv_sec == y.tv_sec) && (x.tv_nsec > y.tv_nsec))) 55d71dbb73Sjbeck 56d71dbb73Sjbeck const char *OUR_FMRI = "svc:/network/physical:nwam"; 57d71dbb73Sjbeck const char *OUR_PG = "nwamd"; 58d71dbb73Sjbeck 59d71dbb73Sjbeck boolean_t fg = B_FALSE; 60d71dbb73Sjbeck boolean_t shutting_down; 61d71dbb73Sjbeck sigset_t original_sigmask; 62*8b2954c8SRenee Danson Sommerfeld static sigset_t sigwaitset; 63d71dbb73Sjbeck char zonename[ZONENAME_MAX]; 64b00044a2SJames Carlson pthread_mutex_t machine_lock = PTHREAD_MUTEX_INITIALIZER; 654ac67f02SAnurag S. Maskey dladm_handle_t dld_handle = NULL; 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 72d71dbb73Sjbeck * on opensolaris.org, and nwamd(1M). 73d71dbb73Sjbeck * 74d71dbb73Sjbeck * The general structure of the code is as a set of threads collecting 75d71dbb73Sjbeck * system events which are fed into a state machine which alters system 76d71dbb73Sjbeck * state based on configuration. 77d71dbb73Sjbeck * 78d71dbb73Sjbeck * signal management 79d71dbb73Sjbeck * Due to being threaded, a simple set of signal handlers would not work 80d71dbb73Sjbeck * very well for nwamd. Instead nwamd blocks signals at startup and 81d71dbb73Sjbeck * then starts a thread which sits in sigwait(2) waiting for signals. 82d71dbb73Sjbeck * When a signal is received the signal handling thread dispatches it. 83d71dbb73Sjbeck * It handles: 84d71dbb73Sjbeck * - shutting down, done by creating an event which is passed through the 85d71dbb73Sjbeck * system allowing the various subsystems to do any necessary cleanup. 86d71dbb73Sjbeck * - SIGALRM for timers. 87d71dbb73Sjbeck * - SIGHUP for instance refresh, which tells us to look up various 88d71dbb73Sjbeck * properties from SMF(5). 89d71dbb73Sjbeck * 90d71dbb73Sjbeck * subprocess management 91d71dbb73Sjbeck * nwamd starts several different subprocesses to manage the system. Some 92d71dbb73Sjbeck * of those start other processes (e.g. `ifconfig <if> dhcp` ends up starting 93d71dbb73Sjbeck * dhcpagent if necessary). Due to the way we manage signals if we started 94d71dbb73Sjbeck * those up without doing anything special their signal mask would mostly 95d71dbb73Sjbeck * block signals. So we restore the signal mask when we start subprocesses. 96d71dbb73Sjbeck * This is especially important with respect to DHCP as later when we exit 97d71dbb73Sjbeck * we need to kill the dhcpagent process which we started; for details, see 98d71dbb73Sjbeck * the block comment in state_machine.c in its cleanup() function. 99d71dbb73Sjbeck */ 100d71dbb73Sjbeck 101d71dbb73Sjbeck /* 102d71dbb73Sjbeck * In this file there are several utility functions which might otherwise 103d71dbb73Sjbeck * belong in util.c, but since they are only called from main(), they can 104d71dbb73Sjbeck * live here as static functions: 105d71dbb73Sjbeck * - syslog set-up 106d71dbb73Sjbeck * - daemonizing 107d71dbb73Sjbeck * - looking up SMF(5) properties 108d71dbb73Sjbeck * - signal handling 109d71dbb73Sjbeck * - managing privileges(5) 110d71dbb73Sjbeck */ 111d71dbb73Sjbeck 112d71dbb73Sjbeck static void 113d71dbb73Sjbeck start_logging(void) 114d71dbb73Sjbeck { 115d71dbb73Sjbeck openlog("nwamd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 116d71dbb73Sjbeck } 117d71dbb73Sjbeck 118d71dbb73Sjbeck static void 119d71dbb73Sjbeck daemonize(void) 120d71dbb73Sjbeck { 121d71dbb73Sjbeck pid_t pid; 122d71dbb73Sjbeck 123d71dbb73Sjbeck /* 124d71dbb73Sjbeck * A little bit of magic here. By the first fork+setsid, we 125d71dbb73Sjbeck * disconnect from our current controlling terminal and become 126d71dbb73Sjbeck * a session group leader. By forking again without calling 127d71dbb73Sjbeck * setsid again, we make certain that we are not the session 128d71dbb73Sjbeck * group leader and can never reacquire a controlling terminal. 129d71dbb73Sjbeck */ 130d71dbb73Sjbeck if ((pid = fork()) == (pid_t)-1) { 131d71dbb73Sjbeck syslog(LOG_ERR, "fork 1 failed"); 132d71dbb73Sjbeck exit(EXIT_FAILURE); 133d71dbb73Sjbeck } 134d71dbb73Sjbeck if (pid != 0) { 135d71dbb73Sjbeck (void) wait(NULL); 13610e672b7Smeem dprintf("child %ld exited, daemonizing", pid); 137d71dbb73Sjbeck _exit(0); 138d71dbb73Sjbeck } 139d71dbb73Sjbeck if (setsid() == (pid_t)-1) { 140d71dbb73Sjbeck syslog(LOG_ERR, "setsid"); 141d71dbb73Sjbeck exit(EXIT_FAILURE); 142d71dbb73Sjbeck } 143d71dbb73Sjbeck if ((pid = fork()) == (pid_t)-1) { 144d71dbb73Sjbeck syslog(LOG_ERR, "fork 2 failed"); 145d71dbb73Sjbeck exit(EXIT_FAILURE); 146d71dbb73Sjbeck } 147d71dbb73Sjbeck if (pid != 0) { 148d71dbb73Sjbeck _exit(0); 149d71dbb73Sjbeck } 150d71dbb73Sjbeck (void) chdir("/"); 151d71dbb73Sjbeck (void) umask(022); 152d71dbb73Sjbeck } 153d71dbb73Sjbeck 154d71dbb73Sjbeck /* 155d71dbb73Sjbeck * Look up nwamd property values and set daemon variables appropriately. 156d71dbb73Sjbeck * This function will be called on startup and via the signal handling 157d71dbb73Sjbeck * thread on receiving a HUP (which occurs when the nwam service is 158d71dbb73Sjbeck * refreshed). 159d71dbb73Sjbeck */ 160d71dbb73Sjbeck static void 161d71dbb73Sjbeck lookup_daemon_properties(void) 162d71dbb73Sjbeck { 163d71dbb73Sjbeck boolean_t debug_set; 164d71dbb73Sjbeck uint64_t scan_interval; 165b00044a2SJames Carlson uint64_t idle_time; 166ab32bdf2SJames Carlson boolean_t strict_bssid_set; 167d71dbb73Sjbeck 168d71dbb73Sjbeck if (lookup_boolean_property(OUR_PG, "debug", &debug_set) == 0) 169d71dbb73Sjbeck debug = debug_set; 170d71dbb73Sjbeck if (lookup_count_property(OUR_PG, "scan_interval", &scan_interval) == 0) 171d71dbb73Sjbeck wlan_scan_interval = scan_interval; 172b00044a2SJames Carlson if (lookup_count_property(OUR_PG, "idle_time", &idle_time) == 0) 173b00044a2SJames Carlson door_idle_time = idle_time; 174ab32bdf2SJames Carlson if (lookup_boolean_property(OUR_PG, "strict_bssid", 175ab32bdf2SJames Carlson &strict_bssid_set) == 0) 176ab32bdf2SJames Carlson strict_bssid = strict_bssid_set; 177d71dbb73Sjbeck dprintf("Read daemon configuration properties."); 178d71dbb73Sjbeck } 179d71dbb73Sjbeck 180d71dbb73Sjbeck /* ARGSUSED */ 181d71dbb73Sjbeck static void * 182d71dbb73Sjbeck sighandler(void *arg) 183d71dbb73Sjbeck { 184ab32bdf2SJames Carlson int sig, err; 185d71dbb73Sjbeck uint32_t now; 186d71dbb73Sjbeck 187b00044a2SJames Carlson while (!shutting_down) { 188*8b2954c8SRenee Danson Sommerfeld sig = sigwait(&sigwaitset); 189d71dbb73Sjbeck dprintf("signal %d caught", sig); 190d71dbb73Sjbeck switch (sig) { 191d71dbb73Sjbeck case SIGALRM: 192d71dbb73Sjbeck /* 193d71dbb73Sjbeck * We may have multiple interfaces with 194d71dbb73Sjbeck * scheduled timers; walk the list and 195d71dbb73Sjbeck * create a timer event for each one. 196d71dbb73Sjbeck */ 197d71dbb73Sjbeck timer_expire = TIMER_INFINITY; 198d71dbb73Sjbeck now = NSEC_TO_SEC(gethrtime()); 199b00044a2SJames Carlson check_interface_timers(now); 200b00044a2SJames Carlson check_door_life(now); 201d71dbb73Sjbeck break; 202d71dbb73Sjbeck case SIGHUP: 203d71dbb73Sjbeck /* 204d71dbb73Sjbeck * Refresh action - reread configuration properties. 205d71dbb73Sjbeck */ 206d71dbb73Sjbeck lookup_daemon_properties(); 207ab32bdf2SJames Carlson /* 208ab32bdf2SJames Carlson * Check if user restarted scanning. 209ab32bdf2SJames Carlson */ 210ab32bdf2SJames Carlson if (scan == 0 && wlan_scan_interval != 0) { 211ab32bdf2SJames Carlson err = pthread_create(&scan, NULL, 212ab32bdf2SJames Carlson periodic_wireless_scan, NULL); 213ab32bdf2SJames Carlson if (err != 0) { 214ab32bdf2SJames Carlson syslog(LOG_NOTICE, 215ab32bdf2SJames Carlson "pthread_create wireless scan: %s", 216ab32bdf2SJames Carlson strerror(err)); 217ab32bdf2SJames Carlson } else { 218ab32bdf2SJames Carlson dprintf("wireless scan thread: %d", 219ab32bdf2SJames Carlson scan); 220ab32bdf2SJames Carlson } 221ab32bdf2SJames Carlson } 222d71dbb73Sjbeck break; 223b00044a2SJames Carlson case SIGINT: 224b00044a2SJames Carlson /* 225b00044a2SJames Carlson * Undocumented "print debug status" signal. 226b00044a2SJames Carlson */ 227b00044a2SJames Carlson print_llp_status(); 228b00044a2SJames Carlson print_interface_status(); 229b00044a2SJames Carlson print_wireless_status(); 230b00044a2SJames Carlson break; 231ab32bdf2SJames Carlson case SIGTHAW: 232ab32bdf2SJames Carlson /* 233ab32bdf2SJames Carlson * It seems unlikely that this is helpful, but it can't 234ab32bdf2SJames Carlson * hurt: when waking up from a sleep, check if the 235ab32bdf2SJames Carlson * wireless interface is still viable. There've been 236ab32bdf2SJames Carlson * bugs in this area. 237ab32bdf2SJames Carlson */ 238ab32bdf2SJames Carlson if (pthread_mutex_lock(&machine_lock) == 0) { 239ab32bdf2SJames Carlson if (link_layer_profile != NULL && 240ab32bdf2SJames Carlson link_layer_profile->llp_type == 241ab32bdf2SJames Carlson IF_WIRELESS) { 242ab32bdf2SJames Carlson wireless_verify( 243ab32bdf2SJames Carlson link_layer_profile->llp_lname); 244ab32bdf2SJames Carlson } 245ab32bdf2SJames Carlson (void) pthread_mutex_unlock(&machine_lock); 246ab32bdf2SJames Carlson } 247ab32bdf2SJames Carlson break; 248*8b2954c8SRenee Danson Sommerfeld case SIGTERM: 249d71dbb73Sjbeck syslog(LOG_NOTICE, "%s received, shutting down", 250d71dbb73Sjbeck strsignal(sig)); 251d71dbb73Sjbeck shutting_down = B_TRUE; 252b00044a2SJames Carlson if (!np_queue_add_event(EV_SHUTDOWN, NULL)) { 253d71dbb73Sjbeck dprintf("could not allocate shutdown event"); 254d71dbb73Sjbeck cleanup(); 255d71dbb73Sjbeck exit(EXIT_FAILURE); 256d71dbb73Sjbeck } 257d71dbb73Sjbeck break; 258*8b2954c8SRenee Danson Sommerfeld default: 259*8b2954c8SRenee Danson Sommerfeld syslog(LOG_NOTICE, "unexpected signal %s received; " 260*8b2954c8SRenee Danson Sommerfeld "ignoring", strsignal(sig)); 261*8b2954c8SRenee Danson Sommerfeld break; 262d71dbb73Sjbeck } 263d71dbb73Sjbeck } 264b00044a2SJames Carlson return (NULL); 265d71dbb73Sjbeck } 266d71dbb73Sjbeck 267d71dbb73Sjbeck static void 268d71dbb73Sjbeck init_signalhandling(void) 269d71dbb73Sjbeck { 270d71dbb73Sjbeck pthread_attr_t attr; 271d71dbb73Sjbeck pthread_t sighand; 272d71dbb73Sjbeck int err; 273d71dbb73Sjbeck 274ab32bdf2SJames Carlson /* 275*8b2954c8SRenee Danson Sommerfeld * Construct the set of signals that we explicitly want 276*8b2954c8SRenee Danson Sommerfeld * to deal with. These will be blocked now, while we're 277*8b2954c8SRenee Danson Sommerfeld * still single-threaded; this block will be inherited by 278*8b2954c8SRenee Danson Sommerfeld * all the threads we create. The signal handling thread 279*8b2954c8SRenee Danson Sommerfeld * will then sigwait() this same set of signals, and will 280*8b2954c8SRenee Danson Sommerfeld * thus receive and process any that are sent to the process. 281ab32bdf2SJames Carlson */ 282*8b2954c8SRenee Danson Sommerfeld (void) sigemptyset(&sigwaitset); 283*8b2954c8SRenee Danson Sommerfeld (void) sigaddset(&sigwaitset, SIGHUP); 284*8b2954c8SRenee Danson Sommerfeld (void) sigaddset(&sigwaitset, SIGINT); 285*8b2954c8SRenee Danson Sommerfeld (void) sigaddset(&sigwaitset, SIGALRM); 286*8b2954c8SRenee Danson Sommerfeld (void) sigaddset(&sigwaitset, SIGTERM); 287*8b2954c8SRenee Danson Sommerfeld (void) sigaddset(&sigwaitset, SIGTHAW); 288*8b2954c8SRenee Danson Sommerfeld (void) pthread_sigmask(SIG_BLOCK, &sigwaitset, &original_sigmask); 289ab32bdf2SJames Carlson 290*8b2954c8SRenee Danson Sommerfeld /* 291*8b2954c8SRenee Danson Sommerfeld * now start the signal handling thread... 292*8b2954c8SRenee Danson Sommerfeld */ 293d71dbb73Sjbeck (void) pthread_attr_init(&attr); 294d71dbb73Sjbeck (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 295d71dbb73Sjbeck if (err = pthread_create(&sighand, &attr, sighandler, NULL)) { 296d71dbb73Sjbeck syslog(LOG_ERR, "pthread_create system: %s", strerror(err)); 297d71dbb73Sjbeck exit(EXIT_FAILURE); 298d71dbb73Sjbeck } else { 299d71dbb73Sjbeck dprintf("signal handler thread: %d", sighand); 300d71dbb73Sjbeck } 301d71dbb73Sjbeck (void) pthread_attr_destroy(&attr); 302d71dbb73Sjbeck } 303d71dbb73Sjbeck 304d71dbb73Sjbeck static void 305d71dbb73Sjbeck change_user_set_privs(void) 306d71dbb73Sjbeck { 307d71dbb73Sjbeck priv_set_t *priv_set; 308d71dbb73Sjbeck 309d71dbb73Sjbeck priv_set = priv_allocset(); 310d71dbb73Sjbeck if (getppriv(PRIV_PERMITTED, priv_set) == -1) { 311d71dbb73Sjbeck dprintf("getppriv %s", strerror(errno)); 312d71dbb73Sjbeck } else { 313d71dbb73Sjbeck char *p; 314d71dbb73Sjbeck 315d71dbb73Sjbeck p = priv_set_to_str(priv_set, ',', 0); 316d71dbb73Sjbeck dprintf("started with privs %s", p != NULL ? p : "Unknown"); 317d71dbb73Sjbeck free(p); 318d71dbb73Sjbeck } 3199b38c944Sokie priv_freeset(priv_set); 320d71dbb73Sjbeck 3219b38c944Sokie /* always start with the basic set */ 3229b38c944Sokie priv_set = priv_str_to_set("basic", ",", NULL); 3239b38c944Sokie if (priv_set == NULL) { 3249b38c944Sokie syslog(LOG_ERR, "converting basic privilege set: %m"); 3259b38c944Sokie exit(EXIT_FAILURE); 3269b38c944Sokie } 3279b38c944Sokie (void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF); 3289b38c944Sokie (void) priv_addset(priv_set, PRIV_FILE_DAC_READ); 3299b38c944Sokie (void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE); 3309b38c944Sokie (void) priv_addset(priv_set, PRIV_NET_PRIVADDR); 3319b38c944Sokie (void) priv_addset(priv_set, PRIV_NET_RAWACCESS); 332b00044a2SJames Carlson (void) priv_addset(priv_set, PRIV_PROC_AUDIT); 3339b38c944Sokie (void) priv_addset(priv_set, PRIV_PROC_OWNER); 3349b38c944Sokie (void) priv_addset(priv_set, PRIV_PROC_SETID); 335b00044a2SJames Carlson (void) priv_addset(priv_set, PRIV_SYS_CONFIG); 3369b38c944Sokie (void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG); 3379b38c944Sokie (void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG); 3389b38c944Sokie (void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG); 3399b38c944Sokie (void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG); 3409b38c944Sokie (void) priv_addset(priv_set, PRIV_SYS_RESOURCE); 341d71dbb73Sjbeck 342d71dbb73Sjbeck if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) { 343d71dbb73Sjbeck syslog(LOG_ERR, "setppriv inheritable: %m"); 344d71dbb73Sjbeck priv_freeset(priv_set); 345d71dbb73Sjbeck exit(EXIT_FAILURE); 346d71dbb73Sjbeck } 347d71dbb73Sjbeck 348d71dbb73Sjbeck if (setppriv(PRIV_SET, PRIV_PERMITTED, priv_set) == -1) { 349d71dbb73Sjbeck syslog(LOG_ERR, "setppriv permitted: %m"); 350d71dbb73Sjbeck priv_freeset(priv_set); 351d71dbb73Sjbeck exit(EXIT_FAILURE); 352d71dbb73Sjbeck } 353d71dbb73Sjbeck 354d71dbb73Sjbeck if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) { 355d71dbb73Sjbeck syslog(LOG_ERR, "setppriv effective: %m"); 356d71dbb73Sjbeck priv_freeset(priv_set); 357d71dbb73Sjbeck exit(EXIT_FAILURE); 358d71dbb73Sjbeck } 359d71dbb73Sjbeck 360d71dbb73Sjbeck priv_freeset(priv_set); 361d71dbb73Sjbeck } 362d71dbb73Sjbeck 363b00044a2SJames Carlson static void 364b00044a2SJames Carlson init_machine_mutex(void) 365b00044a2SJames Carlson { 366b00044a2SJames Carlson pthread_mutexattr_t attrs; 367b00044a2SJames Carlson 368b00044a2SJames Carlson (void) pthread_mutexattr_init(&attrs); 369b00044a2SJames Carlson (void) pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_ERRORCHECK); 370b00044a2SJames Carlson if (pthread_mutex_init(&machine_lock, &attrs) != 0) { 371b00044a2SJames Carlson syslog(LOG_ERR, "unable to set up machine lock"); 372b00044a2SJames Carlson exit(EXIT_FAILURE); 373b00044a2SJames Carlson } 374b00044a2SJames Carlson (void) pthread_mutexattr_destroy(&attrs); 375b00044a2SJames Carlson } 376b00044a2SJames Carlson 377d71dbb73Sjbeck int 378d71dbb73Sjbeck main(int argc, char *argv[]) 379d71dbb73Sjbeck { 380d71dbb73Sjbeck int c; 381d71dbb73Sjbeck int scan_lev; 382d71dbb73Sjbeck struct np_event *e; 383b00044a2SJames Carlson enum np_event_type etype; 384d71dbb73Sjbeck 385d71dbb73Sjbeck (void) setlocale(LC_ALL, ""); 386d71dbb73Sjbeck (void) textdomain(TEXT_DOMAIN); 387d71dbb73Sjbeck 388d71dbb73Sjbeck shutting_down = B_FALSE; 389d71dbb73Sjbeck start_logging(); 390d71dbb73Sjbeck syslog(LOG_INFO, "nwamd pid %d started", getpid()); 391d71dbb73Sjbeck 392d71dbb73Sjbeck while ((c = getopt(argc, argv, "fs:")) != -1) { 393d71dbb73Sjbeck switch (c) { 394d71dbb73Sjbeck case 'f': 395d71dbb73Sjbeck fg = B_TRUE; 396d71dbb73Sjbeck break; 397d71dbb73Sjbeck case 's': 398d71dbb73Sjbeck scan_lev = atoi(optarg); 399d71dbb73Sjbeck if (scan_lev >= DLADM_WLAN_STRENGTH_VERY_WEAK && 400d71dbb73Sjbeck scan_lev <= DLADM_WLAN_STRENGTH_EXCELLENT) { 401d71dbb73Sjbeck wireless_scan_level = scan_lev; 402d71dbb73Sjbeck } else { 403d71dbb73Sjbeck syslog(LOG_ERR, "invalid signal " 404d71dbb73Sjbeck "strength: %s", optarg); 405d71dbb73Sjbeck } 406d71dbb73Sjbeck break; 407d71dbb73Sjbeck default: 408d71dbb73Sjbeck syslog(LOG_ERR, "unrecognized option %c", 409d71dbb73Sjbeck optopt); 410d71dbb73Sjbeck break; 411d71dbb73Sjbeck } 412d71dbb73Sjbeck } 413d71dbb73Sjbeck 414d71dbb73Sjbeck lookup_daemon_properties(); 415d71dbb73Sjbeck 4167c2ac481SAnurag S. Maskey /* 4177c2ac481SAnurag S. Maskey * The dladm handle *must* be opened before privileges are dropped 4187c2ac481SAnurag S. Maskey * by nwamd. The device privilege requirements from 4197c2ac481SAnurag S. Maskey * /etc/security/device_policy may not be loaded yet. These are 4207c2ac481SAnurag S. Maskey * loaded by svc:/system/filesystem/root, which comes online after 4217c2ac481SAnurag S. Maskey * svc:/network/physical. 4227c2ac481SAnurag S. Maskey */ 4237c2ac481SAnurag S. Maskey if (dladm_open(&dld_handle) != DLADM_STATUS_OK) { 4247c2ac481SAnurag S. Maskey syslog(LOG_ERR, "failed to open dladm handle"); 4257c2ac481SAnurag S. Maskey exit(EXIT_FAILURE); 4267c2ac481SAnurag S. Maskey } 4277c2ac481SAnurag S. Maskey 428d71dbb73Sjbeck change_user_set_privs(); 429d71dbb73Sjbeck 430d71dbb73Sjbeck if (!fg) 431d71dbb73Sjbeck daemonize(); 432d71dbb73Sjbeck 433b00044a2SJames Carlson initialize_llp(); 434b00044a2SJames Carlson 435d71dbb73Sjbeck init_signalhandling(); 436d71dbb73Sjbeck 437b00044a2SJames Carlson initialize_wireless(); 438d71dbb73Sjbeck 439d71dbb73Sjbeck lookup_zonename(zonename, sizeof (zonename)); 440d71dbb73Sjbeck 441b00044a2SJames Carlson init_machine_mutex(); 442b00044a2SJames Carlson 443d71dbb73Sjbeck initialize_interfaces(); 444d71dbb73Sjbeck 445d71dbb73Sjbeck llp_parse_config(); 446d71dbb73Sjbeck 447b00044a2SJames Carlson initialize_door(); 448b00044a2SJames Carlson 449d71dbb73Sjbeck (void) start_event_collection(); 450d71dbb73Sjbeck 451b00044a2SJames Carlson while ((e = np_queue_get_event()) != NULL) { 452d71dbb73Sjbeck 453b00044a2SJames Carlson etype = e->npe_type; 454b00044a2SJames Carlson syslog(LOG_INFO, "got event type %s", npe_type_str(etype)); 455b00044a2SJames Carlson if (etype == EV_SHUTDOWN) 456b00044a2SJames Carlson terminate_door(); 457b00044a2SJames Carlson if (pthread_mutex_lock(&machine_lock) != 0) { 458b00044a2SJames Carlson syslog(LOG_ERR, "mutex lock"); 459b00044a2SJames Carlson exit(EXIT_FAILURE); 460b00044a2SJames Carlson } 461d71dbb73Sjbeck state_machine(e); 462b00044a2SJames Carlson (void) pthread_mutex_unlock(&machine_lock); 463d71dbb73Sjbeck free_event(e); 464b00044a2SJames Carlson if (etype == EV_SHUTDOWN) 465d71dbb73Sjbeck break; 466b00044a2SJames Carlson } 467b00044a2SJames Carlson syslog(LOG_DEBUG, "terminating routing and scanning threads"); 468d71dbb73Sjbeck (void) pthread_cancel(routing); 469d71dbb73Sjbeck (void) pthread_join(routing, NULL); 470ab32bdf2SJames Carlson if (scan != 0) { 471ab32bdf2SJames Carlson (void) pthread_cancel(scan); 472d71dbb73Sjbeck (void) pthread_join(scan, NULL); 473ab32bdf2SJames Carlson } 4744ac67f02SAnurag S. Maskey dladm_close(dld_handle); 475d71dbb73Sjbeck syslog(LOG_INFO, "nwamd shutting down"); 476b00044a2SJames Carlson return (EXIT_SUCCESS); 477d71dbb73Sjbeck } 478