xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/main.c (revision 8b2954c8fcce265225254a4269ebef6d1b29ce89)
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