xref: /freebsd/usr.sbin/ppp/tty.c (revision f5a99677)
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  *
26f5a99677SBrian Somers  *	$Id: tty.c,v 1.8 1999/05/27 08:42:49 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>
50f5a99677SBrian Somers #include <sysexits.h>
515d9e6103SBrian Somers #include <sys/wait.h>
526815097bSBrian Somers #include <sys/uio.h>
535d9e6103SBrian Somers #include <termios.h>
545d9e6103SBrian Somers #include <unistd.h>
555d9e6103SBrian Somers 
565d9e6103SBrian Somers #include "layer.h"
575d9e6103SBrian Somers #include "defs.h"
585d9e6103SBrian Somers #include "mbuf.h"
595d9e6103SBrian Somers #include "log.h"
605d9e6103SBrian Somers #include "id.h"
615d9e6103SBrian Somers #include "sync.h"
625d9e6103SBrian Somers #include "timer.h"
635d9e6103SBrian Somers #include "lqr.h"
645d9e6103SBrian Somers #include "hdlc.h"
655d9e6103SBrian Somers #include "throughput.h"
665d9e6103SBrian Somers #include "fsm.h"
675d9e6103SBrian Somers #include "lcp.h"
685d9e6103SBrian Somers #include "ccp.h"
695d9e6103SBrian Somers #include "link.h"
705d9e6103SBrian Somers #include "async.h"
715d9e6103SBrian Somers #include "slcompress.h"
725d9e6103SBrian Somers #include "iplist.h"
735d9e6103SBrian Somers #include "ipcp.h"
745d9e6103SBrian Somers #include "filter.h"
755d9e6103SBrian Somers #include "descriptor.h"
765d9e6103SBrian Somers #include "physical.h"
775d9e6103SBrian Somers #include "mp.h"
785d9e6103SBrian Somers #ifndef NORADIUS
795d9e6103SBrian Somers #include "radius.h"
805d9e6103SBrian Somers #endif
815d9e6103SBrian Somers #include "chat.h"
825d9e6103SBrian Somers #include "command.h"
835d9e6103SBrian Somers #include "bundle.h"
845d9e6103SBrian Somers #include "prompt.h"
855d9e6103SBrian Somers #include "auth.h"
865d9e6103SBrian Somers #include "chap.h"
875d9e6103SBrian Somers #include "cbcp.h"
885d9e6103SBrian Somers #include "datalink.h"
89f5a99677SBrian Somers #include "main.h"
905d9e6103SBrian Somers #include "tty.h"
915d9e6103SBrian Somers 
926815097bSBrian Somers #define	Online(dev)	((dev)->mbits & TIOCM_CD)
936815097bSBrian Somers 
946815097bSBrian Somers struct ttydevice {
956815097bSBrian Somers   struct device dev;		/* What struct physical knows about */
966815097bSBrian Somers   struct pppTimer Timer;	/* CD checks */
976815097bSBrian Somers   int mbits;			/* Current DCD status */
986815097bSBrian Somers   struct termios ios;		/* To be able to reset from raw mode */
996815097bSBrian Somers };
1006815097bSBrian Somers 
1016815097bSBrian Somers #define device2tty(d) ((d)->type == TTY_DEVICE ? (struct ttydevice *)d : NULL)
1025d9e6103SBrian Somers 
103f5a99677SBrian Somers int
104f5a99677SBrian Somers tty_DeviceSize(void)
105f5a99677SBrian Somers {
106f5a99677SBrian Somers   return sizeof(struct ttydevice);
107f5a99677SBrian Somers }
108f5a99677SBrian Somers 
1095d9e6103SBrian Somers /*
1105d9e6103SBrian Somers  * tty_Timeout() watches the DCD signal and mentions it if it's status
1115d9e6103SBrian Somers  * changes.
1125d9e6103SBrian Somers  */
1135d9e6103SBrian Somers static void
1145d9e6103SBrian Somers tty_Timeout(void *data)
1155d9e6103SBrian Somers {
1165d9e6103SBrian Somers   struct physical *p = data;
1176815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1185d9e6103SBrian Somers   int ombits, change;
1195d9e6103SBrian Somers 
1206815097bSBrian Somers   timer_Stop(&dev->Timer);
1216815097bSBrian Somers   dev->Timer.load = SECTICKS;		/* Once a second please */
1226815097bSBrian Somers   timer_Start(&dev->Timer);
1236815097bSBrian Somers   ombits = dev->mbits;
1245d9e6103SBrian Somers 
1255d9e6103SBrian Somers   if (p->fd >= 0) {
1266815097bSBrian Somers     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
1275d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: ioctl error (%s)!\n", p->link.name,
1285d9e6103SBrian Somers                  strerror(errno));
1295d9e6103SBrian Somers       datalink_Down(p->dl, CLOSE_NORMAL);
1306815097bSBrian Somers       timer_Stop(&dev->Timer);
1315d9e6103SBrian Somers       return;
1325d9e6103SBrian Somers     }
1335d9e6103SBrian Somers   } else
1346815097bSBrian Somers     dev->mbits = 0;
1355d9e6103SBrian Somers 
1365d9e6103SBrian Somers   if (ombits == -1) {
1375d9e6103SBrian Somers     /* First time looking for carrier */
1386815097bSBrian Somers     if (Online(dev))
1395d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: %s: CD detected\n", p->link.name, p->name.full);
1405d9e6103SBrian Somers     else if (p->cfg.cd.required) {
1415d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s: Required CD not detected\n",
1425d9e6103SBrian Somers                  p->link.name, p->name.full);
1435d9e6103SBrian Somers       datalink_Down(p->dl, CLOSE_NORMAL);
1445d9e6103SBrian Somers     } else {
1455d9e6103SBrian Somers       log_Printf(LogPHASE, "%s: %s doesn't support CD\n",
1465d9e6103SBrian Somers                  p->link.name, p->name.full);
1476815097bSBrian Somers       timer_Stop(&dev->Timer);
1486815097bSBrian Somers       dev->mbits = TIOCM_CD;
1495d9e6103SBrian Somers     }
1505d9e6103SBrian Somers   } else {
1516815097bSBrian Somers     change = ombits ^ dev->mbits;
1525d9e6103SBrian Somers     if (change & TIOCM_CD) {
1536815097bSBrian Somers       if (dev->mbits & TIOCM_CD)
1545d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
1555d9e6103SBrian Somers       else {
1565d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
1575d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
1585d9e6103SBrian Somers         datalink_Down(p->dl, CLOSE_NORMAL);
1596815097bSBrian Somers         timer_Stop(&dev->Timer);
1605d9e6103SBrian Somers       }
1615d9e6103SBrian Somers     } else
1625d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
1636815097bSBrian Somers                  Online(dev) ? "on" : "off");
1645d9e6103SBrian Somers   }
1655d9e6103SBrian Somers }
1665d9e6103SBrian Somers 
1675d9e6103SBrian Somers static void
1685d9e6103SBrian Somers tty_StartTimer(struct physical *p)
1695d9e6103SBrian Somers {
1706815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1716815097bSBrian Somers 
1726815097bSBrian Somers   timer_Stop(&dev->Timer);
1736815097bSBrian Somers   dev->Timer.load = SECTICKS * p->cfg.cd.delay;
1746815097bSBrian Somers   dev->Timer.func = tty_Timeout;
1756815097bSBrian Somers   dev->Timer.name = "tty CD";
1766815097bSBrian Somers   dev->Timer.arg = p;
1775d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Using tty_Timeout [%p]\n",
1785d9e6103SBrian Somers              p->link.name, tty_Timeout);
1796815097bSBrian Somers   dev->mbits = -1;		/* So we know it's the first time */
1806815097bSBrian Somers   timer_Start(&dev->Timer);
1815d9e6103SBrian Somers }
1825d9e6103SBrian Somers 
1835d9e6103SBrian Somers static int
1845d9e6103SBrian Somers tty_Raw(struct physical *p)
1855d9e6103SBrian Somers {
1866815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1878dbb1e2bSBrian Somers   struct termios ios;
1885d9e6103SBrian Somers   int oldflag;
1895d9e6103SBrian Somers 
1905d9e6103SBrian Somers   if (physical_IsSync(p))
1915d9e6103SBrian Somers     return 1;
1925d9e6103SBrian Somers 
1935d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Entering physical_Raw\n", p->link.name);
1945d9e6103SBrian Somers 
1956815097bSBrian Somers   if (p->type != PHYS_DIRECT && p->fd >= 0 && !Online(dev))
1965d9e6103SBrian Somers     log_Printf(LogDEBUG, "%s: Raw: descriptor = %d, mbits = %x\n",
1976815097bSBrian Somers               p->link.name, p->fd, dev->mbits);
1985d9e6103SBrian Somers 
1998dbb1e2bSBrian Somers   tcgetattr(p->fd, &ios);
2008dbb1e2bSBrian Somers   cfmakeraw(&ios);
2015d9e6103SBrian Somers   if (p->cfg.rts_cts)
2028dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
2035d9e6103SBrian Somers   else
2048dbb1e2bSBrian Somers     ios.c_cflag |= CLOCAL;
2055d9e6103SBrian Somers 
2065d9e6103SBrian Somers   if (p->type != PHYS_DEDICATED)
2078dbb1e2bSBrian Somers     ios.c_cflag |= HUPCL;
2085d9e6103SBrian Somers 
2098dbb1e2bSBrian Somers   tcsetattr(p->fd, TCSANOW, &ios);
2105d9e6103SBrian Somers 
2115d9e6103SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
2125d9e6103SBrian Somers   if (oldflag < 0)
2135d9e6103SBrian Somers     return 0;
2145d9e6103SBrian Somers   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
2155d9e6103SBrian Somers 
2166815097bSBrian Somers   if (ioctl(p->fd, TIOCMGET, &dev->mbits) == 0)
2175d9e6103SBrian Somers     tty_StartTimer(p);
2185d9e6103SBrian Somers 
2195d9e6103SBrian Somers   return 1;
2205d9e6103SBrian Somers }
2215d9e6103SBrian Somers 
2225d9e6103SBrian Somers static void
2235d9e6103SBrian Somers tty_Offline(struct physical *p)
2245d9e6103SBrian Somers {
2256815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2266815097bSBrian Somers 
2275d9e6103SBrian Somers   if (p->fd >= 0) {
2286815097bSBrian Somers     timer_Stop(&dev->Timer);
2296815097bSBrian Somers     dev->mbits &= ~TIOCM_DTR;
2306815097bSBrian Somers     if (Online(dev)) {
2315d9e6103SBrian Somers       struct termios tio;
2325d9e6103SBrian Somers 
2335d9e6103SBrian Somers       tcgetattr(p->fd, &tio);
2345d9e6103SBrian Somers       if (cfsetspeed(&tio, B0) == -1)
2355d9e6103SBrian Somers         log_Printf(LogWARN, "%s: Unable to set physical to speed 0\n",
2365d9e6103SBrian Somers                    p->link.name);
2375d9e6103SBrian Somers       else
2385d9e6103SBrian Somers         tcsetattr(p->fd, TCSANOW, &tio);
2395d9e6103SBrian Somers     }
2405d9e6103SBrian Somers   }
2415d9e6103SBrian Somers }
2425d9e6103SBrian Somers 
2435d9e6103SBrian Somers static void
2445d9e6103SBrian Somers tty_Cooked(struct physical *p)
2455d9e6103SBrian Somers {
2466815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2475d9e6103SBrian Somers   int oldflag;
2485d9e6103SBrian Somers 
249d0b3b745SBrian Somers   tty_Offline(p);	/* In case of emergency close()s */
250d0b3b745SBrian Somers 
2515d9e6103SBrian Somers   tcflush(p->fd, TCIOFLUSH);
2525d9e6103SBrian Somers   if (!physical_IsSync(p)) {
2536815097bSBrian Somers     tcsetattr(p->fd, TCSAFLUSH, &dev->ios);
2545d9e6103SBrian Somers     oldflag = fcntl(p->fd, F_GETFL, 0);
2555d9e6103SBrian Somers     if (oldflag == 0)
2565d9e6103SBrian Somers       fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
2575d9e6103SBrian Somers   }
2585d9e6103SBrian Somers }
2595d9e6103SBrian Somers 
2605d9e6103SBrian Somers static void
2616815097bSBrian Somers tty_StopTimer(struct physical *p)
2625d9e6103SBrian Somers {
2636815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2646815097bSBrian Somers 
2656815097bSBrian Somers   timer_Stop(&dev->Timer);
2665d9e6103SBrian Somers }
2675d9e6103SBrian Somers 
2685d9e6103SBrian Somers static void
2696815097bSBrian Somers tty_Free(struct physical *p)
2705d9e6103SBrian Somers {
2716815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2726815097bSBrian Somers 
273d0b3b745SBrian Somers   tty_Offline(p);	/* In case of emergency close()s */
2746815097bSBrian Somers   free(dev);
2755d9e6103SBrian Somers }
2765d9e6103SBrian Somers 
2775d9e6103SBrian Somers static int
2785d9e6103SBrian Somers tty_Speed(struct physical *p)
2795d9e6103SBrian Somers {
2808dbb1e2bSBrian Somers   struct termios ios;
2815d9e6103SBrian Somers 
2828dbb1e2bSBrian Somers   if (tcgetattr(p->fd, &ios) == -1)
2835d9e6103SBrian Somers     return 0;
2845d9e6103SBrian Somers 
2858dbb1e2bSBrian Somers   return SpeedToInt(cfgetispeed(&ios));
2865d9e6103SBrian Somers }
2875d9e6103SBrian Somers 
2885d9e6103SBrian Somers static const char *
2895d9e6103SBrian Somers tty_OpenInfo(struct physical *p)
2905d9e6103SBrian Somers {
2916815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
2925d9e6103SBrian Somers   static char buf[13];
2935d9e6103SBrian Somers 
2946815097bSBrian Somers   if (Online(dev))
2955d9e6103SBrian Somers     strcpy(buf, "with");
2965d9e6103SBrian Somers   else
2975d9e6103SBrian Somers     strcpy(buf, "no");
2985d9e6103SBrian Somers   strcat(buf, " carrier");
2995d9e6103SBrian Somers   return buf;
3005d9e6103SBrian Somers }
3015d9e6103SBrian Somers 
3026815097bSBrian Somers static void
303f5a99677SBrian Somers tty_device2iov(struct device *d, struct iovec *iov, int *niov,
3046815097bSBrian Somers                int maxiov, pid_t newpid)
3056815097bSBrian Somers {
306f5a99677SBrian Somers   struct ttydevice *dev = device2tty(d);
307f5a99677SBrian Somers   int sz = physical_MaxDeviceSize();
3086815097bSBrian Somers 
309f5a99677SBrian Somers   iov[*niov].iov_base = realloc(d, sz);
310f5a99677SBrian Somers   if (iov[*niov].iov_base == NULL) {
311f5a99677SBrian Somers     log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
312f5a99677SBrian Somers     AbortProgram(EX_OSERR);
313f5a99677SBrian Somers   }
314f5a99677SBrian Somers   iov[*niov].iov_len = sz;
3156815097bSBrian Somers   (*niov)++;
3166815097bSBrian Somers 
3176815097bSBrian Somers   if (dev->Timer.state != TIMER_STOPPED) {
3186815097bSBrian Somers     timer_Stop(&dev->Timer);
3196815097bSBrian Somers     dev->Timer.state = TIMER_RUNNING;
3206815097bSBrian Somers   }
3216815097bSBrian Somers }
3226815097bSBrian Somers 
3236815097bSBrian Somers static struct device basettydevice = {
3245d9e6103SBrian Somers   TTY_DEVICE,
3255d9e6103SBrian Somers   "tty",
3265d9e6103SBrian Somers   tty_Raw,
3275d9e6103SBrian Somers   tty_Offline,
3285d9e6103SBrian Somers   tty_Cooked,
3296815097bSBrian Somers   tty_StopTimer,
3306815097bSBrian Somers   tty_Free,
3316815097bSBrian Somers   NULL,
3326815097bSBrian Somers   NULL,
3336815097bSBrian Somers   tty_device2iov,
3345d9e6103SBrian Somers   tty_Speed,
3355d9e6103SBrian Somers   tty_OpenInfo
3365d9e6103SBrian Somers };
3376815097bSBrian Somers 
3389950fb2aSBrian Somers struct device *
3399950fb2aSBrian Somers tty_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
3409950fb2aSBrian Somers                int maxiov)
3419950fb2aSBrian Somers {
3429950fb2aSBrian Somers   if (type == TTY_DEVICE) {
343acbd1f00SBrian Somers     struct ttydevice *dev = (struct ttydevice *)iov[(*niov)++].iov_base;
3449950fb2aSBrian Somers 
345f5a99677SBrian Somers     dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
346f5a99677SBrian Somers     if (dev == NULL) {
347f5a99677SBrian Somers       log_Printf(LogALERT, "Failed to allocate memory: %d\n",
348f5a99677SBrian Somers                  (int)(sizeof *dev));
349f5a99677SBrian Somers       AbortProgram(EX_OSERR);
350f5a99677SBrian Somers     }
351f5a99677SBrian Somers 
3529950fb2aSBrian Somers     /* Refresh function pointers etc */
3539950fb2aSBrian Somers     memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
3549950fb2aSBrian Somers 
355acbd1f00SBrian Somers     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
3569950fb2aSBrian Somers     if (dev->Timer.state != TIMER_STOPPED) {
3579950fb2aSBrian Somers       dev->Timer.state = TIMER_STOPPED;
358f5a99677SBrian Somers       p->handler = &dev->dev;		/* For the benefit of StartTimer */
3599950fb2aSBrian Somers       tty_StartTimer(p);
3609950fb2aSBrian Somers     }
3619950fb2aSBrian Somers     return &dev->dev;
3629950fb2aSBrian Somers   }
3639950fb2aSBrian Somers 
3649950fb2aSBrian Somers   return NULL;
3659950fb2aSBrian Somers }
3669950fb2aSBrian Somers 
3679950fb2aSBrian Somers struct device *
3689950fb2aSBrian Somers tty_Create(struct physical *p)
36927be3ac6SBrian Somers {
37027be3ac6SBrian Somers   struct ttydevice *dev;
37127be3ac6SBrian Somers   struct termios ios;
37227be3ac6SBrian Somers   int oldflag;
37327be3ac6SBrian Somers 
3749950fb2aSBrian Somers   if (p->fd < 0 || !isatty(p->fd))
3759950fb2aSBrian Somers     /* Don't want this */
37627be3ac6SBrian Somers     return NULL;
37727be3ac6SBrian Somers 
3789950fb2aSBrian Somers   if (*p->name.full == '\0') {
3799950fb2aSBrian Somers     physical_SetDevice(p, ttyname(p->fd));
3809950fb2aSBrian Somers     log_Printf(LogDEBUG, "%s: Input is a tty (%s)\n",
3819950fb2aSBrian Somers                p->link.name, p->name.full);
3829950fb2aSBrian Somers   } else
3839950fb2aSBrian Somers     log_Printf(LogDEBUG, "%s: Opened %s\n", p->link.name, p->name.full);
3849950fb2aSBrian Somers 
3859950fb2aSBrian Somers   /* We're gonna return a ttydevice (unless something goes horribly wrong) */
3869950fb2aSBrian Somers 
3879950fb2aSBrian Somers   if ((dev = malloc(sizeof *dev)) == NULL) {
3889950fb2aSBrian Somers     /* Complete failure - parent doesn't continue trying to ``create'' */
3899950fb2aSBrian Somers     close(p->fd);
3909950fb2aSBrian Somers     p->fd = -1;
3919950fb2aSBrian Somers     return NULL;
3929950fb2aSBrian Somers   }
3939950fb2aSBrian Somers 
39427be3ac6SBrian Somers   memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
3954b698945SBrian Somers   memset(&dev->Timer, '\0', sizeof dev->Timer);
39627be3ac6SBrian Somers   tcgetattr(p->fd, &ios);
39727be3ac6SBrian Somers   dev->ios = ios;
39827be3ac6SBrian Somers 
3999950fb2aSBrian Somers   log_Printf(LogDEBUG, "%s: tty_Create: physical (get): fd = %d,"
40027be3ac6SBrian Somers              " iflag = %lx, oflag = %lx, cflag = %lx\n", p->link.name, p->fd,
40127be3ac6SBrian Somers              (u_long)ios.c_iflag, (u_long)ios.c_oflag, (u_long)ios.c_cflag);
40227be3ac6SBrian Somers 
40327be3ac6SBrian Somers   cfmakeraw(&ios);
40427be3ac6SBrian Somers   if (p->cfg.rts_cts)
40527be3ac6SBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
40627be3ac6SBrian Somers   else {
40727be3ac6SBrian Somers     ios.c_cflag |= CLOCAL;
40827be3ac6SBrian Somers     ios.c_iflag |= IXOFF;
40927be3ac6SBrian Somers   }
41027be3ac6SBrian Somers   ios.c_iflag |= IXON;
41127be3ac6SBrian Somers   if (p->type != PHYS_DEDICATED)
41227be3ac6SBrian Somers     ios.c_cflag |= HUPCL;
41327be3ac6SBrian Somers 
41427be3ac6SBrian Somers   if (p->type != PHYS_DIRECT) {
41527be3ac6SBrian Somers       /* Change tty speed when we're not in -direct mode */
41627be3ac6SBrian Somers       ios.c_cflag &= ~(CSIZE | PARODD | PARENB);
41727be3ac6SBrian Somers       ios.c_cflag |= p->cfg.parity;
41827be3ac6SBrian Somers       if (cfsetspeed(&ios, IntToSpeed(p->cfg.speed)) == -1)
41927be3ac6SBrian Somers 	log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n",
42027be3ac6SBrian Somers 		  p->link.name, p->name.full, p->cfg.speed);
42127be3ac6SBrian Somers   }
42227be3ac6SBrian Somers   tcsetattr(p->fd, TCSADRAIN, &ios);
42327be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: physical (put): iflag = %lx, oflag = %lx, "
42427be3ac6SBrian Somers             "cflag = %lx\n", p->link.name, (u_long)ios.c_iflag,
42527be3ac6SBrian Somers             (u_long)ios.c_oflag, (u_long)ios.c_cflag);
42627be3ac6SBrian Somers 
42727be3ac6SBrian Somers   if (ioctl(p->fd, TIOCMGET, &dev->mbits) == -1) {
42827be3ac6SBrian Somers     if (p->type != PHYS_DIRECT) {
4299950fb2aSBrian Somers       /* Complete failure - parent doesn't continue trying to ``create'' */
4309950fb2aSBrian Somers 
43127be3ac6SBrian Somers       log_Printf(LogWARN, "%s: Open: Cannot get physical status: %s\n",
43227be3ac6SBrian Somers                  p->link.name, strerror(errno));
4339950fb2aSBrian Somers       tty_Cooked(p);
4349950fb2aSBrian Somers       close(p->fd);
4359950fb2aSBrian Somers       p->fd = -1;
43627be3ac6SBrian Somers       return NULL;
43727be3ac6SBrian Somers     } else
43827be3ac6SBrian Somers       dev->mbits = TIOCM_CD;
43927be3ac6SBrian Somers   }
44027be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: Open: physical control = %o\n",
44127be3ac6SBrian Somers              p->link.name, dev->mbits);
44227be3ac6SBrian Somers 
44327be3ac6SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
44427be3ac6SBrian Somers   if (oldflag < 0) {
4459950fb2aSBrian Somers     /* Complete failure - parent doesn't continue trying to ``create'' */
4469950fb2aSBrian Somers 
44727be3ac6SBrian Somers     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
44827be3ac6SBrian Somers                p->link.name, strerror(errno));
4499950fb2aSBrian Somers     tty_Cooked(p);
4509950fb2aSBrian Somers     close(p->fd);
4519950fb2aSBrian Somers     p->fd = -1;
45227be3ac6SBrian Somers     return NULL;
45327be3ac6SBrian Somers   } else
45427be3ac6SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
45527be3ac6SBrian Somers 
456acbd1f00SBrian Somers   physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
45727be3ac6SBrian Somers 
45827be3ac6SBrian Somers   return &dev->dev;
45927be3ac6SBrian Somers }
460