xref: /freebsd/usr.sbin/ppp/tty.c (revision 8dbb1e2b)
15d9e6103SBrian Somers /*-
25d9e6103SBrian Somers  * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
35d9e6103SBrian Somers  * All rights reserved.
45d9e6103SBrian Somers  *
55d9e6103SBrian Somers  * Redistribution and use in source and binary forms, with or without
65d9e6103SBrian Somers  * modification, are permitted provided that the following conditions
75d9e6103SBrian Somers  * are met:
85d9e6103SBrian Somers  * 1. Redistributions of source code must retain the above copyright
95d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer.
105d9e6103SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
115d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
125d9e6103SBrian Somers  *    documentation and/or other materials provided with the distribution.
135d9e6103SBrian Somers  *
145d9e6103SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155d9e6103SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165d9e6103SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175d9e6103SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185d9e6103SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195d9e6103SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205d9e6103SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215d9e6103SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225d9e6103SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235d9e6103SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245d9e6103SBrian Somers  * SUCH DAMAGE.
255d9e6103SBrian Somers  *
268dbb1e2bSBrian Somers  *	$Id: tty.c,v 1.2 1999/05/12 09:49:07 brian Exp $
275d9e6103SBrian Somers  */
285d9e6103SBrian Somers 
295d9e6103SBrian Somers #include <sys/param.h>
305d9e6103SBrian Somers #include <sys/socket.h>
315d9e6103SBrian Somers #include <netinet/in.h>
325d9e6103SBrian Somers #include <arpa/inet.h>
335d9e6103SBrian Somers #include <netdb.h>
345d9e6103SBrian Somers #include <netinet/in_systm.h>
355d9e6103SBrian Somers #include <netinet/ip.h>
365d9e6103SBrian Somers #include <sys/un.h>
375d9e6103SBrian Somers #if defined(__OpenBSD__) || defined(__NetBSD__)
385d9e6103SBrian Somers #include <sys/ioctl.h>
395d9e6103SBrian Somers #include <util.h>
405d9e6103SBrian Somers #else
415d9e6103SBrian Somers #include <libutil.h>
425d9e6103SBrian Somers #endif
435d9e6103SBrian Somers 
445d9e6103SBrian Somers #include <errno.h>
455d9e6103SBrian Somers #include <fcntl.h>
465d9e6103SBrian Somers #include <paths.h>
475d9e6103SBrian Somers #include <stdio.h>
485d9e6103SBrian Somers #include <stdlib.h>
495d9e6103SBrian Somers #include <string.h>
505d9e6103SBrian Somers #include <sys/wait.h>
516815097bSBrian Somers #include <sys/uio.h>
525d9e6103SBrian Somers #include <termios.h>
535d9e6103SBrian Somers #include <unistd.h>
545d9e6103SBrian Somers 
555d9e6103SBrian Somers #include "layer.h"
565d9e6103SBrian Somers #include "defs.h"
575d9e6103SBrian Somers #include "mbuf.h"
585d9e6103SBrian Somers #include "log.h"
595d9e6103SBrian Somers #include "id.h"
605d9e6103SBrian Somers #include "sync.h"
615d9e6103SBrian Somers #include "timer.h"
625d9e6103SBrian Somers #include "lqr.h"
635d9e6103SBrian Somers #include "hdlc.h"
645d9e6103SBrian Somers #include "throughput.h"
655d9e6103SBrian Somers #include "fsm.h"
665d9e6103SBrian Somers #include "lcp.h"
675d9e6103SBrian Somers #include "ccp.h"
685d9e6103SBrian Somers #include "link.h"
695d9e6103SBrian Somers #include "async.h"
705d9e6103SBrian Somers #include "slcompress.h"
715d9e6103SBrian Somers #include "iplist.h"
725d9e6103SBrian Somers #include "ipcp.h"
735d9e6103SBrian Somers #include "filter.h"
745d9e6103SBrian Somers #include "descriptor.h"
755d9e6103SBrian Somers #include "physical.h"
765d9e6103SBrian Somers #include "mp.h"
775d9e6103SBrian Somers #ifndef NORADIUS
785d9e6103SBrian Somers #include "radius.h"
795d9e6103SBrian Somers #endif
805d9e6103SBrian Somers #include "chat.h"
815d9e6103SBrian Somers #include "command.h"
825d9e6103SBrian Somers #include "bundle.h"
835d9e6103SBrian Somers #include "prompt.h"
845d9e6103SBrian Somers #include "auth.h"
855d9e6103SBrian Somers #include "chap.h"
865d9e6103SBrian Somers #include "cbcp.h"
875d9e6103SBrian Somers #include "datalink.h"
885d9e6103SBrian Somers #include "tty.h"
895d9e6103SBrian Somers 
906815097bSBrian Somers #define	Online(dev)	((dev)->mbits & TIOCM_CD)
916815097bSBrian Somers 
926815097bSBrian Somers struct ttydevice {
936815097bSBrian Somers   struct device dev;		/* What struct physical knows about */
946815097bSBrian Somers   struct pppTimer Timer;	/* CD checks */
956815097bSBrian Somers   int mbits;			/* Current DCD status */
966815097bSBrian Somers   struct termios ios;		/* To be able to reset from raw mode */
976815097bSBrian Somers };
986815097bSBrian Somers 
996815097bSBrian Somers #define device2tty(d) ((d)->type == TTY_DEVICE ? (struct ttydevice *)d : NULL)
1005d9e6103SBrian Somers 
1015d9e6103SBrian Somers static int
1025d9e6103SBrian Somers tty_Lock(struct physical *p, int tunno)
1035d9e6103SBrian Somers {
1045d9e6103SBrian Somers   int res;
1055d9e6103SBrian Somers   FILE *lockfile;
1065d9e6103SBrian Somers   char fn[MAXPATHLEN];
1075d9e6103SBrian Somers 
1085d9e6103SBrian Somers   if (*p->name.full != '/')
1095d9e6103SBrian Somers     return 0;
1105d9e6103SBrian Somers 
1115d9e6103SBrian Somers   if (p->type != PHYS_DIRECT &&
1125d9e6103SBrian Somers       (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
1135d9e6103SBrian Somers     if (res == UU_LOCK_INUSE)
1145d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
1155d9e6103SBrian Somers     else
1165d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
1175d9e6103SBrian Somers                  p->link.name, p->name.full, uu_lockerr(res));
1185d9e6103SBrian Somers     return (-1);
1195d9e6103SBrian Somers   }
1205d9e6103SBrian Somers 
1215d9e6103SBrian Somers   snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
1225d9e6103SBrian Somers   lockfile = ID0fopen(fn, "w");
1235d9e6103SBrian Somers   if (lockfile != NULL) {
1245d9e6103SBrian Somers     fprintf(lockfile, "%s%d\n", TUN_NAME, tunno);
1255d9e6103SBrian Somers     fclose(lockfile);
1265d9e6103SBrian Somers   }
1275d9e6103SBrian Somers #ifndef RELEASE_CRUNCH
1285d9e6103SBrian Somers   else
1295d9e6103SBrian Somers     log_Printf(LogALERT, "%s: Can't create %s: %s\n",
1305d9e6103SBrian Somers                p->link.name, fn, strerror(errno));
1315d9e6103SBrian Somers #endif
1325d9e6103SBrian Somers 
1335d9e6103SBrian Somers   return 0;
1345d9e6103SBrian Somers }
1355d9e6103SBrian Somers 
1365d9e6103SBrian Somers static void
1375d9e6103SBrian Somers tty_Unlock(struct physical *p)
1385d9e6103SBrian Somers {
1395d9e6103SBrian Somers   char fn[MAXPATHLEN];
1405d9e6103SBrian Somers 
1415d9e6103SBrian Somers   if (*p->name.full != '/')
1425d9e6103SBrian Somers     return;
1435d9e6103SBrian Somers 
1445d9e6103SBrian Somers   snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
1455d9e6103SBrian Somers #ifndef RELEASE_CRUNCH
1465d9e6103SBrian Somers   if (ID0unlink(fn) == -1)
1475d9e6103SBrian Somers     log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
1485d9e6103SBrian Somers                p->link.name, fn, strerror(errno));
1495d9e6103SBrian Somers #else
1505d9e6103SBrian Somers   ID0unlink(fn);
1515d9e6103SBrian Somers #endif
1525d9e6103SBrian Somers 
1535d9e6103SBrian Somers   if (p->type != PHYS_DIRECT && ID0uu_unlock(p->name.base) == -1)
1545d9e6103SBrian Somers     log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name, fn);
1555d9e6103SBrian Somers }
1565d9e6103SBrian Somers 
1578dbb1e2bSBrian Somers static struct device *
1585d9e6103SBrian Somers tty_SetupDevice(struct physical *p)
1595d9e6103SBrian Somers {
1608dbb1e2bSBrian Somers   struct ttydevice *dev;
1618dbb1e2bSBrian Somers   struct termios ios;
1625d9e6103SBrian Somers   int oldflag;
1635d9e6103SBrian Somers 
1648dbb1e2bSBrian Somers   if ((dev = malloc(sizeof *dev)) == NULL)
1658dbb1e2bSBrian Somers     return NULL;
1668dbb1e2bSBrian Somers 
1678dbb1e2bSBrian Somers   tcgetattr(p->fd, &ios);
1688dbb1e2bSBrian Somers   dev->ios = ios;
1695d9e6103SBrian Somers 
1705d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: tty_SetupDevice: physical (get): fd = %d,"
1715d9e6103SBrian Somers              " iflag = %lx, oflag = %lx, cflag = %lx\n", p->link.name, p->fd,
1728dbb1e2bSBrian Somers              (u_long)ios.c_iflag, (u_long)ios.c_oflag, (u_long)ios.c_cflag);
1735d9e6103SBrian Somers 
1748dbb1e2bSBrian Somers   cfmakeraw(&ios);
1755d9e6103SBrian Somers   if (p->cfg.rts_cts)
1768dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
1775d9e6103SBrian Somers   else {
1788dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL;
1798dbb1e2bSBrian Somers     ios.c_iflag |= IXOFF;
1805d9e6103SBrian Somers   }
1818dbb1e2bSBrian Somers   ios.c_iflag |= IXON;
1825d9e6103SBrian Somers   if (p->type != PHYS_DEDICATED)
1838dbb1e2bSBrian Somers     ios.c_cflag |= HUPCL;
1845d9e6103SBrian Somers 
1855d9e6103SBrian Somers   if (p->type != PHYS_DIRECT) {
1865d9e6103SBrian Somers       /* Change tty speed when we're not in -direct mode */
1878dbb1e2bSBrian Somers       ios.c_cflag &= ~(CSIZE | PARODD | PARENB);
1888dbb1e2bSBrian Somers       ios.c_cflag |= p->cfg.parity;
1898dbb1e2bSBrian Somers       if (cfsetspeed(&ios, IntToSpeed(p->cfg.speed)) == -1)
1905d9e6103SBrian Somers 	log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n",
1915d9e6103SBrian Somers 		  p->link.name, p->name.full, p->cfg.speed);
1925d9e6103SBrian Somers   }
1938dbb1e2bSBrian Somers   tcsetattr(p->fd, TCSADRAIN, &ios);
1945d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: physical (put): iflag = %lx, oflag = %lx, "
1958dbb1e2bSBrian Somers             "cflag = %lx\n", p->link.name, (u_long)ios.c_iflag,
1968dbb1e2bSBrian Somers             (u_long)ios.c_oflag, (u_long)ios.c_cflag);
1975d9e6103SBrian Somers 
1986815097bSBrian Somers   if (ioctl(p->fd, TIOCMGET, &dev->mbits) == -1) {
1995d9e6103SBrian Somers     if (p->type != PHYS_DIRECT) {
2005d9e6103SBrian Somers       log_Printf(LogWARN, "%s: Open: Cannot get physical status: %s\n",
2015d9e6103SBrian Somers                  p->link.name, strerror(errno));
2025d9e6103SBrian Somers       physical_Close(p);
2038dbb1e2bSBrian Somers       return NULL;
2045d9e6103SBrian Somers     } else
2056815097bSBrian Somers       dev->mbits = TIOCM_CD;
2065d9e6103SBrian Somers   }
2075d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Open: physical control = %o\n",
2086815097bSBrian Somers              p->link.name, dev->mbits);
2095d9e6103SBrian Somers 
2105d9e6103SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
2115d9e6103SBrian Somers   if (oldflag < 0) {
2125d9e6103SBrian Somers     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
2135d9e6103SBrian Somers                p->link.name, strerror(errno));
2145d9e6103SBrian Somers     physical_Close(p);
2158dbb1e2bSBrian Somers     return NULL;
2165d9e6103SBrian Somers   } else
2175d9e6103SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
2185d9e6103SBrian Somers 
2196815097bSBrian Somers   physical_SetupStack(p, PHYSICAL_NOFORCE);
2208dbb1e2bSBrian Somers 
2218dbb1e2bSBrian Somers   return &dev->dev;
2225d9e6103SBrian Somers }
2235d9e6103SBrian Somers 
2245d9e6103SBrian Somers /*
2255d9e6103SBrian Somers  * tty_Timeout() watches the DCD signal and mentions it if it's status
2265d9e6103SBrian Somers  * changes.
2275d9e6103SBrian Somers  */
2285d9e6103SBrian Somers static void
2295d9e6103SBrian Somers tty_Timeout(void *data)
2305d9e6103SBrian Somers {
2315d9e6103SBrian Somers   struct physical *p = data;
2326815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2335d9e6103SBrian Somers   int ombits, change;
2345d9e6103SBrian Somers 
2356815097bSBrian Somers   timer_Stop(&dev->Timer);
2366815097bSBrian Somers   dev->Timer.load = SECTICKS;		/* Once a second please */
2376815097bSBrian Somers   timer_Start(&dev->Timer);
2386815097bSBrian Somers   ombits = dev->mbits;
2395d9e6103SBrian Somers 
2405d9e6103SBrian Somers   if (p->fd >= 0) {
2416815097bSBrian Somers     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
2425d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: ioctl error (%s)!\n", p->link.name,
2435d9e6103SBrian Somers                  strerror(errno));
2445d9e6103SBrian Somers       datalink_Down(p->dl, CLOSE_NORMAL);
2456815097bSBrian Somers       timer_Stop(&dev->Timer);
2465d9e6103SBrian Somers       return;
2475d9e6103SBrian Somers     }
2485d9e6103SBrian Somers   } else
2496815097bSBrian Somers     dev->mbits = 0;
2505d9e6103SBrian Somers 
2515d9e6103SBrian Somers   if (ombits == -1) {
2525d9e6103SBrian Somers     /* First time looking for carrier */
2536815097bSBrian Somers     if (Online(dev))
2545d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: %s: CD detected\n", p->link.name, p->name.full);
2555d9e6103SBrian Somers     else if (p->cfg.cd.required) {
2565d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s: Required CD not detected\n",
2575d9e6103SBrian Somers                  p->link.name, p->name.full);
2585d9e6103SBrian Somers       datalink_Down(p->dl, CLOSE_NORMAL);
2595d9e6103SBrian Somers     } else {
2605d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s doesn't support CD\n",
2615d9e6103SBrian Somers                  p->link.name, p->name.full);
2626815097bSBrian Somers       timer_Stop(&dev->Timer);
2636815097bSBrian Somers       dev->mbits = TIOCM_CD;
2645d9e6103SBrian Somers     }
2655d9e6103SBrian Somers   } else {
2666815097bSBrian Somers     change = ombits ^ dev->mbits;
2675d9e6103SBrian Somers     if (change & TIOCM_CD) {
2686815097bSBrian Somers       if (dev->mbits & TIOCM_CD)
2695d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
2705d9e6103SBrian Somers       else {
2715d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
2725d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
2735d9e6103SBrian Somers         datalink_Down(p->dl, CLOSE_NORMAL);
2746815097bSBrian Somers         timer_Stop(&dev->Timer);
2755d9e6103SBrian Somers       }
2765d9e6103SBrian Somers     } else
2775d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
2786815097bSBrian Somers                  Online(dev) ? "on" : "off");
2795d9e6103SBrian Somers   }
2805d9e6103SBrian Somers }
2815d9e6103SBrian Somers 
2825d9e6103SBrian Somers static void
2835d9e6103SBrian Somers tty_StartTimer(struct physical *p)
2845d9e6103SBrian Somers {
2856815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2866815097bSBrian Somers 
2876815097bSBrian Somers   timer_Stop(&dev->Timer);
2886815097bSBrian Somers   dev->Timer.load = SECTICKS * p->cfg.cd.delay;
2896815097bSBrian Somers   dev->Timer.func = tty_Timeout;
2906815097bSBrian Somers   dev->Timer.name = "tty CD";
2916815097bSBrian Somers   dev->Timer.arg = p;
2925d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Using tty_Timeout [%p]\n",
2935d9e6103SBrian Somers              p->link.name, tty_Timeout);
2946815097bSBrian Somers   dev->mbits = -1;		/* So we know it's the first time */
2956815097bSBrian Somers   timer_Start(&dev->Timer);
2965d9e6103SBrian Somers }
2975d9e6103SBrian Somers 
2985d9e6103SBrian Somers static int
2995d9e6103SBrian Somers tty_Raw(struct physical *p)
3005d9e6103SBrian Somers {
3016815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3028dbb1e2bSBrian Somers   struct termios ios;
3035d9e6103SBrian Somers   int oldflag;
3045d9e6103SBrian Somers 
3055d9e6103SBrian Somers   if (physical_IsSync(p))
3065d9e6103SBrian Somers     return 1;
3075d9e6103SBrian Somers 
3085d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Entering physical_Raw\n", p->link.name);
3095d9e6103SBrian Somers 
3106815097bSBrian Somers   if (p->type != PHYS_DIRECT && p->fd >= 0 && !Online(dev))
3115d9e6103SBrian Somers     log_Printf(LogDEBUG, "%s: Raw: descriptor = %d, mbits = %x\n",
3126815097bSBrian Somers               p->link.name, p->fd, dev->mbits);
3135d9e6103SBrian Somers 
3148dbb1e2bSBrian Somers   tcgetattr(p->fd, &ios);
3158dbb1e2bSBrian Somers   cfmakeraw(&ios);
3165d9e6103SBrian Somers   if (p->cfg.rts_cts)
3178dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
3185d9e6103SBrian Somers   else
3198dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL;
3205d9e6103SBrian Somers 
3215d9e6103SBrian Somers   if (p->type != PHYS_DEDICATED)
3228dbb1e2bSBrian Somers     ios.c_cflag |= HUPCL;
3235d9e6103SBrian Somers 
3248dbb1e2bSBrian Somers   tcsetattr(p->fd, TCSANOW, &ios);
3255d9e6103SBrian Somers 
3265d9e6103SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
3275d9e6103SBrian Somers   if (oldflag < 0)
3285d9e6103SBrian Somers     return 0;
3295d9e6103SBrian Somers   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
3305d9e6103SBrian Somers 
3316815097bSBrian Somers   if (ioctl(p->fd, TIOCMGET, &dev->mbits) == 0)
3325d9e6103SBrian Somers     tty_StartTimer(p);
3335d9e6103SBrian Somers 
3345d9e6103SBrian Somers   return 1;
3355d9e6103SBrian Somers }
3365d9e6103SBrian Somers 
3375d9e6103SBrian Somers static void
3385d9e6103SBrian Somers tty_Offline(struct physical *p)
3395d9e6103SBrian Somers {
3406815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3416815097bSBrian Somers 
3425d9e6103SBrian Somers   if (p->fd >= 0) {
3436815097bSBrian Somers     timer_Stop(&dev->Timer);
3446815097bSBrian Somers     dev->mbits &= ~TIOCM_DTR;
3456815097bSBrian Somers     if (Online(dev)) {
3465d9e6103SBrian Somers       struct termios tio;
3475d9e6103SBrian Somers 
3485d9e6103SBrian Somers       tcgetattr(p->fd, &tio);
3495d9e6103SBrian Somers       if (cfsetspeed(&tio, B0) == -1)
3505d9e6103SBrian Somers         log_Printf(LogWARN, "%s: Unable to set physical to speed 0\n",
3515d9e6103SBrian Somers                    p->link.name);
3525d9e6103SBrian Somers       else
3535d9e6103SBrian Somers         tcsetattr(p->fd, TCSANOW, &tio);
3545d9e6103SBrian Somers     }
3555d9e6103SBrian Somers   }
3565d9e6103SBrian Somers }
3575d9e6103SBrian Somers 
3585d9e6103SBrian Somers static void
3595d9e6103SBrian Somers tty_Cooked(struct physical *p)
3605d9e6103SBrian Somers {
3616815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3625d9e6103SBrian Somers   int oldflag;
3635d9e6103SBrian Somers 
3645d9e6103SBrian Somers   tcflush(p->fd, TCIOFLUSH);
3655d9e6103SBrian Somers   if (!physical_IsSync(p)) {
3666815097bSBrian Somers     tcsetattr(p->fd, TCSAFLUSH, &dev->ios);
3675d9e6103SBrian Somers     oldflag = fcntl(p->fd, F_GETFL, 0);
3685d9e6103SBrian Somers     if (oldflag == 0)
3695d9e6103SBrian Somers       fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
3705d9e6103SBrian Somers   }
3715d9e6103SBrian Somers }
3725d9e6103SBrian Somers 
3735d9e6103SBrian Somers static void
3746815097bSBrian Somers tty_StopTimer(struct physical *p)
3755d9e6103SBrian Somers {
3766815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3776815097bSBrian Somers 
3786815097bSBrian Somers   timer_Stop(&dev->Timer);
3795d9e6103SBrian Somers }
3805d9e6103SBrian Somers 
3815d9e6103SBrian Somers static void
3826815097bSBrian Somers tty_Free(struct physical *p)
3835d9e6103SBrian Somers {
3846815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3856815097bSBrian Somers 
3866815097bSBrian Somers   tty_Unlock(p);
3876815097bSBrian Somers   free(dev);
3885d9e6103SBrian Somers }
3895d9e6103SBrian Somers 
3905d9e6103SBrian Somers static int
3915d9e6103SBrian Somers tty_Speed(struct physical *p)
3925d9e6103SBrian Somers {
3938dbb1e2bSBrian Somers   struct termios ios;
3945d9e6103SBrian Somers 
3958dbb1e2bSBrian Somers   if (tcgetattr(p->fd, &ios) == -1)
3965d9e6103SBrian Somers     return 0;
3975d9e6103SBrian Somers 
3988dbb1e2bSBrian Somers   return SpeedToInt(cfgetispeed(&ios));
3995d9e6103SBrian Somers }
4005d9e6103SBrian Somers 
4015d9e6103SBrian Somers static const char *
4025d9e6103SBrian Somers tty_OpenInfo(struct physical *p)
4035d9e6103SBrian Somers {
4046815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4055d9e6103SBrian Somers   static char buf[13];
4065d9e6103SBrian Somers 
4076815097bSBrian Somers   if (Online(dev))
4085d9e6103SBrian Somers     strcpy(buf, "with");
4095d9e6103SBrian Somers   else
4105d9e6103SBrian Somers     strcpy(buf, "no");
4115d9e6103SBrian Somers   strcat(buf, " carrier");
4125d9e6103SBrian Somers   return buf;
4135d9e6103SBrian Somers }
4145d9e6103SBrian Somers 
4156815097bSBrian Somers static void
4166815097bSBrian Somers tty_device2iov(struct physical *p, struct iovec *iov, int *niov,
4176815097bSBrian Somers                int maxiov, pid_t newpid)
4186815097bSBrian Somers {
4196815097bSBrian Somers   struct ttydevice *dev = p ? device2tty(p->handler) : NULL;
4206815097bSBrian Somers 
4216815097bSBrian Somers   iov[*niov].iov_base = p ? p->handler : malloc(sizeof(struct ttydevice));
4226815097bSBrian Somers   iov[*niov].iov_len = sizeof(struct ttydevice);
4236815097bSBrian Somers   (*niov)++;
4246815097bSBrian Somers 
4256815097bSBrian Somers   if (dev->Timer.state != TIMER_STOPPED) {
4266815097bSBrian Somers     timer_Stop(&dev->Timer);
4276815097bSBrian Somers     dev->Timer.state = TIMER_RUNNING;
4286815097bSBrian Somers   }
4296815097bSBrian Somers }
4306815097bSBrian Somers 
4316815097bSBrian Somers static struct device basettydevice = {
4325d9e6103SBrian Somers   TTY_DEVICE,
4335d9e6103SBrian Somers   "tty",
4345d9e6103SBrian Somers   tty_Raw,
4355d9e6103SBrian Somers   tty_Offline,
4365d9e6103SBrian Somers   tty_Cooked,
4376815097bSBrian Somers   tty_StopTimer,
4386815097bSBrian Somers   tty_Free,
4396815097bSBrian Somers   NULL,
4406815097bSBrian Somers   NULL,
4416815097bSBrian Somers   tty_device2iov,
4425d9e6103SBrian Somers   tty_Speed,
4435d9e6103SBrian Somers   tty_OpenInfo
4445d9e6103SBrian Somers };
4456815097bSBrian Somers 
4466815097bSBrian Somers struct device *
4476815097bSBrian Somers tty_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
4486815097bSBrian Somers                int maxiov)
4496815097bSBrian Somers {
4506815097bSBrian Somers   if (type == TTY_DEVICE) {
4516815097bSBrian Somers     struct ttydevice *dev;
4526815097bSBrian Somers 
4536815097bSBrian Somers     /* It's one of ours !  Let's create the device */
4546815097bSBrian Somers 
4556815097bSBrian Somers     dev = (struct ttydevice *)iov[(*niov)++].iov_base;
4566815097bSBrian Somers     /* Refresh function pointers etc */
4576815097bSBrian Somers     memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
4586815097bSBrian Somers 
4596815097bSBrian Somers     physical_SetupStack(p, PHYSICAL_NOFORCE);
4606815097bSBrian Somers     if (dev->Timer.state != TIMER_STOPPED) {
4616815097bSBrian Somers       dev->Timer.state = TIMER_STOPPED;
4626815097bSBrian Somers       tty_StartTimer(p);
4636815097bSBrian Somers     }
4646815097bSBrian Somers     return &dev->dev;
4656815097bSBrian Somers   }
4666815097bSBrian Somers 
4676815097bSBrian Somers   return NULL;
4686815097bSBrian Somers }
4696815097bSBrian Somers 
4706815097bSBrian Somers struct device *
4716815097bSBrian Somers tty_Create(struct physical *p)
4726815097bSBrian Somers {
4736815097bSBrian Somers   if (p->fd >= 0 && isatty(p->fd)) {
4746815097bSBrian Somers     if (*p->name.full == '\0') {
4756815097bSBrian Somers       log_Printf(LogDEBUG, "%s: Input is a tty\n", p->link.name);
4766815097bSBrian Somers       physical_SetDevice(p, ttyname(p->fd));
4776815097bSBrian Somers       if (tty_Lock(p, p->dl->bundle->unit) == -1) {
4786815097bSBrian Somers         close(p->fd);
4796815097bSBrian Somers         p->fd = -1;
4808dbb1e2bSBrian Somers       } else
4818dbb1e2bSBrian Somers         return tty_SetupDevice(p);
4826815097bSBrian Somers     } else if (tty_Lock(p, p->dl->bundle->unit) != -1) {
4836815097bSBrian Somers       log_Printf(LogDEBUG, "%s: Opened %s\n", p->link.name, p->name.full);
4848dbb1e2bSBrian Somers       return tty_SetupDevice(p);
4856815097bSBrian Somers     }
4866815097bSBrian Somers   }
4876815097bSBrian Somers 
4886815097bSBrian Somers   return NULL;
4896815097bSBrian Somers }
490