1*4eaa4710SRishi Srivatsavai /*
2*4eaa4710SRishi Srivatsavai  * CDDL HEADER START
3*4eaa4710SRishi Srivatsavai  *
4*4eaa4710SRishi Srivatsavai  * The contents of this file are subject to the terms of the
5*4eaa4710SRishi Srivatsavai  * Common Development and Distribution License (the "License").
6*4eaa4710SRishi Srivatsavai  * You may not use this file except in compliance with the License.
7*4eaa4710SRishi Srivatsavai  *
8*4eaa4710SRishi Srivatsavai  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4eaa4710SRishi Srivatsavai  * or http://www.opensolaris.org/os/licensing.
10*4eaa4710SRishi Srivatsavai  * See the License for the specific language governing permissions
11*4eaa4710SRishi Srivatsavai  * and limitations under the License.
12*4eaa4710SRishi Srivatsavai  *
13*4eaa4710SRishi Srivatsavai  * When distributing Covered Code, include this CDDL HEADER in each
14*4eaa4710SRishi Srivatsavai  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4eaa4710SRishi Srivatsavai  * If applicable, add the following below this CDDL HEADER, with the
16*4eaa4710SRishi Srivatsavai  * fields enclosed by brackets "[]" replaced with your own identifying
17*4eaa4710SRishi Srivatsavai  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4eaa4710SRishi Srivatsavai  *
19*4eaa4710SRishi Srivatsavai  * CDDL HEADER END
20*4eaa4710SRishi Srivatsavai  */
21*4eaa4710SRishi Srivatsavai 
22*4eaa4710SRishi Srivatsavai /*
23*4eaa4710SRishi Srivatsavai  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*4eaa4710SRishi Srivatsavai  * Use is subject to license terms.
25*4eaa4710SRishi Srivatsavai  */
26*4eaa4710SRishi Srivatsavai 
27*4eaa4710SRishi Srivatsavai /*
28*4eaa4710SRishi Srivatsavai  * bridged - bridging control daemon.
29*4eaa4710SRishi Srivatsavai  */
30*4eaa4710SRishi Srivatsavai 
31*4eaa4710SRishi Srivatsavai #include <assert.h>
32*4eaa4710SRishi Srivatsavai #include <stdio.h>
33*4eaa4710SRishi Srivatsavai #include <stdlib.h>
34*4eaa4710SRishi Srivatsavai #include <unistd.h>
35*4eaa4710SRishi Srivatsavai #include <pthread.h>
36*4eaa4710SRishi Srivatsavai #include <string.h>
37*4eaa4710SRishi Srivatsavai #include <signal.h>
38*4eaa4710SRishi Srivatsavai #include <sys/stat.h>
39*4eaa4710SRishi Srivatsavai #include <sys/types.h>
40*4eaa4710SRishi Srivatsavai #include <sys/wait.h>
41*4eaa4710SRishi Srivatsavai #include <syslog.h>
42*4eaa4710SRishi Srivatsavai #include <locale.h>
43*4eaa4710SRishi Srivatsavai #include <stropts.h>
44*4eaa4710SRishi Srivatsavai 
45*4eaa4710SRishi Srivatsavai #include "global.h"
46*4eaa4710SRishi Srivatsavai 
47*4eaa4710SRishi Srivatsavai boolean_t debugging;
48*4eaa4710SRishi Srivatsavai uint32_t tablemax;
49*4eaa4710SRishi Srivatsavai const char *instance_name = "default";
50*4eaa4710SRishi Srivatsavai 
51*4eaa4710SRishi Srivatsavai struct pollfd *fdarray;
52*4eaa4710SRishi Srivatsavai 
53*4eaa4710SRishi Srivatsavai dladm_handle_t dlhandle;
54*4eaa4710SRishi Srivatsavai 
55*4eaa4710SRishi Srivatsavai boolean_t shutting_down;
56*4eaa4710SRishi Srivatsavai 
57*4eaa4710SRishi Srivatsavai static pthread_t sighand;
58*4eaa4710SRishi Srivatsavai 
59*4eaa4710SRishi Srivatsavai /*
60*4eaa4710SRishi Srivatsavai  * engine_lock is held while the main loop is busy calling librstp functions.
61*4eaa4710SRishi Srivatsavai  * Door threads take the lock to protect the library from reentrancy.
62*4eaa4710SRishi Srivatsavai  */
63*4eaa4710SRishi Srivatsavai static pthread_mutex_t engine_lock = PTHREAD_MUTEX_INITIALIZER;
64*4eaa4710SRishi Srivatsavai 
65*4eaa4710SRishi Srivatsavai /*
66*4eaa4710SRishi Srivatsavai  * These wrapper functions allow the other components in the daemon to remain
67*4eaa4710SRishi Srivatsavai  * ignorant of pthreads details.
68*4eaa4710SRishi Srivatsavai  */
69*4eaa4710SRishi Srivatsavai int
lock_engine(void)70*4eaa4710SRishi Srivatsavai lock_engine(void)
71*4eaa4710SRishi Srivatsavai {
72*4eaa4710SRishi Srivatsavai 	return (pthread_mutex_lock(&engine_lock));
73*4eaa4710SRishi Srivatsavai }
74*4eaa4710SRishi Srivatsavai 
75*4eaa4710SRishi Srivatsavai void
unlock_engine(void)76*4eaa4710SRishi Srivatsavai unlock_engine(void)
77*4eaa4710SRishi Srivatsavai {
78*4eaa4710SRishi Srivatsavai 	(void) pthread_mutex_unlock(&engine_lock);
79*4eaa4710SRishi Srivatsavai }
80*4eaa4710SRishi Srivatsavai 
81*4eaa4710SRishi Srivatsavai /*
82*4eaa4710SRishi Srivatsavai  * Utility function for STREAMS ioctls.
83*4eaa4710SRishi Srivatsavai  */
84*4eaa4710SRishi Srivatsavai ssize_t
strioctl(int fd,int cmd,void * buf,size_t buflen)85*4eaa4710SRishi Srivatsavai strioctl(int fd, int cmd, void *buf, size_t buflen)
86*4eaa4710SRishi Srivatsavai {
87*4eaa4710SRishi Srivatsavai 	int retv;
88*4eaa4710SRishi Srivatsavai 	struct strioctl ic;
89*4eaa4710SRishi Srivatsavai 
90*4eaa4710SRishi Srivatsavai 	ic.ic_cmd = cmd;
91*4eaa4710SRishi Srivatsavai 	ic.ic_timout = 0;
92*4eaa4710SRishi Srivatsavai 	ic.ic_dp = buf;
93*4eaa4710SRishi Srivatsavai 	ic.ic_len = buflen;
94*4eaa4710SRishi Srivatsavai 	if ((retv = ioctl(fd, I_STR, &ic)) != 0)
95*4eaa4710SRishi Srivatsavai 		return (retv);
96*4eaa4710SRishi Srivatsavai 	else
97*4eaa4710SRishi Srivatsavai 		return (ic.ic_len);
98*4eaa4710SRishi Srivatsavai }
99*4eaa4710SRishi Srivatsavai 
100*4eaa4710SRishi Srivatsavai static void
daemonize(void)101*4eaa4710SRishi Srivatsavai daemonize(void)
102*4eaa4710SRishi Srivatsavai {
103*4eaa4710SRishi Srivatsavai 	pid_t pid;
104*4eaa4710SRishi Srivatsavai 
105*4eaa4710SRishi Srivatsavai 	/*
106*4eaa4710SRishi Srivatsavai 	 * A little bit of magic here.  By the first fork+setsid, we
107*4eaa4710SRishi Srivatsavai 	 * disconnect from our current controlling terminal and become
108*4eaa4710SRishi Srivatsavai 	 * a session group leader.  By forking again without calling
109*4eaa4710SRishi Srivatsavai 	 * setsid again, we make certain that we are not the session
110*4eaa4710SRishi Srivatsavai 	 * group leader and can never reacquire a controlling terminal.
111*4eaa4710SRishi Srivatsavai 	 */
112*4eaa4710SRishi Srivatsavai 	if ((pid = fork()) == (pid_t)-1) {
113*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "fork 1 failed");
114*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
115*4eaa4710SRishi Srivatsavai 	}
116*4eaa4710SRishi Srivatsavai 	if (pid != 0) {
117*4eaa4710SRishi Srivatsavai 		(void) wait(NULL);
118*4eaa4710SRishi Srivatsavai 		_exit(EXIT_SUCCESS);
119*4eaa4710SRishi Srivatsavai 	}
120*4eaa4710SRishi Srivatsavai 	if (setsid() == (pid_t)-1) {
121*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "setsid");
122*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
123*4eaa4710SRishi Srivatsavai 	}
124*4eaa4710SRishi Srivatsavai 	if ((pid = fork()) == (pid_t)-1) {
125*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "fork 2 failed");
126*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
127*4eaa4710SRishi Srivatsavai 	}
128*4eaa4710SRishi Srivatsavai 	if (pid != 0)
129*4eaa4710SRishi Srivatsavai 		_exit(EXIT_SUCCESS);
130*4eaa4710SRishi Srivatsavai 	(void) chdir("/");
131*4eaa4710SRishi Srivatsavai 	(void) umask(022);
132*4eaa4710SRishi Srivatsavai }
133*4eaa4710SRishi Srivatsavai 
134*4eaa4710SRishi Srivatsavai static void *
sighandler(void * arg)135*4eaa4710SRishi Srivatsavai sighandler(void *arg)
136*4eaa4710SRishi Srivatsavai {
137*4eaa4710SRishi Srivatsavai 	sigset_t sigset;
138*4eaa4710SRishi Srivatsavai 	int sig;
139*4eaa4710SRishi Srivatsavai 	int sigfd = (int)(uintptr_t)arg;
140*4eaa4710SRishi Srivatsavai 
141*4eaa4710SRishi Srivatsavai 	(void) sigfillset(&sigset);
142*4eaa4710SRishi Srivatsavai 
143*4eaa4710SRishi Srivatsavai 	for (;;) {
144*4eaa4710SRishi Srivatsavai 		sig = sigwait(&sigset);
145*4eaa4710SRishi Srivatsavai 		switch (sig) {
146*4eaa4710SRishi Srivatsavai 		case SIGHUP:
147*4eaa4710SRishi Srivatsavai 			(void) write(sigfd, "", 1);
148*4eaa4710SRishi Srivatsavai 			break;
149*4eaa4710SRishi Srivatsavai 
150*4eaa4710SRishi Srivatsavai 		default:
151*4eaa4710SRishi Srivatsavai 			if (debugging)
152*4eaa4710SRishi Srivatsavai 				syslog(LOG_NOTICE, "%s signal, shutting down",
153*4eaa4710SRishi Srivatsavai 				    strsignal(sig));
154*4eaa4710SRishi Srivatsavai 			shutting_down = B_TRUE;
155*4eaa4710SRishi Srivatsavai 			break;
156*4eaa4710SRishi Srivatsavai 		}
157*4eaa4710SRishi Srivatsavai 
158*4eaa4710SRishi Srivatsavai 		/* if we're shutting down, exit this thread */
159*4eaa4710SRishi Srivatsavai 		if (shutting_down)
160*4eaa4710SRishi Srivatsavai 			return (NULL);
161*4eaa4710SRishi Srivatsavai 	}
162*4eaa4710SRishi Srivatsavai }
163*4eaa4710SRishi Srivatsavai 
164*4eaa4710SRishi Srivatsavai static void
init_signalhandling(void)165*4eaa4710SRishi Srivatsavai init_signalhandling(void)
166*4eaa4710SRishi Srivatsavai {
167*4eaa4710SRishi Srivatsavai 	pthread_attr_t attr;
168*4eaa4710SRishi Srivatsavai 	int err;
169*4eaa4710SRishi Srivatsavai 	sigset_t new;
170*4eaa4710SRishi Srivatsavai 	int fildes[2];
171*4eaa4710SRishi Srivatsavai 
172*4eaa4710SRishi Srivatsavai 	if ((fdarray = malloc(FDOFFSET * sizeof (struct pollfd))) == NULL) {
173*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "unable to allocate fdarray: %m");
174*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
175*4eaa4710SRishi Srivatsavai 	}
176*4eaa4710SRishi Srivatsavai 	if (pipe(fildes) != 0) {
177*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "unable to create signal pipe: %m");
178*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
179*4eaa4710SRishi Srivatsavai 	}
180*4eaa4710SRishi Srivatsavai 	fdarray[0].fd = fildes[0];
181*4eaa4710SRishi Srivatsavai 	fdarray[0].events = POLLIN;
182*4eaa4710SRishi Srivatsavai 	assert(control_fd != -1);
183*4eaa4710SRishi Srivatsavai 	fdarray[1].fd = control_fd;
184*4eaa4710SRishi Srivatsavai 	fdarray[1].events = POLLIN;
185*4eaa4710SRishi Srivatsavai 
186*4eaa4710SRishi Srivatsavai 	(void) sigfillset(&new);
187*4eaa4710SRishi Srivatsavai 	(void) pthread_sigmask(SIG_BLOCK, &new, NULL);
188*4eaa4710SRishi Srivatsavai 	(void) pthread_attr_init(&attr);
189*4eaa4710SRishi Srivatsavai 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
190*4eaa4710SRishi Srivatsavai 	err = pthread_create(&sighand, &attr, sighandler,
191*4eaa4710SRishi Srivatsavai 	    (void *)(uintptr_t)fildes[1]);
192*4eaa4710SRishi Srivatsavai 	if (err != 0) {
193*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "cannot create signal handling thread: %s",
194*4eaa4710SRishi Srivatsavai 		    strerror(err));
195*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
196*4eaa4710SRishi Srivatsavai 	}
197*4eaa4710SRishi Srivatsavai 	(void) pthread_attr_destroy(&attr);
198*4eaa4710SRishi Srivatsavai }
199*4eaa4710SRishi Srivatsavai 
200*4eaa4710SRishi Srivatsavai int
main(int argc,char ** argv)201*4eaa4710SRishi Srivatsavai main(int argc, char **argv)
202*4eaa4710SRishi Srivatsavai {
203*4eaa4710SRishi Srivatsavai 	dladm_status_t status;
204*4eaa4710SRishi Srivatsavai 	char buf[DLADM_STRSIZE];
205*4eaa4710SRishi Srivatsavai 
206*4eaa4710SRishi Srivatsavai 	(void) setlocale(LC_ALL, "");
207*4eaa4710SRishi Srivatsavai 	(void) textdomain(TEXT_DOMAIN);
208*4eaa4710SRishi Srivatsavai 
209*4eaa4710SRishi Srivatsavai 	shutting_down = B_FALSE;
210*4eaa4710SRishi Srivatsavai 	openlog("bridged", LOG_PID | LOG_NDELAY, LOG_DAEMON);
211*4eaa4710SRishi Srivatsavai 
212*4eaa4710SRishi Srivatsavai 	if (argc != 2) {
213*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "instance name is required");
214*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
215*4eaa4710SRishi Srivatsavai 	}
216*4eaa4710SRishi Srivatsavai 
217*4eaa4710SRishi Srivatsavai 	instance_name = argv[1];
218*4eaa4710SRishi Srivatsavai 
219*4eaa4710SRishi Srivatsavai 	if ((status = dladm_open(&dlhandle)) != DLADM_STATUS_OK) {
220*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "%s: unable to open datalink control: %s",
221*4eaa4710SRishi Srivatsavai 		    instance_name, dladm_status2str(status, buf));
222*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
223*4eaa4710SRishi Srivatsavai 	}
224*4eaa4710SRishi Srivatsavai 
225*4eaa4710SRishi Srivatsavai 	status = dladm_bridge_get_privprop(instance_name, &debugging,
226*4eaa4710SRishi Srivatsavai 	    &tablemax);
227*4eaa4710SRishi Srivatsavai 	if (status != DLADM_STATUS_OK) {
228*4eaa4710SRishi Srivatsavai 		syslog(LOG_ERR, "%s: unable to read properties: %s",
229*4eaa4710SRishi Srivatsavai 		    instance_name, dladm_status2str(status, buf));
230*4eaa4710SRishi Srivatsavai 		exit(EXIT_FAILURE);
231*4eaa4710SRishi Srivatsavai 	}
232*4eaa4710SRishi Srivatsavai 
233*4eaa4710SRishi Srivatsavai 	/* Get the properties once so that we have the right initial values */
234*4eaa4710SRishi Srivatsavai 	rstp_init();
235*4eaa4710SRishi Srivatsavai 
236*4eaa4710SRishi Srivatsavai 	open_bridge_control();
237*4eaa4710SRishi Srivatsavai 
238*4eaa4710SRishi Srivatsavai 	daemonize();
239*4eaa4710SRishi Srivatsavai 
240*4eaa4710SRishi Srivatsavai 	init_signalhandling();
241*4eaa4710SRishi Srivatsavai 	init_door();
242*4eaa4710SRishi Srivatsavai 
243*4eaa4710SRishi Srivatsavai 	if (debugging)
244*4eaa4710SRishi Srivatsavai 		syslog(LOG_INFO, "bridged started: instance %s", instance_name);
245*4eaa4710SRishi Srivatsavai 
246*4eaa4710SRishi Srivatsavai 	event_loop();
247*4eaa4710SRishi Srivatsavai 	(void) pthread_cancel(sighand);
248*4eaa4710SRishi Srivatsavai 	(void) pthread_join(sighand, NULL);
249*4eaa4710SRishi Srivatsavai 
250*4eaa4710SRishi Srivatsavai 	return (0);
251*4eaa4710SRishi Srivatsavai }