xref: /freebsd/usr.sbin/ppp/tty.c (revision b3e76948)
15d9e6103SBrian Somers /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
45d9e6103SBrian Somers  * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
55d9e6103SBrian Somers  * All rights reserved.
65d9e6103SBrian Somers  *
75d9e6103SBrian Somers  * Redistribution and use in source and binary forms, with or without
85d9e6103SBrian Somers  * modification, are permitted provided that the following conditions
95d9e6103SBrian Somers  * are met:
105d9e6103SBrian Somers  * 1. Redistributions of source code must retain the above copyright
115d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer.
125d9e6103SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
135d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
145d9e6103SBrian Somers  *    documentation and/or other materials provided with the distribution.
155d9e6103SBrian Somers  *
165d9e6103SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
175d9e6103SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185d9e6103SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
195d9e6103SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
205d9e6103SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215d9e6103SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
225d9e6103SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
235d9e6103SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
245d9e6103SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255d9e6103SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265d9e6103SBrian Somers  * SUCH DAMAGE.
275d9e6103SBrian Somers  */
285d9e6103SBrian Somers 
295d9e6103SBrian Somers #include <sys/param.h>
305d9e6103SBrian Somers #include <sys/un.h>
315d9e6103SBrian Somers #if defined(__OpenBSD__) || defined(__NetBSD__)
325d9e6103SBrian Somers #include <sys/ioctl.h>
335d9e6103SBrian Somers #endif
345d9e6103SBrian Somers 
355d9e6103SBrian Somers #include <errno.h>
365d9e6103SBrian Somers #include <fcntl.h>
37fb11a9c2SBrian Somers #include <stdio.h>
385d9e6103SBrian Somers #include <stdlib.h>
395d9e6103SBrian Somers #include <string.h>
40f5a99677SBrian Somers #include <sysexits.h>
416815097bSBrian Somers #include <sys/uio.h>
425d9e6103SBrian Somers #include <termios.h>
43de59e178SBrian Somers #include <ttyent.h>
445d9e6103SBrian Somers #include <unistd.h>
4597486b09SBrian Somers #ifndef NONETGRAPH
46fb11a9c2SBrian Somers #include <netgraph.h>
47fb11a9c2SBrian Somers #include <netgraph/ng_async.h>
48fb11a9c2SBrian Somers #include <netgraph/ng_message.h>
49fb11a9c2SBrian Somers #include <netgraph/ng_ppp.h>
50fb11a9c2SBrian Somers #include <netgraph/ng_tty.h>
5197486b09SBrian Somers #endif
525d9e6103SBrian Somers 
535d9e6103SBrian Somers #include "layer.h"
545d9e6103SBrian Somers #include "defs.h"
555d9e6103SBrian Somers #include "mbuf.h"
565d9e6103SBrian Somers #include "log.h"
575d9e6103SBrian Somers #include "timer.h"
585d9e6103SBrian Somers #include "lqr.h"
595d9e6103SBrian Somers #include "hdlc.h"
605d9e6103SBrian Somers #include "throughput.h"
615d9e6103SBrian Somers #include "fsm.h"
625d9e6103SBrian Somers #include "lcp.h"
635d9e6103SBrian Somers #include "ccp.h"
645d9e6103SBrian Somers #include "link.h"
655d9e6103SBrian Somers #include "async.h"
665d9e6103SBrian Somers #include "descriptor.h"
675d9e6103SBrian Somers #include "physical.h"
685d9e6103SBrian Somers #include "mp.h"
695d9e6103SBrian Somers #include "chat.h"
705d9e6103SBrian Somers #include "auth.h"
715d9e6103SBrian Somers #include "chap.h"
725d9e6103SBrian Somers #include "cbcp.h"
735d9e6103SBrian Somers #include "datalink.h"
74f5a99677SBrian Somers #include "main.h"
75fb11a9c2SBrian Somers #include "id.h"
765d9e6103SBrian Somers #include "tty.h"
775d9e6103SBrian Somers 
781d3a2f02SBrian Somers #if defined(__mac68k__) || defined(__macppc__)
791d3a2f02SBrian Somers #undef	CRTS_IFLOW
801d3a2f02SBrian Somers #undef	CCTS_OFLOW
811d3a2f02SBrian Somers #define	CRTS_IFLOW	CDTRCTS
821d3a2f02SBrian Somers #define	CCTS_OFLOW	CDTRCTS
831d3a2f02SBrian Somers #endif
841d3a2f02SBrian Somers 
856815097bSBrian Somers #define	Online(dev)	((dev)->mbits & TIOCM_CD)
866815097bSBrian Somers 
876815097bSBrian Somers struct ttydevice {
886815097bSBrian Somers   struct device dev;		/* What struct physical knows about */
896815097bSBrian Somers   struct pppTimer Timer;	/* CD checks */
906815097bSBrian Somers   int mbits;			/* Current DCD status */
91eb6e5e05SBrian Somers   int carrier_seconds;		/* seconds before CD is *required* */
92fb11a9c2SBrian Somers #ifndef NONETGRAPH
93fb11a9c2SBrian Somers   struct {
94057f1760SBrian Somers     unsigned speed;		/* Pre-line-discipline speed */
95fb11a9c2SBrian Somers     int fd;			/* Pre-line-discipline fd */
96fb11a9c2SBrian Somers     int disc;			/* Old line-discipline */
97fb11a9c2SBrian Somers   } real;
98fb11a9c2SBrian Somers   char hook[sizeof NG_ASYNC_HOOK_SYNC]; /* our ng_socket hook */
99fb11a9c2SBrian Somers   int cs;			/* A netgraph control socket (maybe) */
100fb11a9c2SBrian Somers #endif
1016815097bSBrian Somers   struct termios ios;		/* To be able to reset from raw mode */
1026815097bSBrian Somers };
1036815097bSBrian Somers 
1046815097bSBrian Somers #define device2tty(d) ((d)->type == TTY_DEVICE ? (struct ttydevice *)d : NULL)
1055d9e6103SBrian Somers 
106057f1760SBrian Somers unsigned
tty_DeviceSize(void)107f5a99677SBrian Somers tty_DeviceSize(void)
108f5a99677SBrian Somers {
109f5a99677SBrian Somers   return sizeof(struct ttydevice);
110f5a99677SBrian Somers }
111f5a99677SBrian Somers 
1125d9e6103SBrian Somers /*
1135d9e6103SBrian Somers  * tty_Timeout() watches the DCD signal and mentions it if it's status
1145d9e6103SBrian Somers  * changes.
1155d9e6103SBrian Somers  */
1165d9e6103SBrian Somers static void
tty_Timeout(void * data)1175d9e6103SBrian Somers tty_Timeout(void *data)
1185d9e6103SBrian Somers {
1195d9e6103SBrian Somers   struct physical *p = data;
1206815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1215d9e6103SBrian Somers   int ombits, change;
1225d9e6103SBrian Somers 
1236815097bSBrian Somers   timer_Stop(&dev->Timer);
1246815097bSBrian Somers   dev->Timer.load = SECTICKS;		/* Once a second please */
1256815097bSBrian Somers   timer_Start(&dev->Timer);
1266815097bSBrian Somers   ombits = dev->mbits;
1275d9e6103SBrian Somers 
1285d9e6103SBrian Somers   if (p->fd >= 0) {
1296815097bSBrian Somers     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
130eb6e5e05SBrian Somers       /* we must be a pty ? */
131fdc29d54SBrian Somers       if (p->cfg.cd.necessity != CD_DEFAULT)
132fdc29d54SBrian Somers         log_Printf(LogWARN, "%s: Carrier ioctl not supported, "
133fdc29d54SBrian Somers                    "using ``set cd off''\n", p->link.name);
1346815097bSBrian Somers       timer_Stop(&dev->Timer);
1359acc8460SBrian Somers       dev->mbits = TIOCM_CD;
1365d9e6103SBrian Somers       return;
1375d9e6103SBrian Somers     }
1385d9e6103SBrian Somers   } else
1396815097bSBrian Somers     dev->mbits = 0;
1405d9e6103SBrian Somers 
1415d9e6103SBrian Somers   if (ombits == -1) {
1425d9e6103SBrian Somers     /* First time looking for carrier */
1436815097bSBrian Somers     if (Online(dev))
144eb6e5e05SBrian Somers       log_Printf(LogPHASE, "%s: %s: CD detected\n", p->link.name, p->name.full);
145fdc29d54SBrian Somers     else if (++dev->carrier_seconds >= dev->dev.cd.delay) {
146fdc29d54SBrian Somers       if (dev->dev.cd.necessity == CD_REQUIRED)
1475d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: %s: Required CD not detected\n",
1485d9e6103SBrian Somers                    p->link.name, p->name.full);
149eb6e5e05SBrian Somers       else {
1505d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: %s doesn't support CD\n",
1515d9e6103SBrian Somers                    p->link.name, p->name.full);
152eb6e5e05SBrian Somers         dev->mbits = TIOCM_CD;		/* Dodgy null-modem cable ? */
153eb6e5e05SBrian Somers       }
1546815097bSBrian Somers       timer_Stop(&dev->Timer);
155eb6e5e05SBrian Somers       /* tty_AwaitCarrier() will notice */
156eb6e5e05SBrian Somers     } else {
157eb6e5e05SBrian Somers       /* Keep waiting */
158eb6e5e05SBrian Somers       log_Printf(LogDEBUG, "%s: %s: Still no carrier (%d/%d)\n",
159eb6e5e05SBrian Somers                  p->link.name, p->name.full, dev->carrier_seconds,
160fdc29d54SBrian Somers                  dev->dev.cd.delay);
161eb6e5e05SBrian Somers       dev->mbits = -1;
1625d9e6103SBrian Somers     }
1635d9e6103SBrian Somers   } else {
1646815097bSBrian Somers     change = ombits ^ dev->mbits;
1655d9e6103SBrian Somers     if (change & TIOCM_CD) {
1666815097bSBrian Somers       if (dev->mbits & TIOCM_CD)
1675d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
1685d9e6103SBrian Somers       else {
1695d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
1705d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
1715d9e6103SBrian Somers         datalink_Down(p->dl, CLOSE_NORMAL);
1726815097bSBrian Somers         timer_Stop(&dev->Timer);
1735d9e6103SBrian Somers       }
1745d9e6103SBrian Somers     } else
1755d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
1766815097bSBrian Somers                  Online(dev) ? "on" : "off");
1775d9e6103SBrian Somers   }
1785d9e6103SBrian Somers }
1795d9e6103SBrian Somers 
1805d9e6103SBrian Somers static void
tty_StartTimer(struct physical * p)1815d9e6103SBrian Somers tty_StartTimer(struct physical *p)
1825d9e6103SBrian Somers {
1836815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1846815097bSBrian Somers 
1856815097bSBrian Somers   timer_Stop(&dev->Timer);
186eb6e5e05SBrian Somers   dev->Timer.load = SECTICKS;
1876815097bSBrian Somers   dev->Timer.func = tty_Timeout;
1886815097bSBrian Somers   dev->Timer.name = "tty CD";
1896815097bSBrian Somers   dev->Timer.arg = p;
1905d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Using tty_Timeout [%p]\n",
1915d9e6103SBrian Somers              p->link.name, tty_Timeout);
1926815097bSBrian Somers   timer_Start(&dev->Timer);
1935d9e6103SBrian Somers }
1945d9e6103SBrian Somers 
1955d9e6103SBrian Somers static int
tty_AwaitCarrier(struct physical * p)196eb6e5e05SBrian Somers tty_AwaitCarrier(struct physical *p)
197eb6e5e05SBrian Somers {
198eb6e5e05SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
199eb6e5e05SBrian Somers 
200fdc29d54SBrian Somers   if (dev->dev.cd.necessity == CD_NOTREQUIRED || physical_IsSync(p))
201eb6e5e05SBrian Somers     return CARRIER_OK;
202eb6e5e05SBrian Somers 
203eb6e5e05SBrian Somers   if (dev->mbits == -1) {
204eb6e5e05SBrian Somers     if (dev->Timer.state == TIMER_STOPPED) {
205eb6e5e05SBrian Somers       dev->carrier_seconds = 0;
206eb6e5e05SBrian Somers       tty_StartTimer(p);
207eb6e5e05SBrian Somers     }
208eb6e5e05SBrian Somers     return CARRIER_PENDING;			/* Not yet ! */
209eb6e5e05SBrian Somers   }
210eb6e5e05SBrian Somers 
2119acc8460SBrian Somers   return Online(dev) ? CARRIER_OK : CARRIER_LOST;
212eb6e5e05SBrian Somers }
213eb6e5e05SBrian Somers 
214fb11a9c2SBrian Somers #ifdef NONETGRAPH
215fb11a9c2SBrian Somers #define tty_SetAsyncParams	NULL
216fb11a9c2SBrian Somers #define tty_Write		NULL
217fb11a9c2SBrian Somers #define tty_Read		NULL
218fb11a9c2SBrian Somers #else
219fb11a9c2SBrian Somers 
220fb11a9c2SBrian Somers static int
isngtty(struct ttydevice * dev)221fb11a9c2SBrian Somers isngtty(struct ttydevice *dev)
222fb11a9c2SBrian Somers {
223fb11a9c2SBrian Somers   return dev->real.fd != -1;
224fb11a9c2SBrian Somers }
225fb11a9c2SBrian Somers 
226fb11a9c2SBrian Somers static void
tty_SetAsyncParams(struct physical * p,u_int32_t mymap,u_int32_t hismap)227fb11a9c2SBrian Somers tty_SetAsyncParams(struct physical *p, u_int32_t mymap, u_int32_t hismap)
228fb11a9c2SBrian Somers {
229fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
23089624a34SHartmut Brandt   char asyncpath[NG_PATHSIZ];
231fb11a9c2SBrian Somers   struct ng_async_cfg cfg;
232fb11a9c2SBrian Somers 
233fb11a9c2SBrian Somers   if (isngtty(dev)) {
234fb11a9c2SBrian Somers     /* Configure the async converter node */
235fb11a9c2SBrian Somers 
236fb11a9c2SBrian Somers     snprintf(asyncpath, sizeof asyncpath, ".:%s", dev->hook);
237fb11a9c2SBrian Somers     memset(&cfg, 0, sizeof cfg);
238fb11a9c2SBrian Somers     cfg.enabled = 1;
239fb11a9c2SBrian Somers     cfg.accm = mymap | hismap;
240fb11a9c2SBrian Somers     cfg.amru = MAX_MTU;
241fb11a9c2SBrian Somers     cfg.smru = MAX_MRU;
242fb11a9c2SBrian Somers     log_Printf(LogDEBUG, "Configure async node at %s\n", asyncpath);
243fb11a9c2SBrian Somers     if (NgSendMsg(dev->cs, asyncpath, NGM_ASYNC_COOKIE,
244fb11a9c2SBrian Somers                   NGM_ASYNC_CMD_SET_CONFIG, &cfg, sizeof cfg) < 0)
245fb11a9c2SBrian Somers       log_Printf(LogWARN, "%s: Can't configure async node at %s\n",
246fb11a9c2SBrian Somers                  p->link.name, asyncpath);
247fb11a9c2SBrian Somers   } else
248fb11a9c2SBrian Somers     /* No netgraph node, just config the async layer */
249fb11a9c2SBrian Somers     async_SetLinkParams(&p->async, mymap, hismap);
250fb11a9c2SBrian Somers }
251fb11a9c2SBrian Somers 
252fb11a9c2SBrian Somers static int
LoadLineDiscipline(struct physical * p)253fb11a9c2SBrian Somers LoadLineDiscipline(struct physical *p)
254fb11a9c2SBrian Somers {
255fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
256fb11a9c2SBrian Somers   u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
257fb11a9c2SBrian Somers   struct ng_mesg *reply;
258fb11a9c2SBrian Somers   struct nodeinfo *info;
25989624a34SHartmut Brandt   char ttypath[NG_NODESIZ];
260fb11a9c2SBrian Somers   struct ngm_mkpeer ngm;
261fb11a9c2SBrian Somers   struct ngm_connect ngc;
262057f1760SBrian Somers   int ldisc, cs, ds, hot;
263057f1760SBrian Somers   unsigned speed;
264fb11a9c2SBrian Somers 
265768dc550SBrian Somers   /*
266768dc550SBrian Somers    * Don't use the netgraph line discipline for now.  Using it works, but
267768dc550SBrian Somers    * carrier cannot be detected via TIOCMGET and the device doesn't become
268768dc550SBrian Somers    * selectable with 0 bytes to read when carrier is lost :(
269768dc550SBrian Somers    */
270768dc550SBrian Somers   return 0;
271768dc550SBrian Somers 
272fb11a9c2SBrian Somers   reply = (struct ng_mesg *)rbuf;
273fb11a9c2SBrian Somers   info = (struct nodeinfo *)reply->data;
274fb11a9c2SBrian Somers 
275fb11a9c2SBrian Somers   loadmodules(LOAD_VERBOSLY, "netgraph", "ng_tty", "ng_async", "ng_socket",
276fb11a9c2SBrian Somers               NULL);
277fb11a9c2SBrian Somers 
278fb11a9c2SBrian Somers   /* Get the speed before loading the line discipline */
279fb11a9c2SBrian Somers   speed = physical_GetSpeed(p);
280fb11a9c2SBrian Somers 
281fb11a9c2SBrian Somers   if (ioctl(p->fd, TIOCGETD, &dev->real.disc) < 0) {
282fb11a9c2SBrian Somers     log_Printf(LogDEBUG, "%s: Couldn't get tty line discipline\n",
283fb11a9c2SBrian Somers                p->link.name);
284fb11a9c2SBrian Somers     return 0;
285fb11a9c2SBrian Somers   }
286fb11a9c2SBrian Somers   ldisc = NETGRAPHDISC;
287fb11a9c2SBrian Somers   if (ID0ioctl(p->fd, TIOCSETD, &ldisc) < 0) {
288fb11a9c2SBrian Somers     log_Printf(LogDEBUG, "%s: Couldn't set NETGRAPHDISC line discipline\n",
289fb11a9c2SBrian Somers                p->link.name);
290fb11a9c2SBrian Somers     return 0;
291fb11a9c2SBrian Somers   }
292fb11a9c2SBrian Somers 
293fb11a9c2SBrian Somers   /* Get the name of the tty node */
294fb11a9c2SBrian Somers   if (ioctl(p->fd, NGIOCGINFO, info) < 0) {
295fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: ioctl(NGIOCGINFO): %s\n", p->link.name,
296fb11a9c2SBrian Somers                strerror(errno));
297fb11a9c2SBrian Somers     ID0ioctl(p->fd, TIOCSETD, &dev->real.disc);
298fb11a9c2SBrian Somers     return 0;
299fb11a9c2SBrian Somers   }
300fb11a9c2SBrian Somers   snprintf(ttypath, sizeof ttypath, "%s:", info->name);
301fb11a9c2SBrian Somers 
302fb11a9c2SBrian Somers   /* Create a socket node for our endpoint (and to send messages via) */
303fb11a9c2SBrian Somers   if (ID0NgMkSockNode(NULL, &cs, &ds) == -1) {
304fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: NgMkSockNode: %s\n", p->link.name,
305fb11a9c2SBrian Somers                strerror(errno));
306fb11a9c2SBrian Somers     ID0ioctl(p->fd, TIOCSETD, &dev->real.disc);
307fb11a9c2SBrian Somers     return 0;
308fb11a9c2SBrian Somers   }
309fb11a9c2SBrian Somers 
310fb11a9c2SBrian Somers   /* Set the ``hot char'' on the TTY node */
311fb11a9c2SBrian Somers   hot = HDLC_SYN;
312fb11a9c2SBrian Somers   log_Printf(LogDEBUG, "%s: Set tty hotchar to 0x%02x\n", p->link.name, hot);
313fb11a9c2SBrian Somers   if (NgSendMsg(cs, ttypath, NGM_TTY_COOKIE,
314fb11a9c2SBrian Somers       NGM_TTY_SET_HOTCHAR, &hot, sizeof hot) < 0) {
315fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't set hot char\n", p->link.name);
316fb11a9c2SBrian Somers     goto failed;
317fb11a9c2SBrian Somers   }
318fb11a9c2SBrian Somers 
319fb11a9c2SBrian Somers   /* Attach an async converter node */
320fb11a9c2SBrian Somers   snprintf(ngm.type, sizeof ngm.type, "%s", NG_ASYNC_NODE_TYPE);
321fb11a9c2SBrian Somers   snprintf(ngm.ourhook, sizeof ngm.ourhook, "%s", NG_TTY_HOOK);
322fb11a9c2SBrian Somers   snprintf(ngm.peerhook, sizeof ngm.peerhook, "%s", NG_ASYNC_HOOK_ASYNC);
323fb11a9c2SBrian Somers   log_Printf(LogDEBUG, "%s: Send mkpeer async:%s to %s:%s\n", p->link.name,
324fb11a9c2SBrian Somers              ngm.peerhook, ttypath, ngm.ourhook);
325fb11a9c2SBrian Somers   if (NgSendMsg(cs, ttypath, NGM_GENERIC_COOKIE,
326fb11a9c2SBrian Somers       NGM_MKPEER, &ngm, sizeof ngm) < 0) {
327fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't create %s node\n", p->link.name,
328fb11a9c2SBrian Somers                NG_ASYNC_NODE_TYPE);
329fb11a9c2SBrian Somers     goto failed;
330fb11a9c2SBrian Somers   }
331fb11a9c2SBrian Somers 
332fb11a9c2SBrian Somers   /* Connect the async node to our socket */
333fb11a9c2SBrian Somers   snprintf(ngc.path, sizeof ngc.path, "%s%s", ttypath, NG_TTY_HOOK);
334fb11a9c2SBrian Somers   snprintf(ngc.peerhook, sizeof ngc.peerhook, "%s", NG_ASYNC_HOOK_SYNC);
335fb11a9c2SBrian Somers   memcpy(ngc.ourhook, ngc.peerhook, sizeof ngc.ourhook);
336fb11a9c2SBrian Somers   log_Printf(LogDEBUG, "%s: Send connect %s:%s to .:%s\n", p->link.name,
337fb11a9c2SBrian Somers              ngc.path, ngc.peerhook, ngc.ourhook);
338fb11a9c2SBrian Somers   if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
339fb11a9c2SBrian Somers       &ngc, sizeof ngc) < 0) {
340fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't connect .:%s -> %s.%s: %s\n",
341fb11a9c2SBrian Somers                p->link.name, ngc.ourhook, ngc.path, ngc.peerhook,
342fb11a9c2SBrian Somers                strerror(errno));
343fb11a9c2SBrian Somers     goto failed;
344fb11a9c2SBrian Somers   }
345fb11a9c2SBrian Somers 
346fb11a9c2SBrian Somers   /* Get the async node id */
347fb11a9c2SBrian Somers   if (NgSendMsg(cs, ngc.path, NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) {
348fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't request async node info at %s: %s\n",
349fb11a9c2SBrian Somers                p->link.name, ngc.path, strerror(errno));
350fb11a9c2SBrian Somers     goto failed;
351fb11a9c2SBrian Somers   }
352fb11a9c2SBrian Somers   if (NgRecvMsg(cs, reply, sizeof rbuf, NULL) < 0) {
353fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't obtain async node info at %s: %s\n",
354fb11a9c2SBrian Somers                p->link.name, ngc.path, strerror(errno));
355fb11a9c2SBrian Somers     goto failed;
356fb11a9c2SBrian Somers   }
357fb11a9c2SBrian Somers 
358fb11a9c2SBrian Somers   /* All done, set up our device state */
359fb11a9c2SBrian Somers   snprintf(dev->hook, sizeof dev->hook, "%s", ngc.ourhook);
360fb11a9c2SBrian Somers   dev->cs = cs;
361fb11a9c2SBrian Somers   dev->real.fd = p->fd;
362fb11a9c2SBrian Somers   p->fd = ds;
363fb11a9c2SBrian Somers   dev->real.speed = speed;
364fb11a9c2SBrian Somers   physical_SetSync(p);
365fb11a9c2SBrian Somers 
366fb11a9c2SBrian Somers   tty_SetAsyncParams(p, 0xffffffff, 0xffffffff);
367fb11a9c2SBrian Somers   physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
368fb11a9c2SBrian Somers   log_Printf(LogPHASE, "%s: Loaded netgraph tty line discipline\n",
369fb11a9c2SBrian Somers              p->link.name);
370fb11a9c2SBrian Somers 
371fb11a9c2SBrian Somers   return 1;
372fb11a9c2SBrian Somers 
373fb11a9c2SBrian Somers failed:
374fb11a9c2SBrian Somers   ID0ioctl(p->fd, TIOCSETD, &dev->real.disc);
375fb11a9c2SBrian Somers   close(ds);
376fb11a9c2SBrian Somers   close(cs);
377fb11a9c2SBrian Somers 
378fb11a9c2SBrian Somers   return 0;
379fb11a9c2SBrian Somers }
380fb11a9c2SBrian Somers 
381fb11a9c2SBrian Somers static void
UnloadLineDiscipline(struct physical * p)382fb11a9c2SBrian Somers UnloadLineDiscipline(struct physical *p)
383fb11a9c2SBrian Somers {
384fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
385fb11a9c2SBrian Somers 
386fb11a9c2SBrian Somers   if (isngtty(dev)) {
387fb11a9c2SBrian Somers     if (!physical_SetSpeed(p, dev->real.speed))
388fb11a9c2SBrian Somers       log_Printf(LogWARN, "Couldn't reset tty speed to %d\n", dev->real.speed);
389fb11a9c2SBrian Somers     dev->real.speed = 0;
390fb11a9c2SBrian Somers     close(p->fd);
391fb11a9c2SBrian Somers     p->fd = dev->real.fd;
392fb11a9c2SBrian Somers     dev->real.fd = -1;
393fb11a9c2SBrian Somers     close(dev->cs);
394fb11a9c2SBrian Somers     dev->cs = -1;
395fb11a9c2SBrian Somers     *dev->hook = '\0';
396fb11a9c2SBrian Somers     if (ID0ioctl(p->fd, TIOCSETD, &dev->real.disc) == 0) {
397fb11a9c2SBrian Somers       physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
398fb11a9c2SBrian Somers       log_Printf(LogPHASE, "%s: Unloaded netgraph tty line discipline\n",
399fb11a9c2SBrian Somers                  p->link.name);
400fb11a9c2SBrian Somers     } else
401fb11a9c2SBrian Somers       log_Printf(LogWARN, "%s: Failed to unload netgraph tty line discipline\n",
402fb11a9c2SBrian Somers                  p->link.name);
403fb11a9c2SBrian Somers   }
404fb11a9c2SBrian Somers }
405fb11a9c2SBrian Somers 
406fb11a9c2SBrian Somers static ssize_t
tty_Write(struct physical * p,const void * v,size_t n)407fb11a9c2SBrian Somers tty_Write(struct physical *p, const void *v, size_t n)
408fb11a9c2SBrian Somers {
409fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
410fb11a9c2SBrian Somers 
411fb11a9c2SBrian Somers   if (isngtty(dev))
412057f1760SBrian Somers     return NgSendData(p->fd, dev->hook, v, n) == -1 ? -1 : (ssize_t)n;
413fb11a9c2SBrian Somers   else
414fb11a9c2SBrian Somers     return write(p->fd, v, n);
415fb11a9c2SBrian Somers }
416fb11a9c2SBrian Somers 
417fb11a9c2SBrian Somers static ssize_t
tty_Read(struct physical * p,void * v,size_t n)418fb11a9c2SBrian Somers tty_Read(struct physical *p, void *v, size_t n)
419fb11a9c2SBrian Somers {
420fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
421fb11a9c2SBrian Somers   char hook[sizeof NG_ASYNC_HOOK_SYNC];
422fb11a9c2SBrian Somers 
423fb11a9c2SBrian Somers   if (isngtty(dev))
424fb11a9c2SBrian Somers     return NgRecvData(p->fd, v, n, hook);
425fb11a9c2SBrian Somers   else
426fb11a9c2SBrian Somers     return read(p->fd, v, n);
427fb11a9c2SBrian Somers }
428fb11a9c2SBrian Somers 
429fb11a9c2SBrian Somers #endif /* NETGRAPH */
430fb11a9c2SBrian Somers 
431eb6e5e05SBrian Somers static int
tty_Raw(struct physical * p)4325d9e6103SBrian Somers tty_Raw(struct physical *p)
4335d9e6103SBrian Somers {
4346815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4358dbb1e2bSBrian Somers   struct termios ios;
4365d9e6103SBrian Somers   int oldflag;
4375d9e6103SBrian Somers 
438eb6e5e05SBrian Somers   log_Printf(LogDEBUG, "%s: Entering tty_Raw\n", p->link.name);
4395d9e6103SBrian Somers 
4406815097bSBrian Somers   if (p->type != PHYS_DIRECT && p->fd >= 0 && !Online(dev))
4418e7bd08eSBrian Somers     log_Printf(LogDEBUG, "%s: Raw: descriptor = %d, mbits = %x\n",
4426815097bSBrian Somers               p->link.name, p->fd, dev->mbits);
4435d9e6103SBrian Somers 
444eb6e5e05SBrian Somers   if (!physical_IsSync(p)) {
445fb11a9c2SBrian Somers #ifndef NONETGRAPH
446fb11a9c2SBrian Somers     if (!LoadLineDiscipline(p))
447fb11a9c2SBrian Somers #endif
448fb11a9c2SBrian Somers     {
4498dbb1e2bSBrian Somers       tcgetattr(p->fd, &ios);
4508dbb1e2bSBrian Somers       cfmakeraw(&ios);
4515d9e6103SBrian Somers       if (p->cfg.rts_cts)
4528dbb1e2bSBrian Somers         ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
4535d9e6103SBrian Somers       else
4548dbb1e2bSBrian Somers         ios.c_cflag |= CLOCAL;
4555d9e6103SBrian Somers 
456cde8638bSBrian Somers       if (p->type != PHYS_DEDICATED)
4578dbb1e2bSBrian Somers         ios.c_cflag |= HUPCL;
4585d9e6103SBrian Somers 
459fca09861SBrian Somers       if (tcsetattr(p->fd, TCSANOW, &ios) == -1)
460fca09861SBrian Somers         log_Printf(LogWARN, "%s: tcsetattr: Failed configuring device\n",
461fca09861SBrian Somers                    p->link.name);
462eb6e5e05SBrian Somers     }
463fb11a9c2SBrian Somers   }
4645d9e6103SBrian Somers 
4655d9e6103SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
4665d9e6103SBrian Somers   if (oldflag < 0)
4675d9e6103SBrian Somers     return 0;
4685d9e6103SBrian Somers   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
4695d9e6103SBrian Somers 
4705d9e6103SBrian Somers   return 1;
4715d9e6103SBrian Somers }
4725d9e6103SBrian Somers 
4735d9e6103SBrian Somers static void
tty_Offline(struct physical * p)4745d9e6103SBrian Somers tty_Offline(struct physical *p)
4755d9e6103SBrian Somers {
4766815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4776815097bSBrian Somers 
4785d9e6103SBrian Somers   if (p->fd >= 0) {
4796815097bSBrian Somers     timer_Stop(&dev->Timer);
480eb6e5e05SBrian Somers     dev->mbits &= ~TIOCM_DTR;	/* XXX: Hmm, what's this supposed to do ? */
4816815097bSBrian Somers     if (Online(dev)) {
4825d9e6103SBrian Somers       struct termios tio;
4835d9e6103SBrian Somers 
4845d9e6103SBrian Somers       tcgetattr(p->fd, &tio);
485fca09861SBrian Somers       if (cfsetspeed(&tio, B0) == -1 || tcsetattr(p->fd, TCSANOW, &tio) == -1)
4865d9e6103SBrian Somers         log_Printf(LogWARN, "%s: Unable to set physical to speed 0\n",
4875d9e6103SBrian Somers                    p->link.name);
4885d9e6103SBrian Somers     }
4895d9e6103SBrian Somers   }
4905d9e6103SBrian Somers }
4915d9e6103SBrian Somers 
4925d9e6103SBrian Somers static void
tty_Cooked(struct physical * p)4935d9e6103SBrian Somers tty_Cooked(struct physical *p)
4945d9e6103SBrian Somers {
4956815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4965d9e6103SBrian Somers   int oldflag;
4975d9e6103SBrian Somers 
498d0b3b745SBrian Somers   tty_Offline(p);	/* In case of emergency close()s */
499d0b3b745SBrian Somers 
5005d9e6103SBrian Somers   tcflush(p->fd, TCIOFLUSH);
501eb6e5e05SBrian Somers 
502fca09861SBrian Somers   if (!physical_IsSync(p) && tcsetattr(p->fd, TCSAFLUSH, &dev->ios) == -1)
503fca09861SBrian Somers     log_Printf(LogWARN, "%s: tcsetattr: Unable to restore device settings\n",
504fca09861SBrian Somers                p->link.name);
505eb6e5e05SBrian Somers 
506fb11a9c2SBrian Somers #ifndef NONETGRAPH
507fb11a9c2SBrian Somers   UnloadLineDiscipline(p);
508fb11a9c2SBrian Somers #endif
509fb11a9c2SBrian Somers 
510eb6e5e05SBrian Somers   if ((oldflag = fcntl(p->fd, F_GETFL, 0)) != -1)
5115d9e6103SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
5125d9e6103SBrian Somers }
5135d9e6103SBrian Somers 
5145d9e6103SBrian Somers static void
tty_StopTimer(struct physical * p)5156815097bSBrian Somers tty_StopTimer(struct physical *p)
5165d9e6103SBrian Somers {
5176815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
5186815097bSBrian Somers 
5196815097bSBrian Somers   timer_Stop(&dev->Timer);
5205d9e6103SBrian Somers }
5215d9e6103SBrian Somers 
5225d9e6103SBrian Somers static void
tty_Free(struct physical * p)5236815097bSBrian Somers tty_Free(struct physical *p)
5245d9e6103SBrian Somers {
5256815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
5266815097bSBrian Somers 
527d0b3b745SBrian Somers   tty_Offline(p);	/* In case of emergency close()s */
5286815097bSBrian Somers   free(dev);
5295d9e6103SBrian Somers }
5305d9e6103SBrian Somers 
531057f1760SBrian Somers static unsigned
tty_Speed(struct physical * p)5325d9e6103SBrian Somers tty_Speed(struct physical *p)
5335d9e6103SBrian Somers {
5348dbb1e2bSBrian Somers   struct termios ios;
5355d9e6103SBrian Somers 
5368dbb1e2bSBrian Somers   if (tcgetattr(p->fd, &ios) == -1)
5375d9e6103SBrian Somers     return 0;
5385d9e6103SBrian Somers 
539057f1760SBrian Somers   return SpeedToUnsigned(cfgetispeed(&ios));
5405d9e6103SBrian Somers }
5415d9e6103SBrian Somers 
5425d9e6103SBrian Somers static const char *
tty_OpenInfo(struct physical * p)5435d9e6103SBrian Somers tty_OpenInfo(struct physical *p)
5445d9e6103SBrian Somers {
5456815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
5465d9e6103SBrian Somers   static char buf[13];
5475d9e6103SBrian Somers 
5486815097bSBrian Somers   if (Online(dev))
5495d9e6103SBrian Somers     strcpy(buf, "with");
5505d9e6103SBrian Somers   else
5515d9e6103SBrian Somers     strcpy(buf, "no");
5525d9e6103SBrian Somers   strcat(buf, " carrier");
553eb6e5e05SBrian Somers 
5545d9e6103SBrian Somers   return buf;
5555d9e6103SBrian Somers }
5565d9e6103SBrian Somers 
557de59e178SBrian Somers static int
tty_Slot(struct physical * p)558de59e178SBrian Somers tty_Slot(struct physical *p)
559de59e178SBrian Somers {
560de59e178SBrian Somers   struct ttyent *ttyp;
561de59e178SBrian Somers   int slot;
562de59e178SBrian Somers 
563de59e178SBrian Somers   setttyent();
564de59e178SBrian Somers   for (slot = 1; (ttyp = getttyent()); ++slot)
565de59e178SBrian Somers     if (!strcmp(ttyp->ty_name, p->name.base)) {
566de59e178SBrian Somers       endttyent();
567de59e178SBrian Somers       return slot;
568de59e178SBrian Somers     }
569de59e178SBrian Somers 
570de59e178SBrian Somers   endttyent();
571de59e178SBrian Somers   return -1;
572de59e178SBrian Somers }
573de59e178SBrian Somers 
5746815097bSBrian Somers static void
tty_device2iov(struct device * d,struct iovec * iov,int * niov,int maxiov __unused,int * auxfd,int * nauxfd)575f5a99677SBrian Somers tty_device2iov(struct device *d, struct iovec *iov, int *niov,
5761ffcdfc9SRuslan Ermilov                int maxiov __unused,
5771ffcdfc9SRuslan Ermilov #ifndef NONETGRAPH
5781ffcdfc9SRuslan Ermilov                int *auxfd, int *nauxfd
5791ffcdfc9SRuslan Ermilov #else
5801ffcdfc9SRuslan Ermilov                int *auxfd __unused, int *nauxfd __unused
5811ffcdfc9SRuslan Ermilov #endif
5821ffcdfc9SRuslan Ermilov                )
5836815097bSBrian Somers {
584c5e246d4SBrian Somers   struct ttydevice *dev;
585f5a99677SBrian Somers   int sz = physical_MaxDeviceSize();
5866815097bSBrian Somers 
587c5e246d4SBrian Somers   iov[*niov].iov_base = d = realloc(d, sz);
588c5e246d4SBrian Somers   if (d == NULL) {
589f5a99677SBrian Somers     log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
590f5a99677SBrian Somers     AbortProgram(EX_OSERR);
591f5a99677SBrian Somers   }
592f5a99677SBrian Somers   iov[*niov].iov_len = sz;
5936815097bSBrian Somers   (*niov)++;
5946815097bSBrian Somers 
595c5e246d4SBrian Somers   dev = device2tty(d);
596c5e246d4SBrian Somers 
597fb11a9c2SBrian Somers #ifndef NONETGRAPH
598fb11a9c2SBrian Somers   if (dev->cs >= 0) {
599fb11a9c2SBrian Somers     *auxfd = dev->cs;
600fb11a9c2SBrian Somers     (*nauxfd)++;
601fb11a9c2SBrian Somers   }
602fb11a9c2SBrian Somers #endif
603fb11a9c2SBrian Somers 
6046815097bSBrian Somers   if (dev->Timer.state != TIMER_STOPPED) {
6056815097bSBrian Somers     timer_Stop(&dev->Timer);
6066815097bSBrian Somers     dev->Timer.state = TIMER_RUNNING;
6076815097bSBrian Somers   }
6086815097bSBrian Somers }
6096815097bSBrian Somers 
6106815097bSBrian Somers static struct device basettydevice = {
6115d9e6103SBrian Somers   TTY_DEVICE,
6125d9e6103SBrian Somers   "tty",
613c8b9fb53SBrian Somers   0,
614fdc29d54SBrian Somers   { CD_VARIABLE, DEF_TTYCDDELAY },
615eb6e5e05SBrian Somers   tty_AwaitCarrier,
61687c3786eSBrian Somers   NULL,
6175d9e6103SBrian Somers   tty_Raw,
6185d9e6103SBrian Somers   tty_Offline,
6195d9e6103SBrian Somers   tty_Cooked,
620fb11a9c2SBrian Somers   tty_SetAsyncParams,
6216815097bSBrian Somers   tty_StopTimer,
6226815097bSBrian Somers   tty_Free,
623fb11a9c2SBrian Somers   tty_Read,
624fb11a9c2SBrian Somers   tty_Write,
6256815097bSBrian Somers   tty_device2iov,
6265d9e6103SBrian Somers   tty_Speed,
627de59e178SBrian Somers   tty_OpenInfo,
628de59e178SBrian Somers   tty_Slot
6295d9e6103SBrian Somers };
6306815097bSBrian Somers 
6319950fb2aSBrian Somers struct device *
tty_iov2device(int type,struct physical * p,struct iovec * iov,int * niov,int maxiov __unused,int * auxfd,int * nauxfd)6329950fb2aSBrian Somers tty_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
6331ffcdfc9SRuslan Ermilov                int maxiov __unused,
6341ffcdfc9SRuslan Ermilov #ifndef NONETGRAPH
6351ffcdfc9SRuslan Ermilov                int *auxfd, int *nauxfd
6361ffcdfc9SRuslan Ermilov #else
6371ffcdfc9SRuslan Ermilov                int *auxfd __unused, int *nauxfd __unused
6381ffcdfc9SRuslan Ermilov #endif
6391ffcdfc9SRuslan Ermilov                )
6409950fb2aSBrian Somers {
6419950fb2aSBrian Somers   if (type == TTY_DEVICE) {
642acbd1f00SBrian Somers     struct ttydevice *dev = (struct ttydevice *)iov[(*niov)++].iov_base;
6439950fb2aSBrian Somers 
644f5a99677SBrian Somers     dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
645f5a99677SBrian Somers     if (dev == NULL) {
646f5a99677SBrian Somers       log_Printf(LogALERT, "Failed to allocate memory: %d\n",
647f5a99677SBrian Somers                  (int)(sizeof *dev));
648f5a99677SBrian Somers       AbortProgram(EX_OSERR);
649f5a99677SBrian Somers     }
650f5a99677SBrian Somers 
651fb11a9c2SBrian Somers #ifndef NONETGRAPH
652fb11a9c2SBrian Somers     if (*nauxfd) {
653fb11a9c2SBrian Somers       dev->cs = *auxfd;
654fb11a9c2SBrian Somers       (*nauxfd)--;
655fb11a9c2SBrian Somers     } else
656fb11a9c2SBrian Somers       dev->cs = -1;
657fb11a9c2SBrian Somers #endif
658fb11a9c2SBrian Somers 
6599950fb2aSBrian Somers     /* Refresh function pointers etc */
6609950fb2aSBrian Somers     memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
6619950fb2aSBrian Somers 
662acbd1f00SBrian Somers     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
6639950fb2aSBrian Somers     if (dev->Timer.state != TIMER_STOPPED) {
6649950fb2aSBrian Somers       dev->Timer.state = TIMER_STOPPED;
665f5a99677SBrian Somers       p->handler = &dev->dev;		/* For the benefit of StartTimer */
6669950fb2aSBrian Somers       tty_StartTimer(p);
6679950fb2aSBrian Somers     }
6689950fb2aSBrian Somers     return &dev->dev;
6699950fb2aSBrian Somers   }
6709950fb2aSBrian Somers 
6719950fb2aSBrian Somers   return NULL;
6729950fb2aSBrian Somers }
6739950fb2aSBrian Somers 
6749950fb2aSBrian Somers struct device *
tty_Create(struct physical * p)6759950fb2aSBrian Somers tty_Create(struct physical *p)
67627be3ac6SBrian Somers {
67727be3ac6SBrian Somers   struct ttydevice *dev;
67827be3ac6SBrian Somers   struct termios ios;
67927be3ac6SBrian Somers   int oldflag;
68027be3ac6SBrian Somers 
6819950fb2aSBrian Somers   if (p->fd < 0 || !isatty(p->fd))
6829950fb2aSBrian Somers     /* Don't want this */
68327be3ac6SBrian Somers     return NULL;
68427be3ac6SBrian Somers 
6859950fb2aSBrian Somers   if (*p->name.full == '\0') {
6869950fb2aSBrian Somers     physical_SetDevice(p, ttyname(p->fd));
6879950fb2aSBrian Somers     log_Printf(LogDEBUG, "%s: Input is a tty (%s)\n",
6889950fb2aSBrian Somers                p->link.name, p->name.full);
6899950fb2aSBrian Somers   } else
6909950fb2aSBrian Somers     log_Printf(LogDEBUG, "%s: Opened %s\n", p->link.name, p->name.full);
6919950fb2aSBrian Somers 
6929950fb2aSBrian Somers   /* We're gonna return a ttydevice (unless something goes horribly wrong) */
6939950fb2aSBrian Somers 
6949950fb2aSBrian Somers   if ((dev = malloc(sizeof *dev)) == NULL) {
6959950fb2aSBrian Somers     /* Complete failure - parent doesn't continue trying to ``create'' */
6969950fb2aSBrian Somers     close(p->fd);
6979950fb2aSBrian Somers     p->fd = -1;
6989950fb2aSBrian Somers     return NULL;
6999950fb2aSBrian Somers   }
7009950fb2aSBrian Somers 
70127be3ac6SBrian Somers   memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
7024b698945SBrian Somers   memset(&dev->Timer, '\0', sizeof dev->Timer);
703eb6e5e05SBrian Somers   dev->mbits = -1;
704fb11a9c2SBrian Somers #ifndef NONETGRAPH
705fb11a9c2SBrian Somers   dev->real.speed = 0;
706fb11a9c2SBrian Somers   dev->real.fd = -1;
707fb11a9c2SBrian Somers   dev->real.disc = -1;
708fb11a9c2SBrian Somers   *dev->hook = '\0';
709fb11a9c2SBrian Somers #endif
71027be3ac6SBrian Somers   tcgetattr(p->fd, &ios);
71127be3ac6SBrian Somers   dev->ios = ios;
71227be3ac6SBrian Somers 
713fdc29d54SBrian Somers   if (p->cfg.cd.necessity != CD_DEFAULT)
714fdc29d54SBrian Somers     /* Any override is ok for the tty device */
715fdc29d54SBrian Somers     dev->dev.cd = p->cfg.cd;
716fdc29d54SBrian Somers 
7179950fb2aSBrian Somers   log_Printf(LogDEBUG, "%s: tty_Create: physical (get): fd = %d,"
71827be3ac6SBrian Somers              " iflag = %lx, oflag = %lx, cflag = %lx\n", p->link.name, p->fd,
71927be3ac6SBrian Somers              (u_long)ios.c_iflag, (u_long)ios.c_oflag, (u_long)ios.c_cflag);
72027be3ac6SBrian Somers 
72127be3ac6SBrian Somers   cfmakeraw(&ios);
72227be3ac6SBrian Somers   if (p->cfg.rts_cts)
72327be3ac6SBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
72427be3ac6SBrian Somers   else {
72527be3ac6SBrian Somers     ios.c_cflag |= CLOCAL;
72627be3ac6SBrian Somers     ios.c_iflag |= IXOFF;
72727be3ac6SBrian Somers   }
72827be3ac6SBrian Somers   ios.c_iflag |= IXON;
729cde8638bSBrian Somers   if (p->type != PHYS_DEDICATED)
73027be3ac6SBrian Somers     ios.c_cflag |= HUPCL;
73127be3ac6SBrian Somers 
73227be3ac6SBrian Somers   if (p->type != PHYS_DIRECT) {
73327be3ac6SBrian Somers       /* Change tty speed when we're not in -direct mode */
73427be3ac6SBrian Somers       ios.c_cflag &= ~(CSIZE | PARODD | PARENB);
73527be3ac6SBrian Somers       ios.c_cflag |= p->cfg.parity;
736057f1760SBrian Somers       if (cfsetspeed(&ios, UnsignedToSpeed(p->cfg.speed)) == -1)
73727be3ac6SBrian Somers 	log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n",
73827be3ac6SBrian Somers 		  p->link.name, p->name.full, p->cfg.speed);
73927be3ac6SBrian Somers   }
740fca09861SBrian Somers 
741fca09861SBrian Somers   if (tcsetattr(p->fd, TCSADRAIN, &ios) == -1) {
742fca09861SBrian Somers     log_Printf(LogWARN, "%s: tcsetattr: Failed configuring device\n",
743fca09861SBrian Somers                p->link.name);
744fca09861SBrian Somers     if (p->type != PHYS_DIRECT && p->cfg.speed > 115200)
745fca09861SBrian Somers       log_Printf(LogWARN, "%.*s             Perhaps the speed is unsupported\n",
746fca09861SBrian Somers                  (int)strlen(p->link.name), "");
747fca09861SBrian Somers   }
748fca09861SBrian Somers 
74927be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: physical (put): iflag = %lx, oflag = %lx, "
75027be3ac6SBrian Somers             "cflag = %lx\n", p->link.name, (u_long)ios.c_iflag,
75127be3ac6SBrian Somers             (u_long)ios.c_oflag, (u_long)ios.c_cflag);
75227be3ac6SBrian Somers 
75327be3ac6SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
75427be3ac6SBrian Somers   if (oldflag < 0) {
7559950fb2aSBrian Somers     /* Complete failure - parent doesn't continue trying to ``create'' */
7569950fb2aSBrian Somers 
75727be3ac6SBrian Somers     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
75827be3ac6SBrian Somers                p->link.name, strerror(errno));
7599950fb2aSBrian Somers     tty_Cooked(p);
7609950fb2aSBrian Somers     close(p->fd);
7619950fb2aSBrian Somers     p->fd = -1;
762eb6e5e05SBrian Somers     free(dev);
76327be3ac6SBrian Somers     return NULL;
76427be3ac6SBrian Somers   } else
76527be3ac6SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
76627be3ac6SBrian Somers 
767acbd1f00SBrian Somers   physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
76827be3ac6SBrian Somers 
76927be3ac6SBrian Somers   return &dev->dev;
77027be3ac6SBrian Somers }
771