10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*796Smathue * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * This code implements the Starfire Virtual Console host daemon
300Sstevel@tonic-gate * (see cvcd(1M)). It accepts a connection from netcon_server
310Sstevel@tonic-gate * and transfers console I/O to/from the SSP across the
320Sstevel@tonic-gate * network via TLI. The I/O is sent to the cvcredir device
330Sstevel@tonic-gate * on the host (see cvc(7) and cvcredir(7)). It also sends
340Sstevel@tonic-gate * disconnect and break ioctl's to the kernel CVC drivers.
350Sstevel@tonic-gate */
360Sstevel@tonic-gate
370Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
380Sstevel@tonic-gate
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <stdio.h>
410Sstevel@tonic-gate #include <stdarg.h>
420Sstevel@tonic-gate #include <syslog.h>
430Sstevel@tonic-gate #include <stdlib.h>
440Sstevel@tonic-gate #include <tiuser.h>
450Sstevel@tonic-gate #include <sys/timod.h>
460Sstevel@tonic-gate #include <fcntl.h>
470Sstevel@tonic-gate #include <sys/param.h>
480Sstevel@tonic-gate #include <sys/utsname.h>
490Sstevel@tonic-gate #include <sys/stat.h>
500Sstevel@tonic-gate #include <unistd.h>
510Sstevel@tonic-gate #include <stropts.h>
520Sstevel@tonic-gate #include <sys/conf.h>
530Sstevel@tonic-gate #include <pwd.h>
540Sstevel@tonic-gate #include <errno.h>
550Sstevel@tonic-gate #include <sys/socket.h>
560Sstevel@tonic-gate #include <arpa/inet.h>
570Sstevel@tonic-gate #include <locale.h>
580Sstevel@tonic-gate #include <termio.h>
590Sstevel@tonic-gate #include <signal.h>
600Sstevel@tonic-gate #include <sys/cvc.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate #include <string.h>
630Sstevel@tonic-gate
640Sstevel@tonic-gate #include <sys/ioctl.h>
650Sstevel@tonic-gate #include <sys/file.h>
660Sstevel@tonic-gate #include <sys/sockio.h>
670Sstevel@tonic-gate
680Sstevel@tonic-gate #include <sys/tihdr.h>
690Sstevel@tonic-gate
700Sstevel@tonic-gate #include <netdb.h>
710Sstevel@tonic-gate #include <net/if.h>
720Sstevel@tonic-gate #include <netinet/if_ether.h>
730Sstevel@tonic-gate
740Sstevel@tonic-gate #include <inet/common.h>
750Sstevel@tonic-gate #include <sys/systeminfo.h>
760Sstevel@tonic-gate
770Sstevel@tonic-gate /* Process priority control */
780Sstevel@tonic-gate #include <sys/priocntl.h>
790Sstevel@tonic-gate #include <sys/tspriocntl.h>
800Sstevel@tonic-gate #include <sys/rtpriocntl.h>
810Sstevel@tonic-gate
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate * Misc. defines.
840Sstevel@tonic-gate */
850Sstevel@tonic-gate #define CONREF "connection request from illegal host"
860Sstevel@tonic-gate #define SSPHOSTNAMEFILE "/etc/ssphostname"
870Sstevel@tonic-gate #define NODENAME "/etc/nodename"
880Sstevel@tonic-gate #define MAXIFS 256
890Sstevel@tonic-gate
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate * Function prototypes
920Sstevel@tonic-gate */
930Sstevel@tonic-gate static void cvcd_connect(int fd, struct pollfd *);
940Sstevel@tonic-gate static void cvcd_reject(int fd);
950Sstevel@tonic-gate static void cvcd_read(struct pollfd *);
960Sstevel@tonic-gate static void cvcd_write(char *data, int size);
970Sstevel@tonic-gate static void cvcd_status(int fd);
980Sstevel@tonic-gate static void cvcd_winch(int, char *, int);
990Sstevel@tonic-gate static void cvcd_ioctl(int fd, int cmd);
1000Sstevel@tonic-gate static void cvcd_err(int code, char *format, ...);
1010Sstevel@tonic-gate static void usage(void);
1020Sstevel@tonic-gate static id_t schedinfo(char *name, short *maxpri);
1030Sstevel@tonic-gate static void cvcd_setopt(int fd, int name);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate * Globals
1070Sstevel@tonic-gate */
1080Sstevel@tonic-gate static int rconsfd; /* Console redirection driver */
1090Sstevel@tonic-gate static char progname[MAXPATHLEN];
1100Sstevel@tonic-gate static char ssphostname[MAXPATHLEN];
1110Sstevel@tonic-gate static int debug = 0;
1120Sstevel@tonic-gate static int connected = 0;
1130Sstevel@tonic-gate static int peercheck = 1;
1140Sstevel@tonic-gate static char nic_name[32];
1150Sstevel@tonic-gate
116*796Smathue int
main(int argc,char ** argv)1170Sstevel@tonic-gate main(int argc, char **argv)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate int opt;
1200Sstevel@tonic-gate int tport = 0;
1210Sstevel@tonic-gate char *hostname;
1220Sstevel@tonic-gate struct utsname utsname;
1230Sstevel@tonic-gate struct t_info tinfo;
1240Sstevel@tonic-gate int cvcd_ssp;
1250Sstevel@tonic-gate int nfd;
1260Sstevel@tonic-gate struct pollfd *cvcd_pfd;
1270Sstevel@tonic-gate int i;
1280Sstevel@tonic-gate int j;
1290Sstevel@tonic-gate struct servent *se;
1300Sstevel@tonic-gate struct sockaddr_in *sin;
1310Sstevel@tonic-gate struct t_bind *reqb;
1320Sstevel@tonic-gate struct t_bind *retb;
1330Sstevel@tonic-gate struct t_optmgmt *topt, *tropt;
1340Sstevel@tonic-gate struct opthdr *sockopt;
1350Sstevel@tonic-gate int on = 1;
1360Sstevel@tonic-gate int tmperr = 0;
1370Sstevel@tonic-gate int event;
1380Sstevel@tonic-gate char prefix[256];
1390Sstevel@tonic-gate pcparms_t pcparms;
1400Sstevel@tonic-gate tsparms_t *tsparmsp;
1410Sstevel@tonic-gate id_t pid, tsID;
1420Sstevel@tonic-gate short tsmaxpri;
1430Sstevel@tonic-gate static int netcon_fail = 0;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1460Sstevel@tonic-gate (void) strcpy(progname, argv[0]);
1470Sstevel@tonic-gate (void) memset(ssphostname, 0, MAXPATHLEN);
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate if ((cvcd_ssp = open(SSPHOSTNAMEFILE, O_RDONLY)) < 0) {
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * If there is no /etc/ssphostname disable peer check after
1520Sstevel@tonic-gate * issuing warning.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate tmperr = errno;
1550Sstevel@tonic-gate peercheck = 0;
1560Sstevel@tonic-gate } else {
1570Sstevel@tonic-gate if ((i = read(cvcd_ssp, ssphostname, MAXPATHLEN)) < 0) {
1580Sstevel@tonic-gate cvcd_err(LOG_ERR, "failed to read ssphostname");
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate * The ssp-config(1M) command newline terminates the
1620Sstevel@tonic-gate * ssphostname in the /etc/ssphostname file
1630Sstevel@tonic-gate */
1640Sstevel@tonic-gate ssphostname[i-1] = '\0';
1650Sstevel@tonic-gate (void) close(cvcd_ssp);
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate (void) memset(nic_name, 0, sizeof (nic_name));
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate #if defined(DEBUG)
1710Sstevel@tonic-gate while ((opt = getopt(argc, argv, "dp:r:")) != EOF) {
1720Sstevel@tonic-gate #else
1730Sstevel@tonic-gate while ((opt = getopt(argc, argv, "r:")) != EOF) {
1740Sstevel@tonic-gate #endif /* DEBUG */
1750Sstevel@tonic-gate switch (opt) {
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate #if defined(DEBUG)
1780Sstevel@tonic-gate case 'd' : debug = 1;
1790Sstevel@tonic-gate break;
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate case 'p' : tport = atoi(optarg);
1820Sstevel@tonic-gate break;
1830Sstevel@tonic-gate #endif /* DEBUG */
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate case 'r' : (void) strcpy(ssphostname, optarg);
1860Sstevel@tonic-gate break;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate default : usage();
1890Sstevel@tonic-gate exit(1);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate if (uname(&utsname) == -1) {
1940Sstevel@tonic-gate perror("HOSTNAME not defined");
1950Sstevel@tonic-gate exit(1);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate hostname = utsname.nodename;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate * hostname may still be NULL, depends on when cvcd was started
2010Sstevel@tonic-gate * in the boot sequence. If it is NULL, try one more time
2020Sstevel@tonic-gate * to get a hostname -> look in the /etc/nodename file.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate if (!strlen(hostname)) {
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * try to get the hostname from the /etc/nodename file
2070Sstevel@tonic-gate * we reuse the utsname.nodename buffer here! hostname
2080Sstevel@tonic-gate * already points to it.
2090Sstevel@tonic-gate */
2100Sstevel@tonic-gate if ((nfd = open(NODENAME, O_RDONLY)) > 0) {
2110Sstevel@tonic-gate if ((i = read(nfd, utsname.nodename, SYS_NMLN)) <= 0) {
2120Sstevel@tonic-gate cvcd_err(LOG_WARNING,
2130Sstevel@tonic-gate "failed to acquire hostname");
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate utsname.nodename[i-1] = '\0';
2160Sstevel@tonic-gate (void) close(nfd);
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate * Must be root.
2220Sstevel@tonic-gate */
2230Sstevel@tonic-gate if (debug == 0 && geteuid() != 0) {
2240Sstevel@tonic-gate fprintf(stderr, "cvcd: Must be root");
2250Sstevel@tonic-gate exit(1);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * Daemonize...
2300Sstevel@tonic-gate */
2310Sstevel@tonic-gate if (debug == 0) {
2320Sstevel@tonic-gate for (i = 0; i < NOFILE; i++) {
2330Sstevel@tonic-gate (void) close(i);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate (void) chdir("/");
2360Sstevel@tonic-gate (void) umask(0);
2370Sstevel@tonic-gate if (fork() != 0) {
2380Sstevel@tonic-gate exit(0);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate (void) setpgrp();
2410Sstevel@tonic-gate (void) sprintf(prefix, "%s-(HOSTNAME:%s)", progname, hostname);
2420Sstevel@tonic-gate openlog(prefix, LOG_CONS | LOG_NDELAY, LOG_LOCAL0);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate if (peercheck == 0) {
2450Sstevel@tonic-gate cvcd_err(LOG_ERR, "open(SSPHOSTNAMEFILE):%s",
2460Sstevel@tonic-gate strerror(tmperr));
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate cvcd_pfd = (struct pollfd *)malloc(3*sizeof (struct pollfd));
2500Sstevel@tonic-gate if (cvcd_pfd == (struct pollfd *)NULL) {
2510Sstevel@tonic-gate cvcd_err(LOG_ERR, "malloc:", strerror(errno));
2520Sstevel@tonic-gate exit(1);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate (void) memset((void *)cvcd_pfd, 0, 3*sizeof (struct pollfd));
2550Sstevel@tonic-gate cvcd_pfd[0].fd = -1;
2560Sstevel@tonic-gate cvcd_pfd[1].fd = -1;
2570Sstevel@tonic-gate cvcd_pfd[2].fd = -1;
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate /* SPR 94004 */
2600Sstevel@tonic-gate (void) sigignore(SIGTERM);
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate * SPR 83644: cvc and kadb are not compatible under heavy loads.
2640Sstevel@tonic-gate * Fix: will give cvcd highest TS priority at execution time.
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate pid = getpid();
2670Sstevel@tonic-gate pcparms.pc_cid = PC_CLNULL;
2680Sstevel@tonic-gate tsparmsp = (tsparms_t *)pcparms.pc_clparms;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /* Get scheduler properties for this PID */
2710Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_GETPARMS, (caddr_t)&pcparms) == -1L) {
2720Sstevel@tonic-gate cvcd_err(LOG_ERR,
2730Sstevel@tonic-gate "cvcd: GETPARMS failed. Warning: can't get ",
2740Sstevel@tonic-gate "TS priorities.");
2750Sstevel@tonic-gate } else {
2760Sstevel@tonic-gate /* Get class IDs and maximum priorities for a TS process */
2770Sstevel@tonic-gate if ((tsID = schedinfo("TS", &tsmaxpri)) == -1) {
2780Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd: Warning, can't get ",
2790Sstevel@tonic-gate "TS scheduler info.");
2800Sstevel@tonic-gate } else {
2810Sstevel@tonic-gate if (debug) { /* Print priority info */
2820Sstevel@tonic-gate if (pcparms.pc_cid == tsID) {
2830Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "%s%d%s%d%s%d\n",
2840Sstevel@tonic-gate "cvcd:: PID:", pid,
2850Sstevel@tonic-gate ", TS priority:",
2860Sstevel@tonic-gate tsparmsp->ts_upri,
2870Sstevel@tonic-gate ", TS max_pri:", tsmaxpri);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate /* Change proc's priority to maxtspri */
2910Sstevel@tonic-gate pcparms.pc_cid = tsID;
2920Sstevel@tonic-gate tsparmsp = (struct tsparms *)pcparms.pc_clparms;
2930Sstevel@tonic-gate tsparmsp->ts_upri = tsmaxpri;
2940Sstevel@tonic-gate tsparmsp->ts_uprilim = tsmaxpri;
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_SETPARMS,
2970Sstevel@tonic-gate (caddr_t)&pcparms) == -1L) {
2980Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd: Warning, ",
2990Sstevel@tonic-gate "can't set TS maximum priority.");
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate /* Done */
3020Sstevel@tonic-gate if (debug) { /* Get new scheduler properties for PID */
3030Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_GETPARMS,
3040Sstevel@tonic-gate (caddr_t)&pcparms) == -1L) {
3050Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "GETPARMS failed");
3060Sstevel@tonic-gate exit(1);
3070Sstevel@tonic-gate } else {
3080Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "%s%d%s%d%s%d\n",
3090Sstevel@tonic-gate "cvcd:: PID:", pid,
3100Sstevel@tonic-gate ", New TS priority:",
3110Sstevel@tonic-gate tsparmsp->ts_upri,
3120Sstevel@tonic-gate ", TS max_pri:", tsmaxpri);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate if (debug == 1) {
3190Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "tport = %d, debug = %d", tport, debug);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate if (tport == 0) {
3230Sstevel@tonic-gate if ((se = getservbyname(CVCD_SERVICE, "tcp")) == NULL) {
3240Sstevel@tonic-gate cvcd_err(LOG_ERR, "getservbyname(%s) not found",
3250Sstevel@tonic-gate CVCD_SERVICE);
3260Sstevel@tonic-gate exit(1);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate tport = se->s_port;
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate cvcd_ssp = t_open(TCP_DEV, O_RDWR, &tinfo);
3320Sstevel@tonic-gate if (cvcd_ssp == -1) {
3330Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_open: %s", t_errlist[t_errno]);
3340Sstevel@tonic-gate exit(1);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate * Set the SO_REUSEADDR option for this TLI endpoint.
3390Sstevel@tonic-gate */
3400Sstevel@tonic-gate cvcd_setopt(cvcd_ssp, SO_REUSEADDR);
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate /*
3430Sstevel@tonic-gate * Set the SO_DONTROUTE option for this TLI endpoint, if
3440Sstevel@tonic-gate * /etc/ssphostname exists.
3450Sstevel@tonic-gate */
3460Sstevel@tonic-gate if (peercheck == 1)
3470Sstevel@tonic-gate cvcd_setopt(cvcd_ssp, SO_DONTROUTE);
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate * Bind it.
3510Sstevel@tonic-gate */
3520Sstevel@tonic-gate if (((reqb = (struct t_bind *)t_alloc(cvcd_ssp, T_BIND, T_ALL))
3530Sstevel@tonic-gate == (struct t_bind *)NULL)) {
3540Sstevel@tonic-gate cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]);
3550Sstevel@tonic-gate exit(1);
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate if (((retb = (struct t_bind *)t_alloc(cvcd_ssp, T_BIND, T_ALL))
3580Sstevel@tonic-gate == (struct t_bind *)NULL)) {
3590Sstevel@tonic-gate cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]);
3600Sstevel@tonic-gate exit(1);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate reqb->qlen = 1;
3630Sstevel@tonic-gate reqb->addr.len = sizeof (struct sockaddr_in);
3640Sstevel@tonic-gate sin = (struct sockaddr_in *)reqb->addr.buf;
3650Sstevel@tonic-gate (void) memset((void *)sin, 0, sizeof (struct sockaddr_in));
3660Sstevel@tonic-gate sin->sin_family = AF_INET;
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(INADDR_ANY);
3700Sstevel@tonic-gate sin->sin_port = htons(tport);
3710Sstevel@tonic-gate if (t_bind(cvcd_ssp, reqb, retb) == -1) {
3720Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_bind: %s", t_errlist[t_errno]);
3730Sstevel@tonic-gate exit(1);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate sin = (struct sockaddr_in *)retb->addr.buf;
3760Sstevel@tonic-gate if (sin->sin_port != htons(tport)) {
3770Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_bind: bound to wrong port");
3780Sstevel@tonic-gate cvcd_err(LOG_ERR, "Wanted %d, got %d", tport,
3790Sstevel@tonic-gate ntohs(sin->sin_port));
3800Sstevel@tonic-gate exit(1);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate t_free((char *)reqb, T_BIND);
3840Sstevel@tonic-gate t_free((char *)retb, T_BIND);
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate * Wait for connect from OBP.
3890Sstevel@tonic-gate */
3900Sstevel@tonic-gate cvcd_pfd[2].fd = cvcd_ssp;
3910Sstevel@tonic-gate cvcd_pfd[2].events = POLLIN|POLLPRI;
3920Sstevel@tonic-gate if ((event = poll(&cvcd_pfd[2], 1, -1)) == -1) {
3930Sstevel@tonic-gate cvcd_err(LOG_ERR, "poll: %s", strerror(errno));
3940Sstevel@tonic-gate exit(1);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate * cvcd_connect sets global
3980Sstevel@tonic-gate * connected = 1 if successful.
3990Sstevel@tonic-gate */
4000Sstevel@tonic-gate cvcd_connect(cvcd_ssp, cvcd_pfd);
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * Now set up the Network Console redirection driver.
4040Sstevel@tonic-gate */
4050Sstevel@tonic-gate rconsfd = open(CVCREDIR_DEV, O_RDWR|O_NDELAY);
4060Sstevel@tonic-gate if (rconsfd < 0) {
4070Sstevel@tonic-gate cvcd_err(LOG_ERR, "open: %s", strerror(errno));
4080Sstevel@tonic-gate exit(1);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate * cvcd_pfd holds three file descriptors we need to poll from:
4130Sstevel@tonic-gate * 0 will be connected to in_cvcd; 1 is the CVC Redirection driver;
4140Sstevel@tonic-gate * and 2 is the listen endpoint for new connections.
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate cvcd_pfd[1].fd = rconsfd;
4170Sstevel@tonic-gate cvcd_pfd[1].events = POLLIN;
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate * Loop through main service routine. We check for inbound in.cvcd
4200Sstevel@tonic-gate * connection and data xfer between host and in.cvcd.
4210Sstevel@tonic-gate */
4220Sstevel@tonic-gate for (;;) {
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate char buf[MAXPKTSZ];
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate * Check for in_cvcd connect requests.
4280Sstevel@tonic-gate */
4290Sstevel@tonic-gate switch ((event = t_look(cvcd_ssp))) {
4300Sstevel@tonic-gate case -1 :
4310Sstevel@tonic-gate cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]);
4320Sstevel@tonic-gate exit(1);
4330Sstevel@tonic-gate /* NOTREACHED */
4340Sstevel@tonic-gate break;
4350Sstevel@tonic-gate case 0 : /* Nothing to do */
4360Sstevel@tonic-gate break;
4370Sstevel@tonic-gate case T_LISTEN :
4380Sstevel@tonic-gate if (connected == 1) {
4390Sstevel@tonic-gate /*
4400Sstevel@tonic-gate * Someone already connected.
4410Sstevel@tonic-gate */
4420Sstevel@tonic-gate cvcd_reject(cvcd_ssp);
4430Sstevel@tonic-gate } else {
4440Sstevel@tonic-gate /*
4450Sstevel@tonic-gate * cvcd_connect sets global
4460Sstevel@tonic-gate * connected = 1 if successful.
4470Sstevel@tonic-gate */
4480Sstevel@tonic-gate cvcd_connect(cvcd_ssp, cvcd_pfd);
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate * Re-open the cvcredir driver if
4520Sstevel@tonic-gate * the netcon_fail is true. This
4530Sstevel@tonic-gate * indicates there was a previous
4540Sstevel@tonic-gate * network connection that got closed.
4550Sstevel@tonic-gate */
4560Sstevel@tonic-gate if (netcon_fail) {
4570Sstevel@tonic-gate rconsfd = open(CVCREDIR_DEV,
4580Sstevel@tonic-gate O_RDWR|O_NDELAY);
4590Sstevel@tonic-gate if (rconsfd < 0) {
4600Sstevel@tonic-gate cvcd_err(LOG_ERR,
4610Sstevel@tonic-gate "open: %s",
4620Sstevel@tonic-gate strerror(errno));
4630Sstevel@tonic-gate exit(1);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate cvcd_pfd[1].fd = rconsfd;
4660Sstevel@tonic-gate cvcd_pfd[1].events = POLLIN;
4670Sstevel@tonic-gate netcon_fail = 0;
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate break;
4710Sstevel@tonic-gate default :
4720Sstevel@tonic-gate cvcd_err(LOG_ERR,
4730Sstevel@tonic-gate "Illegal event %d for cvcd_ssp", event);
4740Sstevel@tonic-gate exit(1);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate * Take a look for console I/O or connect request.
4780Sstevel@tonic-gate */
4790Sstevel@tonic-gate if ((event = poll(cvcd_pfd, 3, -1)) == -1) {
4800Sstevel@tonic-gate cvcd_err(LOG_ERR, "poll: %s", strerror(errno));
4810Sstevel@tonic-gate exit(1);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate /*
4850Sstevel@tonic-gate * The following for loop is to detect any bad
4860Sstevel@tonic-gate * things(ie hangup,errors,invalid fd) have happened
4870Sstevel@tonic-gate * to the file descriptors we're interested in.
4880Sstevel@tonic-gate * If so, disconnect current network console connection.
4890Sstevel@tonic-gate */
4900Sstevel@tonic-gate for (j = 0; j < 3; j++) {
4910Sstevel@tonic-gate if (cvcd_pfd[j].revents & (POLLERR|POLLHUP|POLLNVAL)) {
4920Sstevel@tonic-gate cvcd_err(LOG_WARNING,
4930Sstevel@tonic-gate "poll: status on %s fd:%s%s%s",
4940Sstevel@tonic-gate ((j == 2) ? "listen" :
4950Sstevel@tonic-gate ((j == 0) ? "network" : "redir")),
4960Sstevel@tonic-gate (cvcd_pfd[j].revents & POLLERR) ?
4970Sstevel@tonic-gate " error" : "",
4980Sstevel@tonic-gate (cvcd_pfd[j].revents & POLLHUP) ?
4990Sstevel@tonic-gate " hangup" : "",
5000Sstevel@tonic-gate (cvcd_pfd[j].revents & POLLNVAL) ?
5010Sstevel@tonic-gate " bad fd" : "");
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate (void) t_close(cvcd_pfd[0].fd);
5040Sstevel@tonic-gate cvcd_pfd[0].fd = -1;
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate (void) close(cvcd_pfd[1].fd);
5070Sstevel@tonic-gate cvcd_pfd[1].fd = -1;
5080Sstevel@tonic-gate connected = 0;
5090Sstevel@tonic-gate netcon_fail = 1;
5100Sstevel@tonic-gate break;
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate /*
5150Sstevel@tonic-gate * Check if dummy netcon_fail flag is set, if set returns
5160Sstevel@tonic-gate * to the beginning of the main service routine.
5170Sstevel@tonic-gate */
5180Sstevel@tonic-gate if (netcon_fail)
5190Sstevel@tonic-gate continue;
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate if (event != 0) {
5220Sstevel@tonic-gate if (cvcd_pfd[0].revents == POLLIN) {
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate * Process cvcd_ssp data and commands.
5250Sstevel@tonic-gate */
5260Sstevel@tonic-gate cvcd_read(cvcd_pfd);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate if (cvcd_pfd[1].revents == POLLIN) {
5290Sstevel@tonic-gate int s;
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate if ((s = read(rconsfd, buf, MAXPKTSZ)) == -1) {
5320Sstevel@tonic-gate cvcd_err(LOG_ERR, "read: %s",
5330Sstevel@tonic-gate strerror(errno));
5340Sstevel@tonic-gate exit(1);
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate if ((s > 0) && (connected == 1)) {
5370Sstevel@tonic-gate if (write(cvcd_pfd[0].fd, buf, s) !=
5380Sstevel@tonic-gate s) {
5390Sstevel@tonic-gate cvcd_err(LOG_ERR,
5400Sstevel@tonic-gate "lost data output");
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate } /* End forever loop */
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate #ifdef lint
5480Sstevel@tonic-gate /* NOTREACHED */
5490Sstevel@tonic-gate return (1);
5500Sstevel@tonic-gate #endif /* lint */
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate static void
5540Sstevel@tonic-gate cvcd_reject(int fd)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate struct t_call *tcall;
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate tcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
5590Sstevel@tonic-gate if (tcall == (struct t_call *)NULL) {
5600Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: t_alloc: %s",
5610Sstevel@tonic-gate t_errlist[t_errno]);
5620Sstevel@tonic-gate return;
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate if (t_listen(fd, tcall) == -1) {
5650Sstevel@tonic-gate if (t_errno == TNODATA) {
5660Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: No client data!");
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: t_listen: %s",
5690Sstevel@tonic-gate t_errlist[t_errno]);
5700Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
5710Sstevel@tonic-gate return;
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate if (t_snddis(fd, tcall) < 0) {
5740Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_reject: t_snddis: %s",
5750Sstevel@tonic-gate t_errlist[t_errno]);
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate static void
5810Sstevel@tonic-gate cvcd_connect(int fd, struct pollfd *pfd)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate struct t_call *tcall;
5840Sstevel@tonic-gate int newfd;
5850Sstevel@tonic-gate struct sockaddr_in *peer;
5860Sstevel@tonic-gate int badpeer = 1;
5870Sstevel@tonic-gate struct hostent *he;
5880Sstevel@tonic-gate struct netbuf netbuf;
5890Sstevel@tonic-gate char addr[100];
5900Sstevel@tonic-gate ulong_t tmpaddr; /* network byte order */
5910Sstevel@tonic-gate char **pp;
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate tcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
5940Sstevel@tonic-gate if (tcall == (struct t_call *)NULL) {
5950Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: t_alloc: %s",
5960Sstevel@tonic-gate t_errlist[t_errno]);
5970Sstevel@tonic-gate return;
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate if (t_listen(fd, tcall) == -1) {
6000Sstevel@tonic-gate if (t_errno == TNODATA) {
6010Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: No client data!");
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate cvcd_err(LOG_ERR, "cnctip_connect: t_listen: %s",
6040Sstevel@tonic-gate t_errlist[t_errno]);
6050Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
6060Sstevel@tonic-gate return;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate if (pfd[0].fd != -1) {
6090Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: no free file descriptors!");
6100Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
6110Sstevel@tonic-gate return;
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate newfd = t_open(TCP_DEV, O_RDWR|O_NDELAY, NULL);
6140Sstevel@tonic-gate if (newfd == -1) {
6150Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: t_open: %s",
6160Sstevel@tonic-gate t_errlist[t_errno]);
6170Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
6180Sstevel@tonic-gate return;
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate if (t_accept(fd, newfd, tcall) < 0) {
6210Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_connect: t_accept: %s",
6220Sstevel@tonic-gate t_errlist[t_errno]);
6230Sstevel@tonic-gate t_close(newfd);
6240Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
6250Sstevel@tonic-gate return;
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate t_free((char *)tcall, T_CALL);
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * If /etc/ssphostname doesnt exists, dont bother verifying
6310Sstevel@tonic-gate * peer since we cant do gethostbyname.
6320Sstevel@tonic-gate */
6330Sstevel@tonic-gate if (peercheck == 1) {
6340Sstevel@tonic-gate he = gethostbyname(ssphostname);
6350Sstevel@tonic-gate if (he == NULL) {
6360Sstevel@tonic-gate cvcd_err(LOG_ERR, "gethostbyname: %s",
6370Sstevel@tonic-gate strerror(h_errno));
6380Sstevel@tonic-gate cvcd_err(LOG_ERR, "unable to get SSP name %s!",
6390Sstevel@tonic-gate ssphostname);
6400Sstevel@tonic-gate exit(1);
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate * Verify peer is from specified host by comparing the
6440Sstevel@tonic-gate * address (in network byte order) of the TLI endpoint
6450Sstevel@tonic-gate * and the address (in network byte order) of the ssp
6460Sstevel@tonic-gate * (using the hostname found in /etc/ssphostname).
6470Sstevel@tonic-gate */
6480Sstevel@tonic-gate (void) memset(addr, 0, 100);
6490Sstevel@tonic-gate netbuf.buf = addr;
6500Sstevel@tonic-gate netbuf.len = 0;
6510Sstevel@tonic-gate netbuf.maxlen = 100;
6520Sstevel@tonic-gate if (ioctl(newfd, TI_GETPEERNAME, &netbuf) < 0) {
6530Sstevel@tonic-gate cvcd_err(LOG_ERR, "ioctl(TI_GETPEERNAME): %s",
6540Sstevel@tonic-gate strerror(errno));
6550Sstevel@tonic-gate t_close(newfd);
6560Sstevel@tonic-gate return;
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate * cvcd doesn't check multi-homed ssphostname
6610Sstevel@tonic-gate * properly (only checks 1st address)
6620Sstevel@tonic-gate */
6630Sstevel@tonic-gate peer = (struct sockaddr_in *)addr;
6640Sstevel@tonic-gate for (pp = he->h_addr_list; *pp != 0; pp++) {
6650Sstevel@tonic-gate tmpaddr = htonl(*(ulong_t *)*pp);
6660Sstevel@tonic-gate if (memcmp(&peer->sin_addr.s_addr, &tmpaddr,
6670Sstevel@tonic-gate he->h_length) == 0) {
6680Sstevel@tonic-gate badpeer = 0;
6690Sstevel@tonic-gate break;
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate if (badpeer) {
6740Sstevel@tonic-gate cvcd_err(LOG_ERR, CONREF);
6750Sstevel@tonic-gate cvcd_err(LOG_ERR, "remote host = %s.",
6760Sstevel@tonic-gate inet_ntoa(peer->sin_addr));
6770Sstevel@tonic-gate t_close(newfd);
6780Sstevel@tonic-gate return;
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate pfd[0].fd = newfd;
6820Sstevel@tonic-gate pfd[0].events = POLLIN;
6830Sstevel@tonic-gate connected = 1;
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate /*
6870Sstevel@tonic-gate * Read in data from client.
6880Sstevel@tonic-gate */
6890Sstevel@tonic-gate static void
6900Sstevel@tonic-gate cvcd_read(struct pollfd *pd)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate register char *data;
6930Sstevel@tonic-gate register int fd = pd[0].fd;
6940Sstevel@tonic-gate char buf[MAXPKTSZ];
6950Sstevel@tonic-gate int flags = 0;
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate data = buf;
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate if (pd[0].revents & POLLIN) {
7000Sstevel@tonic-gate int n;
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate if ((n = t_rcv(fd, data, MAXPKTSZ, &flags)) == -1) {
7030Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_read: t_rcv: %s",
7040Sstevel@tonic-gate t_errlist[t_errno]);
7050Sstevel@tonic-gate (void) t_close(pd[0].fd);
7060Sstevel@tonic-gate pd[0].fd = -1;
7070Sstevel@tonic-gate connected = 0;
7080Sstevel@tonic-gate return;
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate if (flags & T_EXPEDITED) {
7110Sstevel@tonic-gate if (n != 1) {
7120Sstevel@tonic-gate cvcd_err(LOG_ERR,
7130Sstevel@tonic-gate "cvcd_read: %d bytes EXD!!",
7140Sstevel@tonic-gate n);
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate /*
7170Sstevel@tonic-gate * Deal with cvcd_ssp_commands.
7180Sstevel@tonic-gate */
7190Sstevel@tonic-gate switch (data[n-1]) {
7200Sstevel@tonic-gate case CVC_CONN_BREAK :
7210Sstevel@tonic-gate cvcd_ioctl(rconsfd, CVC_BREAK);
7220Sstevel@tonic-gate break;
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate case CVC_CONN_DIS :
7250Sstevel@tonic-gate (void) t_close(pd[0].fd);
7260Sstevel@tonic-gate pd[0].fd = -1;
7270Sstevel@tonic-gate cvcd_ioctl(rconsfd, CVC_DISCONNECT);
7280Sstevel@tonic-gate connected = 0;
7290Sstevel@tonic-gate break;
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate case CVC_CONN_STAT :
7320Sstevel@tonic-gate cvcd_status(fd);
7330Sstevel@tonic-gate break;
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate default :
7360Sstevel@tonic-gate cvcd_err(LOG_ERR,
7370Sstevel@tonic-gate "Illegal cmd 0x%x", buf[n-1]);
7380Sstevel@tonic-gate break;
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate } else {
7410Sstevel@tonic-gate if (((data[0] & 0377) == 0377) &&
7420Sstevel@tonic-gate ((data[1] & 0377) == 0377)) {
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate * Pass on window size changes (TIOCSWINSZ).
7450Sstevel@tonic-gate */
7460Sstevel@tonic-gate cvcd_winch(rconsfd, data, n);
7470Sstevel@tonic-gate (void) memset(data, 0, n);
7480Sstevel@tonic-gate } else {
7490Sstevel@tonic-gate cvcd_write(buf, n);
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate static void
7570Sstevel@tonic-gate cvcd_ioctl(int fd, int flags)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate struct strioctl cmd;
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate cmd.ic_cmd = flags;
7620Sstevel@tonic-gate cmd.ic_timout = 0;
7630Sstevel@tonic-gate cmd.ic_len = 0;
7640Sstevel@tonic-gate cmd.ic_dp = NULL;
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate if (ioctl(fd, I_STR, &cmd) == -1) {
7670Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_ioctl: %s", strerror(errno));
7680Sstevel@tonic-gate exit(1);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate /* ARGSUSED */
7740Sstevel@tonic-gate static void
7750Sstevel@tonic-gate cvcd_status(int fd)
7760Sstevel@tonic-gate {
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate /*
7810Sstevel@tonic-gate * Write input to console - called from cvcd_read.
7820Sstevel@tonic-gate */
7830Sstevel@tonic-gate static void
7840Sstevel@tonic-gate cvcd_write(char *data, int size)
7850Sstevel@tonic-gate {
7860Sstevel@tonic-gate int n;
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate if ((n = write(rconsfd, data, size)) == -1) {
7890Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_write: write: %s", strerror(errno));
7900Sstevel@tonic-gate exit(1);
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate if (n != size) {
7930Sstevel@tonic-gate cvcd_err(LOG_ERR, "cvcd_write: wrote %d of %d bytes", n, size);
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate static void
7980Sstevel@tonic-gate usage()
7990Sstevel@tonic-gate {
8000Sstevel@tonic-gate #if defined(DEBUG)
8010Sstevel@tonic-gate (void) printf("%s [-d] [-p port]\n", progname);
8020Sstevel@tonic-gate #else
8030Sstevel@tonic-gate (void) printf("%s -r [ssp host]\n", progname);
8040Sstevel@tonic-gate #endif /* DEBUG */
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate /*
8080Sstevel@tonic-gate * cvcd_err ()
8090Sstevel@tonic-gate *
8100Sstevel@tonic-gate * Description:
8110Sstevel@tonic-gate * Log messages via syslog daemon.
8120Sstevel@tonic-gate *
8130Sstevel@tonic-gate * Input:
8140Sstevel@tonic-gate * code - logging code
8150Sstevel@tonic-gate * format - messages to log
8160Sstevel@tonic-gate *
8170Sstevel@tonic-gate * Output:
8180Sstevel@tonic-gate * void
8190Sstevel@tonic-gate *
8200Sstevel@tonic-gate */
8210Sstevel@tonic-gate static void
8220Sstevel@tonic-gate cvcd_err(int code, char *format, ...)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate va_list varg_ptr;
8250Sstevel@tonic-gate char buf[MAXPKTSZ];
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate va_start(varg_ptr, format);
8280Sstevel@tonic-gate (void) vsprintf(buf, format, varg_ptr);
8290Sstevel@tonic-gate va_end(varg_ptr);
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate if (debug == 0)
8320Sstevel@tonic-gate syslog(code, buf);
8330Sstevel@tonic-gate else
8340Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", progname, buf);
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate /*
8380Sstevel@tonic-gate * Handle a "control" request (signaled by magic being present)
8390Sstevel@tonic-gate * in the data stream. For now, we are only willing to handle
8400Sstevel@tonic-gate * window size changes.
8410Sstevel@tonic-gate */
8420Sstevel@tonic-gate void
8430Sstevel@tonic-gate cvcd_winch(int pty, char *cp, int n)
8440Sstevel@tonic-gate {
8450Sstevel@tonic-gate struct winsize w;
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
8480Sstevel@tonic-gate return;
8490Sstevel@tonic-gate (void) memcpy(&w, cp + 4, sizeof (w));
8500Sstevel@tonic-gate w.ws_row = ntohs(w.ws_row);
8510Sstevel@tonic-gate w.ws_col = ntohs(w.ws_col);
8520Sstevel@tonic-gate w.ws_xpixel = ntohs(w.ws_xpixel);
8530Sstevel@tonic-gate w.ws_ypixel = ntohs(w.ws_ypixel);
8540Sstevel@tonic-gate (void) ioctl(pty, TIOCSWINSZ, &w);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate /*
8590Sstevel@tonic-gate * Return class ID and maximum priority of it.
8600Sstevel@tonic-gate * Input:
8610Sstevel@tonic-gate * name: is class name (either TS or RT).
8620Sstevel@tonic-gate * maxpri: maximum priority for the class, returned in *maxpri.
8630Sstevel@tonic-gate * Output:
8640Sstevel@tonic-gate * pc_cid: class ID
8650Sstevel@tonic-gate */
8660Sstevel@tonic-gate static id_t
8670Sstevel@tonic-gate schedinfo(char *name, short *maxpri)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate pcinfo_t info;
8700Sstevel@tonic-gate tsinfo_t *tsinfop;
8710Sstevel@tonic-gate rtinfo_t *rtinfop;
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate (void) strcpy(info.pc_clname, name);
8740Sstevel@tonic-gate if (priocntl(0L, 0L, PC_GETCID, (caddr_t)&info) == -1L) {
8750Sstevel@tonic-gate return (-1);
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate if (strcmp(name, "TS") == 0) { /* Time Shared */
8780Sstevel@tonic-gate tsinfop = (struct tsinfo *)info.pc_clinfo;
8790Sstevel@tonic-gate *maxpri = tsinfop->ts_maxupri;
8800Sstevel@tonic-gate } else if (strcmp(name, "RT") == 0) { /* Real Time */
8810Sstevel@tonic-gate rtinfop = (struct rtinfo *)info.pc_clinfo;
8820Sstevel@tonic-gate *maxpri = rtinfop->rt_maxpri;
8830Sstevel@tonic-gate } else {
8840Sstevel@tonic-gate return (-1);
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate return (info.pc_cid);
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate /*
8910Sstevel@tonic-gate * set the tli options for the given endpoint represented by fd
8920Sstevel@tonic-gate */
8930Sstevel@tonic-gate static void
8940Sstevel@tonic-gate cvcd_setopt(int fd, int name)
8950Sstevel@tonic-gate {
8960Sstevel@tonic-gate struct t_optmgmt *topt, *tropt;
8970Sstevel@tonic-gate struct opthdr *sockopt;
8980Sstevel@tonic-gate int on = 1;
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate topt = (struct t_optmgmt *)t_alloc(fd, T_OPTMGMT, 0);
9010Sstevel@tonic-gate if (topt == NULL) {
9020Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_alloc: %s", t_errlist[t_errno]);
9030Sstevel@tonic-gate exit(1);
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate tropt = (struct t_optmgmt *)t_alloc(fd, T_OPTMGMT, 0);
9060Sstevel@tonic-gate if (tropt == NULL) {
9070Sstevel@tonic-gate cvcd_err(LOG_ERR, "t_alloc: %s", t_errlist[t_errno]);
9080Sstevel@tonic-gate exit(1);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate topt->opt.buf = (char *)malloc(sizeof (struct opthdr) + sizeof (int));
9110Sstevel@tonic-gate topt->opt.maxlen = 0;
9120Sstevel@tonic-gate topt->opt.len = sizeof (struct opthdr) + sizeof (int);
9130Sstevel@tonic-gate topt->flags = T_NEGOTIATE;
9140Sstevel@tonic-gate sockopt = (struct opthdr *)topt->opt.buf;
9150Sstevel@tonic-gate sockopt->level = SOL_SOCKET;
9160Sstevel@tonic-gate sockopt->name = name;
9170Sstevel@tonic-gate sockopt->len = sizeof (int);
9180Sstevel@tonic-gate (void) memcpy((char *)(topt->opt.buf + sizeof (struct opthdr)),
9190Sstevel@tonic-gate (char *)&on, sizeof (on));
9200Sstevel@tonic-gate tropt->opt.buf = (char *)malloc(sizeof (struct opthdr) + sizeof (int));
9210Sstevel@tonic-gate tropt->opt.maxlen = sizeof (struct opthdr) + sizeof (int);
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate if (t_optmgmt(fd, topt, tropt) == -1) {
9240Sstevel@tonic-gate t_error("t_optmgmt");
9250Sstevel@tonic-gate exit(1);
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate t_free((char *)topt, T_OPTMGMT);
9290Sstevel@tonic-gate t_free((char *)tropt, T_OPTMGMT);
9300Sstevel@tonic-gate }
931