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 }
252