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