1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate /* 29*0Sstevel@tonic-gate * This code implements the Starfire Virtual Console host daemon 30*0Sstevel@tonic-gate * (see cvcd(1M)). It accepts a connection from netcon_server 31*0Sstevel@tonic-gate * and transfers console I/O to/from the SSP across the 32*0Sstevel@tonic-gate * network via TLI. The I/O is sent to the cvcredir device 33*0Sstevel@tonic-gate * on the host (see cvc(7) and cvcredir(7)). It also sends 34*0Sstevel@tonic-gate * disconnect and break ioctl's to the kernel CVC drivers. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #include <stdio.h> 41*0Sstevel@tonic-gate #include <stdarg.h> 42*0Sstevel@tonic-gate #include <syslog.h> 43*0Sstevel@tonic-gate #include <stdlib.h> 44*0Sstevel@tonic-gate #include <tiuser.h> 45*0Sstevel@tonic-gate #include <sys/timod.h> 46*0Sstevel@tonic-gate #include <fcntl.h> 47*0Sstevel@tonic-gate #include <sys/param.h> 48*0Sstevel@tonic-gate #include <sys/utsname.h> 49*0Sstevel@tonic-gate #include <sys/stat.h> 50*0Sstevel@tonic-gate #include <unistd.h> 51*0Sstevel@tonic-gate #include <stropts.h> 52*0Sstevel@tonic-gate #include <sys/conf.h> 53*0Sstevel@tonic-gate #include <pwd.h> 54*0Sstevel@tonic-gate #include <errno.h> 55*0Sstevel@tonic-gate #include <sys/socket.h> 56*0Sstevel@tonic-gate #include <arpa/inet.h> 57*0Sstevel@tonic-gate #include <locale.h> 58*0Sstevel@tonic-gate #include <termio.h> 59*0Sstevel@tonic-gate #include <signal.h> 60*0Sstevel@tonic-gate #include <sys/cvc.h> 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #include <string.h> 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate #include <sys/ioctl.h> 65*0Sstevel@tonic-gate #include <sys/file.h> 66*0Sstevel@tonic-gate #include <sys/sockio.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #include <sys/tihdr.h> 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate #include <netdb.h> 71*0Sstevel@tonic-gate #include <net/if.h> 72*0Sstevel@tonic-gate #include <netinet/if_ether.h> 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #include <inet/common.h> 75*0Sstevel@tonic-gate #include <sys/systeminfo.h> 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /* Process priority control */ 78*0Sstevel@tonic-gate #include <sys/priocntl.h> 79*0Sstevel@tonic-gate #include <sys/tspriocntl.h> 80*0Sstevel@tonic-gate #include <sys/rtpriocntl.h> 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * Misc. defines. 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate #define CONREF "connection request from illegal host" 86*0Sstevel@tonic-gate #define SSPHOSTNAMEFILE "/etc/ssphostname" 87*0Sstevel@tonic-gate #define NODENAME "/etc/nodename" 88*0Sstevel@tonic-gate #define MAXIFS 256 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* 91*0Sstevel@tonic-gate * Function prototypes 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate static void cvcd_connect(int fd, struct pollfd *); 94*0Sstevel@tonic-gate static void cvcd_reject(int fd); 95*0Sstevel@tonic-gate static void cvcd_read(struct pollfd *); 96*0Sstevel@tonic-gate static void cvcd_write(char *data, int size); 97*0Sstevel@tonic-gate static void cvcd_status(int fd); 98*0Sstevel@tonic-gate static void cvcd_winch(int, char *, int); 99*0Sstevel@tonic-gate static void cvcd_ioctl(int fd, int cmd); 100*0Sstevel@tonic-gate static void cvcd_err(int code, char *format, ...); 101*0Sstevel@tonic-gate static void usage(void); 102*0Sstevel@tonic-gate static id_t schedinfo(char *name, short *maxpri); 103*0Sstevel@tonic-gate static void cvcd_setopt(int fd, int name); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * Globals 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate static int rconsfd; /* Console redirection driver */ 109*0Sstevel@tonic-gate static char progname[MAXPATHLEN]; 110*0Sstevel@tonic-gate static char ssphostname[MAXPATHLEN]; 111*0Sstevel@tonic-gate static int debug = 0; 112*0Sstevel@tonic-gate static int connected = 0; 113*0Sstevel@tonic-gate static int peercheck = 1; 114*0Sstevel@tonic-gate static char nic_name[32]; 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate main(int argc, char **argv) 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate int opt; 119*0Sstevel@tonic-gate int tport = 0; 120*0Sstevel@tonic-gate char *hostname; 121*0Sstevel@tonic-gate struct utsname utsname; 122*0Sstevel@tonic-gate struct t_info tinfo; 123*0Sstevel@tonic-gate int cvcd_ssp; 124*0Sstevel@tonic-gate int nfd; 125*0Sstevel@tonic-gate struct pollfd *cvcd_pfd; 126*0Sstevel@tonic-gate int i; 127*0Sstevel@tonic-gate int j; 128*0Sstevel@tonic-gate struct servent *se; 129*0Sstevel@tonic-gate struct sockaddr_in *sin; 130*0Sstevel@tonic-gate struct t_bind *reqb; 131*0Sstevel@tonic-gate struct t_bind *retb; 132*0Sstevel@tonic-gate struct t_optmgmt *topt, *tropt; 133*0Sstevel@tonic-gate struct opthdr *sockopt; 134*0Sstevel@tonic-gate int on = 1; 135*0Sstevel@tonic-gate int tmperr = 0; 136*0Sstevel@tonic-gate int event; 137*0Sstevel@tonic-gate char prefix[256]; 138*0Sstevel@tonic-gate pcparms_t pcparms; 139*0Sstevel@tonic-gate tsparms_t *tsparmsp; 140*0Sstevel@tonic-gate id_t pid, tsID; 141*0Sstevel@tonic-gate short tsmaxpri; 142*0Sstevel@tonic-gate static int netcon_fail = 0; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 145*0Sstevel@tonic-gate (void) strcpy(progname, argv[0]); 146*0Sstevel@tonic-gate (void) memset(ssphostname, 0, MAXPATHLEN); 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if ((cvcd_ssp = open(SSPHOSTNAMEFILE, O_RDONLY)) < 0) { 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * If there is no /etc/ssphostname disable peer check after 151*0Sstevel@tonic-gate * issuing warning. 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate tmperr = errno; 154*0Sstevel@tonic-gate peercheck = 0; 155*0Sstevel@tonic-gate } else { 156*0Sstevel@tonic-gate if ((i = read(cvcd_ssp, ssphostname, MAXPATHLEN)) < 0) { 157*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "failed to read ssphostname"); 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * The ssp-config(1M) command newline terminates the 161*0Sstevel@tonic-gate * ssphostname in the /etc/ssphostname file 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate ssphostname[i-1] = '\0'; 164*0Sstevel@tonic-gate (void) close(cvcd_ssp); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate (void) memset(nic_name, 0, sizeof (nic_name)); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate #if defined(DEBUG) 170*0Sstevel@tonic-gate while ((opt = getopt(argc, argv, "dp:r:")) != EOF) { 171*0Sstevel@tonic-gate #else 172*0Sstevel@tonic-gate while ((opt = getopt(argc, argv, "r:")) != EOF) { 173*0Sstevel@tonic-gate #endif /* DEBUG */ 174*0Sstevel@tonic-gate switch (opt) { 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate #if defined(DEBUG) 177*0Sstevel@tonic-gate case 'd' : debug = 1; 178*0Sstevel@tonic-gate break; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate case 'p' : tport = atoi(optarg); 181*0Sstevel@tonic-gate break; 182*0Sstevel@tonic-gate #endif /* DEBUG */ 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate case 'r' : (void) strcpy(ssphostname, optarg); 185*0Sstevel@tonic-gate break; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate default : usage(); 188*0Sstevel@tonic-gate exit(1); 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate if (uname(&utsname) == -1) { 193*0Sstevel@tonic-gate perror("HOSTNAME not defined"); 194*0Sstevel@tonic-gate exit(1); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate hostname = utsname.nodename; 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate /* 199*0Sstevel@tonic-gate * hostname may still be NULL, depends on when cvcd was started 200*0Sstevel@tonic-gate * in the boot sequence. If it is NULL, try one more time 201*0Sstevel@tonic-gate * to get a hostname -> look in the /etc/nodename file. 202*0Sstevel@tonic-gate */ 203*0Sstevel@tonic-gate if (!strlen(hostname)) { 204*0Sstevel@tonic-gate /* 205*0Sstevel@tonic-gate * try to get the hostname from the /etc/nodename file 206*0Sstevel@tonic-gate * we reuse the utsname.nodename buffer here! hostname 207*0Sstevel@tonic-gate * already points to it. 208*0Sstevel@tonic-gate */ 209*0Sstevel@tonic-gate if ((nfd = open(NODENAME, O_RDONLY)) > 0) { 210*0Sstevel@tonic-gate if ((i = read(nfd, utsname.nodename, SYS_NMLN)) <= 0) { 211*0Sstevel@tonic-gate cvcd_err(LOG_WARNING, 212*0Sstevel@tonic-gate "failed to acquire hostname"); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate utsname.nodename[i-1] = '\0'; 215*0Sstevel@tonic-gate (void) close(nfd); 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate /* 220*0Sstevel@tonic-gate * Must be root. 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate if (debug == 0 && geteuid() != 0) { 223*0Sstevel@tonic-gate fprintf(stderr, "cvcd: Must be root"); 224*0Sstevel@tonic-gate exit(1); 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate /* 228*0Sstevel@tonic-gate * Daemonize... 229*0Sstevel@tonic-gate */ 230*0Sstevel@tonic-gate if (debug == 0) { 231*0Sstevel@tonic-gate for (i = 0; i < NOFILE; i++) { 232*0Sstevel@tonic-gate (void) close(i); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate (void) chdir("/"); 235*0Sstevel@tonic-gate (void) umask(0); 236*0Sstevel@tonic-gate if (fork() != 0) { 237*0Sstevel@tonic-gate exit(0); 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate (void) setpgrp(); 240*0Sstevel@tonic-gate (void) sprintf(prefix, "%s-(HOSTNAME:%s)", progname, hostname); 241*0Sstevel@tonic-gate openlog(prefix, LOG_CONS | LOG_NDELAY, LOG_LOCAL0); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate if (peercheck == 0) { 244*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "open(SSPHOSTNAMEFILE):%s", 245*0Sstevel@tonic-gate strerror(tmperr)); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate cvcd_pfd = (struct pollfd *)malloc(3*sizeof (struct pollfd)); 249*0Sstevel@tonic-gate if (cvcd_pfd == (struct pollfd *)NULL) { 250*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "malloc:", strerror(errno)); 251*0Sstevel@tonic-gate exit(1); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate (void) memset((void *)cvcd_pfd, 0, 3*sizeof (struct pollfd)); 254*0Sstevel@tonic-gate cvcd_pfd[0].fd = -1; 255*0Sstevel@tonic-gate cvcd_pfd[1].fd = -1; 256*0Sstevel@tonic-gate cvcd_pfd[2].fd = -1; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* SPR 94004 */ 259*0Sstevel@tonic-gate (void) sigignore(SIGTERM); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * SPR 83644: cvc and kadb are not compatible under heavy loads. 263*0Sstevel@tonic-gate * Fix: will give cvcd highest TS priority at execution time. 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate pid = getpid(); 266*0Sstevel@tonic-gate pcparms.pc_cid = PC_CLNULL; 267*0Sstevel@tonic-gate tsparmsp = (tsparms_t *)pcparms.pc_clparms; 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate /* Get scheduler properties for this PID */ 270*0Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_GETPARMS, (caddr_t)&pcparms) == -1L) { 271*0Sstevel@tonic-gate cvcd_err(LOG_ERR, 272*0Sstevel@tonic-gate "cvcd: GETPARMS failed. Warning: can't get ", 273*0Sstevel@tonic-gate "TS priorities."); 274*0Sstevel@tonic-gate } else { 275*0Sstevel@tonic-gate /* Get class IDs and maximum priorities for a TS process */ 276*0Sstevel@tonic-gate if ((tsID = schedinfo("TS", &tsmaxpri)) == -1) { 277*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd: Warning, can't get ", 278*0Sstevel@tonic-gate "TS scheduler info."); 279*0Sstevel@tonic-gate } else { 280*0Sstevel@tonic-gate if (debug) { /* Print priority info */ 281*0Sstevel@tonic-gate if (pcparms.pc_cid == tsID) { 282*0Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "%s%d%s%d%s%d\n", 283*0Sstevel@tonic-gate "cvcd:: PID:", pid, 284*0Sstevel@tonic-gate ", TS priority:", 285*0Sstevel@tonic-gate tsparmsp->ts_upri, 286*0Sstevel@tonic-gate ", TS max_pri:", tsmaxpri); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate /* Change proc's priority to maxtspri */ 290*0Sstevel@tonic-gate pcparms.pc_cid = tsID; 291*0Sstevel@tonic-gate tsparmsp = (struct tsparms *)pcparms.pc_clparms; 292*0Sstevel@tonic-gate tsparmsp->ts_upri = tsmaxpri; 293*0Sstevel@tonic-gate tsparmsp->ts_uprilim = tsmaxpri; 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_SETPARMS, 296*0Sstevel@tonic-gate (caddr_t)&pcparms) == -1L) { 297*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd: Warning, ", 298*0Sstevel@tonic-gate "can't set TS maximum priority."); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate /* Done */ 301*0Sstevel@tonic-gate if (debug) { /* Get new scheduler properties for PID */ 302*0Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_GETPARMS, 303*0Sstevel@tonic-gate (caddr_t)&pcparms) == -1L) { 304*0Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "GETPARMS failed"); 305*0Sstevel@tonic-gate exit(1); 306*0Sstevel@tonic-gate } else { 307*0Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "%s%d%s%d%s%d\n", 308*0Sstevel@tonic-gate "cvcd:: PID:", pid, 309*0Sstevel@tonic-gate ", New TS priority:", 310*0Sstevel@tonic-gate tsparmsp->ts_upri, 311*0Sstevel@tonic-gate ", TS max_pri:", tsmaxpri); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate if (debug == 1) { 318*0Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "tport = %d, debug = %d", tport, debug); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate if (tport == 0) { 322*0Sstevel@tonic-gate if ((se = getservbyname(CVCD_SERVICE, "tcp")) == NULL) { 323*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "getservbyname(%s) not found", 324*0Sstevel@tonic-gate CVCD_SERVICE); 325*0Sstevel@tonic-gate exit(1); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate tport = se->s_port; 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate cvcd_ssp = t_open(TCP_DEV, O_RDWR, &tinfo); 331*0Sstevel@tonic-gate if (cvcd_ssp == -1) { 332*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_open: %s", t_errlist[t_errno]); 333*0Sstevel@tonic-gate exit(1); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * Set the SO_REUSEADDR option for this TLI endpoint. 338*0Sstevel@tonic-gate */ 339*0Sstevel@tonic-gate cvcd_setopt(cvcd_ssp, SO_REUSEADDR); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate /* 342*0Sstevel@tonic-gate * Set the SO_DONTROUTE option for this TLI endpoint, if 343*0Sstevel@tonic-gate * /etc/ssphostname exists. 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate if (peercheck == 1) 346*0Sstevel@tonic-gate cvcd_setopt(cvcd_ssp, SO_DONTROUTE); 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * Bind it. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate if (((reqb = (struct t_bind *)t_alloc(cvcd_ssp, T_BIND, T_ALL)) 352*0Sstevel@tonic-gate == (struct t_bind *)NULL)) { 353*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]); 354*0Sstevel@tonic-gate exit(1); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate if (((retb = (struct t_bind *)t_alloc(cvcd_ssp, T_BIND, T_ALL)) 357*0Sstevel@tonic-gate == (struct t_bind *)NULL)) { 358*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]); 359*0Sstevel@tonic-gate exit(1); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate reqb->qlen = 1; 362*0Sstevel@tonic-gate reqb->addr.len = sizeof (struct sockaddr_in); 363*0Sstevel@tonic-gate sin = (struct sockaddr_in *)reqb->addr.buf; 364*0Sstevel@tonic-gate (void) memset((void *)sin, 0, sizeof (struct sockaddr_in)); 365*0Sstevel@tonic-gate sin->sin_family = AF_INET; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(INADDR_ANY); 369*0Sstevel@tonic-gate sin->sin_port = htons(tport); 370*0Sstevel@tonic-gate if (t_bind(cvcd_ssp, reqb, retb) == -1) { 371*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_bind: %s", t_errlist[t_errno]); 372*0Sstevel@tonic-gate exit(1); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate sin = (struct sockaddr_in *)retb->addr.buf; 375*0Sstevel@tonic-gate if (sin->sin_port != htons(tport)) { 376*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_bind: bound to wrong port"); 377*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "Wanted %d, got %d", tport, 378*0Sstevel@tonic-gate ntohs(sin->sin_port)); 379*0Sstevel@tonic-gate exit(1); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate t_free((char *)reqb, T_BIND); 383*0Sstevel@tonic-gate t_free((char *)retb, T_BIND); 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * Wait for connect from OBP. 388*0Sstevel@tonic-gate */ 389*0Sstevel@tonic-gate cvcd_pfd[2].fd = cvcd_ssp; 390*0Sstevel@tonic-gate cvcd_pfd[2].events = POLLIN|POLLPRI; 391*0Sstevel@tonic-gate if ((event = poll(&cvcd_pfd[2], 1, -1)) == -1) { 392*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "poll: %s", strerror(errno)); 393*0Sstevel@tonic-gate exit(1); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate /* 396*0Sstevel@tonic-gate * cvcd_connect sets global 397*0Sstevel@tonic-gate * connected = 1 if successful. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate cvcd_connect(cvcd_ssp, cvcd_pfd); 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate /* 402*0Sstevel@tonic-gate * Now set up the Network Console redirection driver. 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate rconsfd = open(CVCREDIR_DEV, O_RDWR|O_NDELAY); 405*0Sstevel@tonic-gate if (rconsfd < 0) { 406*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "open: %s", strerror(errno)); 407*0Sstevel@tonic-gate exit(1); 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate /* 411*0Sstevel@tonic-gate * cvcd_pfd holds three file descriptors we need to poll from: 412*0Sstevel@tonic-gate * 0 will be connected to in_cvcd; 1 is the CVC Redirection driver; 413*0Sstevel@tonic-gate * and 2 is the listen endpoint for new connections. 414*0Sstevel@tonic-gate */ 415*0Sstevel@tonic-gate cvcd_pfd[1].fd = rconsfd; 416*0Sstevel@tonic-gate cvcd_pfd[1].events = POLLIN; 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * Loop through main service routine. We check for inbound in.cvcd 419*0Sstevel@tonic-gate * connection and data xfer between host and in.cvcd. 420*0Sstevel@tonic-gate */ 421*0Sstevel@tonic-gate for (;;) { 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate char buf[MAXPKTSZ]; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate /* 426*0Sstevel@tonic-gate * Check for in_cvcd connect requests. 427*0Sstevel@tonic-gate */ 428*0Sstevel@tonic-gate switch ((event = t_look(cvcd_ssp))) { 429*0Sstevel@tonic-gate case -1 : 430*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]); 431*0Sstevel@tonic-gate exit(1); 432*0Sstevel@tonic-gate /* NOTREACHED */ 433*0Sstevel@tonic-gate break; 434*0Sstevel@tonic-gate case 0 : /* Nothing to do */ 435*0Sstevel@tonic-gate break; 436*0Sstevel@tonic-gate case T_LISTEN : 437*0Sstevel@tonic-gate if (connected == 1) { 438*0Sstevel@tonic-gate /* 439*0Sstevel@tonic-gate * Someone already connected. 440*0Sstevel@tonic-gate */ 441*0Sstevel@tonic-gate cvcd_reject(cvcd_ssp); 442*0Sstevel@tonic-gate } else { 443*0Sstevel@tonic-gate /* 444*0Sstevel@tonic-gate * cvcd_connect sets global 445*0Sstevel@tonic-gate * connected = 1 if successful. 446*0Sstevel@tonic-gate */ 447*0Sstevel@tonic-gate cvcd_connect(cvcd_ssp, cvcd_pfd); 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * Re-open the cvcredir driver if 451*0Sstevel@tonic-gate * the netcon_fail is true. This 452*0Sstevel@tonic-gate * indicates there was a previous 453*0Sstevel@tonic-gate * network connection that got closed. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate if (netcon_fail) { 456*0Sstevel@tonic-gate rconsfd = open(CVCREDIR_DEV, 457*0Sstevel@tonic-gate O_RDWR|O_NDELAY); 458*0Sstevel@tonic-gate if (rconsfd < 0) { 459*0Sstevel@tonic-gate cvcd_err(LOG_ERR, 460*0Sstevel@tonic-gate "open: %s", 461*0Sstevel@tonic-gate strerror(errno)); 462*0Sstevel@tonic-gate exit(1); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate cvcd_pfd[1].fd = rconsfd; 465*0Sstevel@tonic-gate cvcd_pfd[1].events = POLLIN; 466*0Sstevel@tonic-gate netcon_fail = 0; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate break; 470*0Sstevel@tonic-gate default : 471*0Sstevel@tonic-gate cvcd_err(LOG_ERR, 472*0Sstevel@tonic-gate "Illegal event %d for cvcd_ssp", event); 473*0Sstevel@tonic-gate exit(1); 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate /* 476*0Sstevel@tonic-gate * Take a look for console I/O or connect request. 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate if ((event = poll(cvcd_pfd, 3, -1)) == -1) { 479*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "poll: %s", strerror(errno)); 480*0Sstevel@tonic-gate exit(1); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate /* 484*0Sstevel@tonic-gate * The following for loop is to detect any bad 485*0Sstevel@tonic-gate * things(ie hangup,errors,invalid fd) have happened 486*0Sstevel@tonic-gate * to the file descriptors we're interested in. 487*0Sstevel@tonic-gate * If so, disconnect current network console connection. 488*0Sstevel@tonic-gate */ 489*0Sstevel@tonic-gate for (j = 0; j < 3; j++) { 490*0Sstevel@tonic-gate if (cvcd_pfd[j].revents & (POLLERR|POLLHUP|POLLNVAL)) { 491*0Sstevel@tonic-gate cvcd_err(LOG_WARNING, 492*0Sstevel@tonic-gate "poll: status on %s fd:%s%s%s", 493*0Sstevel@tonic-gate ((j == 2) ? "listen" : 494*0Sstevel@tonic-gate ((j == 0) ? "network" : "redir")), 495*0Sstevel@tonic-gate (cvcd_pfd[j].revents & POLLERR) ? 496*0Sstevel@tonic-gate " error" : "", 497*0Sstevel@tonic-gate (cvcd_pfd[j].revents & POLLHUP) ? 498*0Sstevel@tonic-gate " hangup" : "", 499*0Sstevel@tonic-gate (cvcd_pfd[j].revents & POLLNVAL) ? 500*0Sstevel@tonic-gate " bad fd" : ""); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate (void) t_close(cvcd_pfd[0].fd); 503*0Sstevel@tonic-gate cvcd_pfd[0].fd = -1; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate (void) close(cvcd_pfd[1].fd); 506*0Sstevel@tonic-gate cvcd_pfd[1].fd = -1; 507*0Sstevel@tonic-gate connected = 0; 508*0Sstevel@tonic-gate netcon_fail = 1; 509*0Sstevel@tonic-gate break; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate /* 514*0Sstevel@tonic-gate * Check if dummy netcon_fail flag is set, if set returns 515*0Sstevel@tonic-gate * to the beginning of the main service routine. 516*0Sstevel@tonic-gate */ 517*0Sstevel@tonic-gate if (netcon_fail) 518*0Sstevel@tonic-gate continue; 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate if (event != 0) { 521*0Sstevel@tonic-gate if (cvcd_pfd[0].revents == POLLIN) { 522*0Sstevel@tonic-gate /* 523*0Sstevel@tonic-gate * Process cvcd_ssp data and commands. 524*0Sstevel@tonic-gate */ 525*0Sstevel@tonic-gate cvcd_read(cvcd_pfd); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate if (cvcd_pfd[1].revents == POLLIN) { 528*0Sstevel@tonic-gate int s; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate if ((s = read(rconsfd, buf, MAXPKTSZ)) == -1) { 531*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "read: %s", 532*0Sstevel@tonic-gate strerror(errno)); 533*0Sstevel@tonic-gate exit(1); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate if ((s > 0) && (connected == 1)) { 536*0Sstevel@tonic-gate if (write(cvcd_pfd[0].fd, buf, s) != 537*0Sstevel@tonic-gate s) { 538*0Sstevel@tonic-gate cvcd_err(LOG_ERR, 539*0Sstevel@tonic-gate "lost data output"); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate } /* End forever loop */ 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate #ifdef lint 547*0Sstevel@tonic-gate /* NOTREACHED */ 548*0Sstevel@tonic-gate return (1); 549*0Sstevel@tonic-gate #endif /* lint */ 550*0Sstevel@tonic-gate } 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate static void 553*0Sstevel@tonic-gate cvcd_reject(int fd) 554*0Sstevel@tonic-gate { 555*0Sstevel@tonic-gate struct t_call *tcall; 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate tcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); 558*0Sstevel@tonic-gate if (tcall == (struct t_call *)NULL) { 559*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: t_alloc: %s", 560*0Sstevel@tonic-gate t_errlist[t_errno]); 561*0Sstevel@tonic-gate return; 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate if (t_listen(fd, tcall) == -1) { 564*0Sstevel@tonic-gate if (t_errno == TNODATA) { 565*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: No client data!"); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: t_listen: %s", 568*0Sstevel@tonic-gate t_errlist[t_errno]); 569*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 570*0Sstevel@tonic-gate return; 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate if (t_snddis(fd, tcall) < 0) { 573*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: t_snddis: %s", 574*0Sstevel@tonic-gate t_errlist[t_errno]); 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate static void 580*0Sstevel@tonic-gate cvcd_connect(int fd, struct pollfd *pfd) 581*0Sstevel@tonic-gate { 582*0Sstevel@tonic-gate struct t_call *tcall; 583*0Sstevel@tonic-gate int newfd; 584*0Sstevel@tonic-gate struct sockaddr_in *peer; 585*0Sstevel@tonic-gate int badpeer = 1; 586*0Sstevel@tonic-gate struct hostent *he; 587*0Sstevel@tonic-gate struct netbuf netbuf; 588*0Sstevel@tonic-gate char addr[100]; 589*0Sstevel@tonic-gate ulong_t tmpaddr; /* network byte order */ 590*0Sstevel@tonic-gate char **pp; 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate tcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); 593*0Sstevel@tonic-gate if (tcall == (struct t_call *)NULL) { 594*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: t_alloc: %s", 595*0Sstevel@tonic-gate t_errlist[t_errno]); 596*0Sstevel@tonic-gate return; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate if (t_listen(fd, tcall) == -1) { 599*0Sstevel@tonic-gate if (t_errno == TNODATA) { 600*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: No client data!"); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cnctip_connect: t_listen: %s", 603*0Sstevel@tonic-gate t_errlist[t_errno]); 604*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 605*0Sstevel@tonic-gate return; 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate if (pfd[0].fd != -1) { 608*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: no free file descriptors!"); 609*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 610*0Sstevel@tonic-gate return; 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate newfd = t_open(TCP_DEV, O_RDWR|O_NDELAY, NULL); 613*0Sstevel@tonic-gate if (newfd == -1) { 614*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: t_open: %s", 615*0Sstevel@tonic-gate t_errlist[t_errno]); 616*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 617*0Sstevel@tonic-gate return; 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate if (t_accept(fd, newfd, tcall) < 0) { 620*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: t_accept: %s", 621*0Sstevel@tonic-gate t_errlist[t_errno]); 622*0Sstevel@tonic-gate t_close(newfd); 623*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 624*0Sstevel@tonic-gate return; 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate t_free((char *)tcall, T_CALL); 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* 629*0Sstevel@tonic-gate * If /etc/ssphostname doesnt exists, dont bother verifying 630*0Sstevel@tonic-gate * peer since we cant do gethostbyname. 631*0Sstevel@tonic-gate */ 632*0Sstevel@tonic-gate if (peercheck == 1) { 633*0Sstevel@tonic-gate he = gethostbyname(ssphostname); 634*0Sstevel@tonic-gate if (he == NULL) { 635*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "gethostbyname: %s", 636*0Sstevel@tonic-gate strerror(h_errno)); 637*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "unable to get SSP name %s!", 638*0Sstevel@tonic-gate ssphostname); 639*0Sstevel@tonic-gate exit(1); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate /* 642*0Sstevel@tonic-gate * Verify peer is from specified host by comparing the 643*0Sstevel@tonic-gate * address (in network byte order) of the TLI endpoint 644*0Sstevel@tonic-gate * and the address (in network byte order) of the ssp 645*0Sstevel@tonic-gate * (using the hostname found in /etc/ssphostname). 646*0Sstevel@tonic-gate */ 647*0Sstevel@tonic-gate (void) memset(addr, 0, 100); 648*0Sstevel@tonic-gate netbuf.buf = addr; 649*0Sstevel@tonic-gate netbuf.len = 0; 650*0Sstevel@tonic-gate netbuf.maxlen = 100; 651*0Sstevel@tonic-gate if (ioctl(newfd, TI_GETPEERNAME, &netbuf) < 0) { 652*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "ioctl(TI_GETPEERNAME): %s", 653*0Sstevel@tonic-gate strerror(errno)); 654*0Sstevel@tonic-gate t_close(newfd); 655*0Sstevel@tonic-gate return; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * cvcd doesn't check multi-homed ssphostname 660*0Sstevel@tonic-gate * properly (only checks 1st address) 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate peer = (struct sockaddr_in *)addr; 663*0Sstevel@tonic-gate for (pp = he->h_addr_list; *pp != 0; pp++) { 664*0Sstevel@tonic-gate tmpaddr = htonl(*(ulong_t *)*pp); 665*0Sstevel@tonic-gate if (memcmp(&peer->sin_addr.s_addr, &tmpaddr, 666*0Sstevel@tonic-gate he->h_length) == 0) { 667*0Sstevel@tonic-gate badpeer = 0; 668*0Sstevel@tonic-gate break; 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate if (badpeer) { 673*0Sstevel@tonic-gate cvcd_err(LOG_ERR, CONREF); 674*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "remote host = %s.", 675*0Sstevel@tonic-gate inet_ntoa(peer->sin_addr)); 676*0Sstevel@tonic-gate t_close(newfd); 677*0Sstevel@tonic-gate return; 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate pfd[0].fd = newfd; 681*0Sstevel@tonic-gate pfd[0].events = POLLIN; 682*0Sstevel@tonic-gate connected = 1; 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate /* 686*0Sstevel@tonic-gate * Read in data from client. 687*0Sstevel@tonic-gate */ 688*0Sstevel@tonic-gate static void 689*0Sstevel@tonic-gate cvcd_read(struct pollfd *pd) 690*0Sstevel@tonic-gate { 691*0Sstevel@tonic-gate register char *data; 692*0Sstevel@tonic-gate register int fd = pd[0].fd; 693*0Sstevel@tonic-gate char buf[MAXPKTSZ]; 694*0Sstevel@tonic-gate int flags = 0; 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate data = buf; 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate if (pd[0].revents & POLLIN) { 699*0Sstevel@tonic-gate int n; 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate if ((n = t_rcv(fd, data, MAXPKTSZ, &flags)) == -1) { 702*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_read: t_rcv: %s", 703*0Sstevel@tonic-gate t_errlist[t_errno]); 704*0Sstevel@tonic-gate (void) t_close(pd[0].fd); 705*0Sstevel@tonic-gate pd[0].fd = -1; 706*0Sstevel@tonic-gate connected = 0; 707*0Sstevel@tonic-gate return; 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate if (flags & T_EXPEDITED) { 710*0Sstevel@tonic-gate if (n != 1) { 711*0Sstevel@tonic-gate cvcd_err(LOG_ERR, 712*0Sstevel@tonic-gate "cvcd_read: %d bytes EXD!!", 713*0Sstevel@tonic-gate n); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate /* 716*0Sstevel@tonic-gate * Deal with cvcd_ssp_commands. 717*0Sstevel@tonic-gate */ 718*0Sstevel@tonic-gate switch (data[n-1]) { 719*0Sstevel@tonic-gate case CVC_CONN_BREAK : 720*0Sstevel@tonic-gate cvcd_ioctl(rconsfd, CVC_BREAK); 721*0Sstevel@tonic-gate break; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate case CVC_CONN_DIS : 724*0Sstevel@tonic-gate (void) t_close(pd[0].fd); 725*0Sstevel@tonic-gate pd[0].fd = -1; 726*0Sstevel@tonic-gate cvcd_ioctl(rconsfd, CVC_DISCONNECT); 727*0Sstevel@tonic-gate connected = 0; 728*0Sstevel@tonic-gate break; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate case CVC_CONN_STAT : 731*0Sstevel@tonic-gate cvcd_status(fd); 732*0Sstevel@tonic-gate break; 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate default : 735*0Sstevel@tonic-gate cvcd_err(LOG_ERR, 736*0Sstevel@tonic-gate "Illegal cmd 0x%x", buf[n-1]); 737*0Sstevel@tonic-gate break; 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate } else { 740*0Sstevel@tonic-gate if (((data[0] & 0377) == 0377) && 741*0Sstevel@tonic-gate ((data[1] & 0377) == 0377)) { 742*0Sstevel@tonic-gate /* 743*0Sstevel@tonic-gate * Pass on window size changes (TIOCSWINSZ). 744*0Sstevel@tonic-gate */ 745*0Sstevel@tonic-gate cvcd_winch(rconsfd, data, n); 746*0Sstevel@tonic-gate (void) memset(data, 0, n); 747*0Sstevel@tonic-gate } else { 748*0Sstevel@tonic-gate cvcd_write(buf, n); 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate static void 756*0Sstevel@tonic-gate cvcd_ioctl(int fd, int flags) 757*0Sstevel@tonic-gate { 758*0Sstevel@tonic-gate struct strioctl cmd; 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate cmd.ic_cmd = flags; 761*0Sstevel@tonic-gate cmd.ic_timout = 0; 762*0Sstevel@tonic-gate cmd.ic_len = 0; 763*0Sstevel@tonic-gate cmd.ic_dp = NULL; 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate if (ioctl(fd, I_STR, &cmd) == -1) { 766*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_ioctl: %s", strerror(errno)); 767*0Sstevel@tonic-gate exit(1); 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* ARGSUSED */ 773*0Sstevel@tonic-gate static void 774*0Sstevel@tonic-gate cvcd_status(int fd) 775*0Sstevel@tonic-gate { 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate /* 780*0Sstevel@tonic-gate * Write input to console - called from cvcd_read. 781*0Sstevel@tonic-gate */ 782*0Sstevel@tonic-gate static void 783*0Sstevel@tonic-gate cvcd_write(char *data, int size) 784*0Sstevel@tonic-gate { 785*0Sstevel@tonic-gate int n; 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate if ((n = write(rconsfd, data, size)) == -1) { 788*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_write: write: %s", strerror(errno)); 789*0Sstevel@tonic-gate exit(1); 790*0Sstevel@tonic-gate } 791*0Sstevel@tonic-gate if (n != size) { 792*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_write: wrote %d of %d bytes", n, size); 793*0Sstevel@tonic-gate } 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate static void 797*0Sstevel@tonic-gate usage() 798*0Sstevel@tonic-gate { 799*0Sstevel@tonic-gate #if defined(DEBUG) 800*0Sstevel@tonic-gate (void) printf("%s [-d] [-p port]\n", progname); 801*0Sstevel@tonic-gate #else 802*0Sstevel@tonic-gate (void) printf("%s -r [ssp host]\n", progname); 803*0Sstevel@tonic-gate #endif /* DEBUG */ 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate /* 807*0Sstevel@tonic-gate * cvcd_err () 808*0Sstevel@tonic-gate * 809*0Sstevel@tonic-gate * Description: 810*0Sstevel@tonic-gate * Log messages via syslog daemon. 811*0Sstevel@tonic-gate * 812*0Sstevel@tonic-gate * Input: 813*0Sstevel@tonic-gate * code - logging code 814*0Sstevel@tonic-gate * format - messages to log 815*0Sstevel@tonic-gate * 816*0Sstevel@tonic-gate * Output: 817*0Sstevel@tonic-gate * void 818*0Sstevel@tonic-gate * 819*0Sstevel@tonic-gate */ 820*0Sstevel@tonic-gate static void 821*0Sstevel@tonic-gate cvcd_err(int code, char *format, ...) 822*0Sstevel@tonic-gate { 823*0Sstevel@tonic-gate va_list varg_ptr; 824*0Sstevel@tonic-gate char buf[MAXPKTSZ]; 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate va_start(varg_ptr, format); 827*0Sstevel@tonic-gate (void) vsprintf(buf, format, varg_ptr); 828*0Sstevel@tonic-gate va_end(varg_ptr); 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate if (debug == 0) 831*0Sstevel@tonic-gate syslog(code, buf); 832*0Sstevel@tonic-gate else 833*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", progname, buf); 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate /* 837*0Sstevel@tonic-gate * Handle a "control" request (signaled by magic being present) 838*0Sstevel@tonic-gate * in the data stream. For now, we are only willing to handle 839*0Sstevel@tonic-gate * window size changes. 840*0Sstevel@tonic-gate */ 841*0Sstevel@tonic-gate void 842*0Sstevel@tonic-gate cvcd_winch(int pty, char *cp, int n) 843*0Sstevel@tonic-gate { 844*0Sstevel@tonic-gate struct winsize w; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 847*0Sstevel@tonic-gate return; 848*0Sstevel@tonic-gate (void) memcpy(&w, cp + 4, sizeof (w)); 849*0Sstevel@tonic-gate w.ws_row = ntohs(w.ws_row); 850*0Sstevel@tonic-gate w.ws_col = ntohs(w.ws_col); 851*0Sstevel@tonic-gate w.ws_xpixel = ntohs(w.ws_xpixel); 852*0Sstevel@tonic-gate w.ws_ypixel = ntohs(w.ws_ypixel); 853*0Sstevel@tonic-gate (void) ioctl(pty, TIOCSWINSZ, &w); 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate /* 858*0Sstevel@tonic-gate * Return class ID and maximum priority of it. 859*0Sstevel@tonic-gate * Input: 860*0Sstevel@tonic-gate * name: is class name (either TS or RT). 861*0Sstevel@tonic-gate * maxpri: maximum priority for the class, returned in *maxpri. 862*0Sstevel@tonic-gate * Output: 863*0Sstevel@tonic-gate * pc_cid: class ID 864*0Sstevel@tonic-gate */ 865*0Sstevel@tonic-gate static id_t 866*0Sstevel@tonic-gate schedinfo(char *name, short *maxpri) 867*0Sstevel@tonic-gate { 868*0Sstevel@tonic-gate pcinfo_t info; 869*0Sstevel@tonic-gate tsinfo_t *tsinfop; 870*0Sstevel@tonic-gate rtinfo_t *rtinfop; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate (void) strcpy(info.pc_clname, name); 873*0Sstevel@tonic-gate if (priocntl(0L, 0L, PC_GETCID, (caddr_t)&info) == -1L) { 874*0Sstevel@tonic-gate return (-1); 875*0Sstevel@tonic-gate } 876*0Sstevel@tonic-gate if (strcmp(name, "TS") == 0) { /* Time Shared */ 877*0Sstevel@tonic-gate tsinfop = (struct tsinfo *)info.pc_clinfo; 878*0Sstevel@tonic-gate *maxpri = tsinfop->ts_maxupri; 879*0Sstevel@tonic-gate } else if (strcmp(name, "RT") == 0) { /* Real Time */ 880*0Sstevel@tonic-gate rtinfop = (struct rtinfo *)info.pc_clinfo; 881*0Sstevel@tonic-gate *maxpri = rtinfop->rt_maxpri; 882*0Sstevel@tonic-gate } else { 883*0Sstevel@tonic-gate return (-1); 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate return (info.pc_cid); 886*0Sstevel@tonic-gate } 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate /* 890*0Sstevel@tonic-gate * set the tli options for the given endpoint represented by fd 891*0Sstevel@tonic-gate */ 892*0Sstevel@tonic-gate static void 893*0Sstevel@tonic-gate cvcd_setopt(int fd, int name) 894*0Sstevel@tonic-gate { 895*0Sstevel@tonic-gate struct t_optmgmt *topt, *tropt; 896*0Sstevel@tonic-gate struct opthdr *sockopt; 897*0Sstevel@tonic-gate int on = 1; 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate topt = (struct t_optmgmt *)t_alloc(fd, T_OPTMGMT, 0); 900*0Sstevel@tonic-gate if (topt == NULL) { 901*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_alloc: %s", t_errlist[t_errno]); 902*0Sstevel@tonic-gate exit(1); 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate tropt = (struct t_optmgmt *)t_alloc(fd, T_OPTMGMT, 0); 905*0Sstevel@tonic-gate if (tropt == NULL) { 906*0Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_alloc: %s", t_errlist[t_errno]); 907*0Sstevel@tonic-gate exit(1); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate topt->opt.buf = (char *)malloc(sizeof (struct opthdr) + sizeof (int)); 910*0Sstevel@tonic-gate topt->opt.maxlen = 0; 911*0Sstevel@tonic-gate topt->opt.len = sizeof (struct opthdr) + sizeof (int); 912*0Sstevel@tonic-gate topt->flags = T_NEGOTIATE; 913*0Sstevel@tonic-gate sockopt = (struct opthdr *)topt->opt.buf; 914*0Sstevel@tonic-gate sockopt->level = SOL_SOCKET; 915*0Sstevel@tonic-gate sockopt->name = name; 916*0Sstevel@tonic-gate sockopt->len = sizeof (int); 917*0Sstevel@tonic-gate (void) memcpy((char *)(topt->opt.buf + sizeof (struct opthdr)), 918*0Sstevel@tonic-gate (char *)&on, sizeof (on)); 919*0Sstevel@tonic-gate tropt->opt.buf = (char *)malloc(sizeof (struct opthdr) + sizeof (int)); 920*0Sstevel@tonic-gate tropt->opt.maxlen = sizeof (struct opthdr) + sizeof (int); 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate if (t_optmgmt(fd, topt, tropt) == -1) { 923*0Sstevel@tonic-gate t_error("t_optmgmt"); 924*0Sstevel@tonic-gate exit(1); 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate t_free((char *)topt, T_OPTMGMT); 928*0Sstevel@tonic-gate t_free((char *)tropt, T_OPTMGMT); 929*0Sstevel@tonic-gate } 930