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