xref: /freebsd/usr.sbin/ppp/tty.c (revision 4b698945)
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  *
264b698945SBrian Somers  *	$Id: tty.c,v 1.4 1999/05/13 19:29:40 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 
1575d9e6103SBrian Somers /*
1585d9e6103SBrian Somers  * tty_Timeout() watches the DCD signal and mentions it if it's status
1595d9e6103SBrian Somers  * changes.
1605d9e6103SBrian Somers  */
1615d9e6103SBrian Somers static void
1625d9e6103SBrian Somers tty_Timeout(void *data)
1635d9e6103SBrian Somers {
1645d9e6103SBrian Somers   struct physical *p = data;
1656815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1665d9e6103SBrian Somers   int ombits, change;
1675d9e6103SBrian Somers 
1686815097bSBrian Somers   timer_Stop(&dev->Timer);
1696815097bSBrian Somers   dev->Timer.load = SECTICKS;		/* Once a second please */
1706815097bSBrian Somers   timer_Start(&dev->Timer);
1716815097bSBrian Somers   ombits = dev->mbits;
1725d9e6103SBrian Somers 
1735d9e6103SBrian Somers   if (p->fd >= 0) {
1746815097bSBrian Somers     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
1755d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: ioctl error (%s)!\n", p->link.name,
1765d9e6103SBrian Somers                  strerror(errno));
1775d9e6103SBrian Somers       datalink_Down(p->dl, CLOSE_NORMAL);
1786815097bSBrian Somers       timer_Stop(&dev->Timer);
1795d9e6103SBrian Somers       return;
1805d9e6103SBrian Somers     }
1815d9e6103SBrian Somers   } else
1826815097bSBrian Somers     dev->mbits = 0;
1835d9e6103SBrian Somers 
1845d9e6103SBrian Somers   if (ombits == -1) {
1855d9e6103SBrian Somers     /* First time looking for carrier */
1866815097bSBrian Somers     if (Online(dev))
1875d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: %s: CD detected\n", p->link.name, p->name.full);
1885d9e6103SBrian Somers     else if (p->cfg.cd.required) {
1895d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s: Required CD not detected\n",
1905d9e6103SBrian Somers                  p->link.name, p->name.full);
1915d9e6103SBrian Somers       datalink_Down(p->dl, CLOSE_NORMAL);
1925d9e6103SBrian Somers     } else {
1935d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s doesn't support CD\n",
1945d9e6103SBrian Somers                  p->link.name, p->name.full);
1956815097bSBrian Somers       timer_Stop(&dev->Timer);
1966815097bSBrian Somers       dev->mbits = TIOCM_CD;
1975d9e6103SBrian Somers     }
1985d9e6103SBrian Somers   } else {
1996815097bSBrian Somers     change = ombits ^ dev->mbits;
2005d9e6103SBrian Somers     if (change & TIOCM_CD) {
2016815097bSBrian Somers       if (dev->mbits & TIOCM_CD)
2025d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
2035d9e6103SBrian Somers       else {
2045d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
2055d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
2065d9e6103SBrian Somers         datalink_Down(p->dl, CLOSE_NORMAL);
2076815097bSBrian Somers         timer_Stop(&dev->Timer);
2085d9e6103SBrian Somers       }
2095d9e6103SBrian Somers     } else
2105d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
2116815097bSBrian Somers                  Online(dev) ? "on" : "off");
2125d9e6103SBrian Somers   }
2135d9e6103SBrian Somers }
2145d9e6103SBrian Somers 
2155d9e6103SBrian Somers static void
2165d9e6103SBrian Somers tty_StartTimer(struct physical *p)
2175d9e6103SBrian Somers {
2186815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2196815097bSBrian Somers 
2206815097bSBrian Somers   timer_Stop(&dev->Timer);
2216815097bSBrian Somers   dev->Timer.load = SECTICKS * p->cfg.cd.delay;
2226815097bSBrian Somers   dev->Timer.func = tty_Timeout;
2236815097bSBrian Somers   dev->Timer.name = "tty CD";
2246815097bSBrian Somers   dev->Timer.arg = p;
2255d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Using tty_Timeout [%p]\n",
2265d9e6103SBrian Somers              p->link.name, tty_Timeout);
2276815097bSBrian Somers   dev->mbits = -1;		/* So we know it's the first time */
2286815097bSBrian Somers   timer_Start(&dev->Timer);
2295d9e6103SBrian Somers }
2305d9e6103SBrian Somers 
2315d9e6103SBrian Somers static int
2325d9e6103SBrian Somers tty_Raw(struct physical *p)
2335d9e6103SBrian Somers {
2346815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2358dbb1e2bSBrian Somers   struct termios ios;
2365d9e6103SBrian Somers   int oldflag;
2375d9e6103SBrian Somers 
2385d9e6103SBrian Somers   if (physical_IsSync(p))
2395d9e6103SBrian Somers     return 1;
2405d9e6103SBrian Somers 
2415d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Entering physical_Raw\n", p->link.name);
2425d9e6103SBrian Somers 
2436815097bSBrian Somers   if (p->type != PHYS_DIRECT && p->fd >= 0 && !Online(dev))
2445d9e6103SBrian Somers     log_Printf(LogDEBUG, "%s: Raw: descriptor = %d, mbits = %x\n",
2456815097bSBrian Somers               p->link.name, p->fd, dev->mbits);
2465d9e6103SBrian Somers 
2478dbb1e2bSBrian Somers   tcgetattr(p->fd, &ios);
2488dbb1e2bSBrian Somers   cfmakeraw(&ios);
2495d9e6103SBrian Somers   if (p->cfg.rts_cts)
2508dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
2515d9e6103SBrian Somers   else
2528dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL;
2535d9e6103SBrian Somers 
2545d9e6103SBrian Somers   if (p->type != PHYS_DEDICATED)
2558dbb1e2bSBrian Somers     ios.c_cflag |= HUPCL;
2565d9e6103SBrian Somers 
2578dbb1e2bSBrian Somers   tcsetattr(p->fd, TCSANOW, &ios);
2585d9e6103SBrian Somers 
2595d9e6103SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
2605d9e6103SBrian Somers   if (oldflag < 0)
2615d9e6103SBrian Somers     return 0;
2625d9e6103SBrian Somers   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
2635d9e6103SBrian Somers 
2646815097bSBrian Somers   if (ioctl(p->fd, TIOCMGET, &dev->mbits) == 0)
2655d9e6103SBrian Somers     tty_StartTimer(p);
2665d9e6103SBrian Somers 
2675d9e6103SBrian Somers   return 1;
2685d9e6103SBrian Somers }
2695d9e6103SBrian Somers 
2705d9e6103SBrian Somers static void
2715d9e6103SBrian Somers tty_Offline(struct physical *p)
2725d9e6103SBrian Somers {
2736815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2746815097bSBrian Somers 
2755d9e6103SBrian Somers   if (p->fd >= 0) {
2766815097bSBrian Somers     timer_Stop(&dev->Timer);
2776815097bSBrian Somers     dev->mbits &= ~TIOCM_DTR;
2786815097bSBrian Somers     if (Online(dev)) {
2795d9e6103SBrian Somers       struct termios tio;
2805d9e6103SBrian Somers 
2815d9e6103SBrian Somers       tcgetattr(p->fd, &tio);
2825d9e6103SBrian Somers       if (cfsetspeed(&tio, B0) == -1)
2835d9e6103SBrian Somers         log_Printf(LogWARN, "%s: Unable to set physical to speed 0\n",
2845d9e6103SBrian Somers                    p->link.name);
2855d9e6103SBrian Somers       else
2865d9e6103SBrian Somers         tcsetattr(p->fd, TCSANOW, &tio);
2875d9e6103SBrian Somers     }
2885d9e6103SBrian Somers   }
2895d9e6103SBrian Somers }
2905d9e6103SBrian Somers 
2915d9e6103SBrian Somers static void
2925d9e6103SBrian Somers tty_Cooked(struct physical *p)
2935d9e6103SBrian Somers {
2946815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2955d9e6103SBrian Somers   int oldflag;
2965d9e6103SBrian Somers 
2975d9e6103SBrian Somers   tcflush(p->fd, TCIOFLUSH);
2985d9e6103SBrian Somers   if (!physical_IsSync(p)) {
2996815097bSBrian Somers     tcsetattr(p->fd, TCSAFLUSH, &dev->ios);
3005d9e6103SBrian Somers     oldflag = fcntl(p->fd, F_GETFL, 0);
3015d9e6103SBrian Somers     if (oldflag == 0)
3025d9e6103SBrian Somers       fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
3035d9e6103SBrian Somers   }
3045d9e6103SBrian Somers }
3055d9e6103SBrian Somers 
3065d9e6103SBrian Somers static void
3076815097bSBrian Somers tty_StopTimer(struct physical *p)
3085d9e6103SBrian Somers {
3096815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3106815097bSBrian Somers 
3116815097bSBrian Somers   timer_Stop(&dev->Timer);
3125d9e6103SBrian Somers }
3135d9e6103SBrian Somers 
3145d9e6103SBrian Somers static void
3156815097bSBrian Somers tty_Free(struct physical *p)
3165d9e6103SBrian Somers {
3176815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3186815097bSBrian Somers 
3196815097bSBrian Somers   tty_Unlock(p);
3206815097bSBrian Somers   free(dev);
3215d9e6103SBrian Somers }
3225d9e6103SBrian Somers 
3235d9e6103SBrian Somers static int
3245d9e6103SBrian Somers tty_Speed(struct physical *p)
3255d9e6103SBrian Somers {
3268dbb1e2bSBrian Somers   struct termios ios;
3275d9e6103SBrian Somers 
3288dbb1e2bSBrian Somers   if (tcgetattr(p->fd, &ios) == -1)
3295d9e6103SBrian Somers     return 0;
3305d9e6103SBrian Somers 
3318dbb1e2bSBrian Somers   return SpeedToInt(cfgetispeed(&ios));
3325d9e6103SBrian Somers }
3335d9e6103SBrian Somers 
3345d9e6103SBrian Somers static const char *
3355d9e6103SBrian Somers tty_OpenInfo(struct physical *p)
3365d9e6103SBrian Somers {
3376815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
3385d9e6103SBrian Somers   static char buf[13];
3395d9e6103SBrian Somers 
3406815097bSBrian Somers   if (Online(dev))
3415d9e6103SBrian Somers     strcpy(buf, "with");
3425d9e6103SBrian Somers   else
3435d9e6103SBrian Somers     strcpy(buf, "no");
3445d9e6103SBrian Somers   strcat(buf, " carrier");
3455d9e6103SBrian Somers   return buf;
3465d9e6103SBrian Somers }
3475d9e6103SBrian Somers 
3486815097bSBrian Somers static void
3496815097bSBrian Somers tty_device2iov(struct physical *p, struct iovec *iov, int *niov,
3506815097bSBrian Somers                int maxiov, pid_t newpid)
3516815097bSBrian Somers {
3526815097bSBrian Somers   struct ttydevice *dev = p ? device2tty(p->handler) : NULL;
3536815097bSBrian Somers 
3546815097bSBrian Somers   iov[*niov].iov_base = p ? p->handler : malloc(sizeof(struct ttydevice));
3556815097bSBrian Somers   iov[*niov].iov_len = sizeof(struct ttydevice);
3566815097bSBrian Somers   (*niov)++;
3576815097bSBrian Somers 
3586815097bSBrian Somers   if (dev->Timer.state != TIMER_STOPPED) {
3596815097bSBrian Somers     timer_Stop(&dev->Timer);
3606815097bSBrian Somers     dev->Timer.state = TIMER_RUNNING;
3616815097bSBrian Somers   }
3626815097bSBrian Somers }
3636815097bSBrian Somers 
3646815097bSBrian Somers static struct device basettydevice = {
3655d9e6103SBrian Somers   TTY_DEVICE,
3665d9e6103SBrian Somers   "tty",
3675d9e6103SBrian Somers   tty_Raw,
3685d9e6103SBrian Somers   tty_Offline,
3695d9e6103SBrian Somers   tty_Cooked,
3706815097bSBrian Somers   tty_StopTimer,
3716815097bSBrian Somers   tty_Free,
3726815097bSBrian Somers   NULL,
3736815097bSBrian Somers   NULL,
3746815097bSBrian Somers   tty_device2iov,
3755d9e6103SBrian Somers   tty_Speed,
3765d9e6103SBrian Somers   tty_OpenInfo
3775d9e6103SBrian Somers };
3786815097bSBrian Somers 
37927be3ac6SBrian Somers static struct device *
38027be3ac6SBrian Somers tty_SetupDevice(struct physical *p)
38127be3ac6SBrian Somers {
38227be3ac6SBrian Somers   struct ttydevice *dev;
38327be3ac6SBrian Somers   struct termios ios;
38427be3ac6SBrian Somers   int oldflag;
38527be3ac6SBrian Somers 
38627be3ac6SBrian Somers   if ((dev = malloc(sizeof *dev)) == NULL)
38727be3ac6SBrian Somers     return NULL;
38827be3ac6SBrian Somers 
38927be3ac6SBrian Somers   memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
3904b698945SBrian Somers   memset(&dev->Timer, '\0', sizeof dev->Timer);
39127be3ac6SBrian Somers   tcgetattr(p->fd, &ios);
39227be3ac6SBrian Somers   dev->ios = ios;
39327be3ac6SBrian Somers 
39427be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: tty_SetupDevice: physical (get): fd = %d,"
39527be3ac6SBrian Somers              " iflag = %lx, oflag = %lx, cflag = %lx\n", p->link.name, p->fd,
39627be3ac6SBrian Somers              (u_long)ios.c_iflag, (u_long)ios.c_oflag, (u_long)ios.c_cflag);
39727be3ac6SBrian Somers 
39827be3ac6SBrian Somers   cfmakeraw(&ios);
39927be3ac6SBrian Somers   if (p->cfg.rts_cts)
40027be3ac6SBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
40127be3ac6SBrian Somers   else {
40227be3ac6SBrian Somers     ios.c_cflag |= CLOCAL;
40327be3ac6SBrian Somers     ios.c_iflag |= IXOFF;
40427be3ac6SBrian Somers   }
40527be3ac6SBrian Somers   ios.c_iflag |= IXON;
40627be3ac6SBrian Somers   if (p->type != PHYS_DEDICATED)
40727be3ac6SBrian Somers     ios.c_cflag |= HUPCL;
40827be3ac6SBrian Somers 
40927be3ac6SBrian Somers   if (p->type != PHYS_DIRECT) {
41027be3ac6SBrian Somers       /* Change tty speed when we're not in -direct mode */
41127be3ac6SBrian Somers       ios.c_cflag &= ~(CSIZE | PARODD | PARENB);
41227be3ac6SBrian Somers       ios.c_cflag |= p->cfg.parity;
41327be3ac6SBrian Somers       if (cfsetspeed(&ios, IntToSpeed(p->cfg.speed)) == -1)
41427be3ac6SBrian Somers 	log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n",
41527be3ac6SBrian Somers 		  p->link.name, p->name.full, p->cfg.speed);
41627be3ac6SBrian Somers   }
41727be3ac6SBrian Somers   tcsetattr(p->fd, TCSADRAIN, &ios);
41827be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: physical (put): iflag = %lx, oflag = %lx, "
41927be3ac6SBrian Somers             "cflag = %lx\n", p->link.name, (u_long)ios.c_iflag,
42027be3ac6SBrian Somers             (u_long)ios.c_oflag, (u_long)ios.c_cflag);
42127be3ac6SBrian Somers 
42227be3ac6SBrian Somers   if (ioctl(p->fd, TIOCMGET, &dev->mbits) == -1) {
42327be3ac6SBrian Somers     if (p->type != PHYS_DIRECT) {
42427be3ac6SBrian Somers       log_Printf(LogWARN, "%s: Open: Cannot get physical status: %s\n",
42527be3ac6SBrian Somers                  p->link.name, strerror(errno));
42627be3ac6SBrian Somers       physical_Close(p);
42727be3ac6SBrian Somers       return NULL;
42827be3ac6SBrian Somers     } else
42927be3ac6SBrian Somers       dev->mbits = TIOCM_CD;
43027be3ac6SBrian Somers   }
43127be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: Open: physical control = %o\n",
43227be3ac6SBrian Somers              p->link.name, dev->mbits);
43327be3ac6SBrian Somers 
43427be3ac6SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
43527be3ac6SBrian Somers   if (oldflag < 0) {
43627be3ac6SBrian Somers     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
43727be3ac6SBrian Somers                p->link.name, strerror(errno));
43827be3ac6SBrian Somers     physical_Close(p);
43927be3ac6SBrian Somers     return NULL;
44027be3ac6SBrian Somers   } else
44127be3ac6SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
44227be3ac6SBrian Somers 
44327be3ac6SBrian Somers   physical_SetupStack(p, PHYSICAL_NOFORCE);
44427be3ac6SBrian Somers 
44527be3ac6SBrian Somers   return &dev->dev;
44627be3ac6SBrian Somers }
44727be3ac6SBrian Somers 
4486815097bSBrian Somers struct device *
4496815097bSBrian Somers tty_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
4506815097bSBrian Somers                int maxiov)
4516815097bSBrian Somers {
4526815097bSBrian Somers   if (type == TTY_DEVICE) {
4536815097bSBrian Somers     struct ttydevice *dev;
4546815097bSBrian Somers 
4556815097bSBrian Somers     /* It's one of ours !  Let's create the device */
4566815097bSBrian Somers 
4576815097bSBrian Somers     dev = (struct ttydevice *)iov[(*niov)++].iov_base;
4586815097bSBrian Somers     /* Refresh function pointers etc */
4596815097bSBrian Somers     memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
4606815097bSBrian Somers 
4616815097bSBrian Somers     physical_SetupStack(p, PHYSICAL_NOFORCE);
4626815097bSBrian Somers     if (dev->Timer.state != TIMER_STOPPED) {
4636815097bSBrian Somers       dev->Timer.state = TIMER_STOPPED;
4646815097bSBrian Somers       tty_StartTimer(p);
4656815097bSBrian Somers     }
4666815097bSBrian Somers     return &dev->dev;
4676815097bSBrian Somers   }
4686815097bSBrian Somers 
4696815097bSBrian Somers   return NULL;
4706815097bSBrian Somers }
4716815097bSBrian Somers 
4726815097bSBrian Somers struct device *
4736815097bSBrian Somers tty_Create(struct physical *p)
4746815097bSBrian Somers {
4756815097bSBrian Somers   if (p->fd >= 0 && isatty(p->fd)) {
4766815097bSBrian Somers     if (*p->name.full == '\0') {
4776815097bSBrian Somers       log_Printf(LogDEBUG, "%s: Input is a tty\n", p->link.name);
4786815097bSBrian Somers       physical_SetDevice(p, ttyname(p->fd));
4796815097bSBrian Somers       if (tty_Lock(p, p->dl->bundle->unit) == -1) {
4806815097bSBrian Somers         close(p->fd);
4816815097bSBrian Somers         p->fd = -1;
4828dbb1e2bSBrian Somers       } else
4838dbb1e2bSBrian Somers         return tty_SetupDevice(p);
4846815097bSBrian Somers     } else if (tty_Lock(p, p->dl->bundle->unit) != -1) {
4856815097bSBrian Somers       log_Printf(LogDEBUG, "%s: Opened %s\n", p->link.name, p->name.full);
4868dbb1e2bSBrian Somers       return tty_SetupDevice(p);
4876815097bSBrian Somers     }
4886815097bSBrian Somers   }
4896815097bSBrian Somers 
4906815097bSBrian Somers   return NULL;
4916815097bSBrian Somers }
492