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 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 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 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 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 * 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 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 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