xref: /freebsd/usr.sbin/ppp/tty.c (revision 97486b09)
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  *
2697d92980SPeter Wemm  * $FreeBSD$
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>
435d9e6103SBrian Somers #include <unistd.h>
4497486b09SBrian Somers #ifndef NONETGRAPH
45fb11a9c2SBrian Somers #include <netgraph.h>
46fb11a9c2SBrian Somers #include <netgraph/ng_async.h>
47fb11a9c2SBrian Somers #include <netgraph/ng_message.h>
48fb11a9c2SBrian Somers #include <netgraph/ng_ppp.h>
49fb11a9c2SBrian Somers #include <netgraph/ng_tty.h>
5097486b09SBrian Somers #endif
515d9e6103SBrian Somers 
525d9e6103SBrian Somers #include "layer.h"
535d9e6103SBrian Somers #include "defs.h"
545d9e6103SBrian Somers #include "mbuf.h"
555d9e6103SBrian Somers #include "log.h"
565d9e6103SBrian Somers #include "timer.h"
575d9e6103SBrian Somers #include "lqr.h"
585d9e6103SBrian Somers #include "hdlc.h"
595d9e6103SBrian Somers #include "throughput.h"
605d9e6103SBrian Somers #include "fsm.h"
615d9e6103SBrian Somers #include "lcp.h"
625d9e6103SBrian Somers #include "ccp.h"
635d9e6103SBrian Somers #include "link.h"
645d9e6103SBrian Somers #include "async.h"
655d9e6103SBrian Somers #include "descriptor.h"
665d9e6103SBrian Somers #include "physical.h"
675d9e6103SBrian Somers #include "mp.h"
685d9e6103SBrian Somers #include "chat.h"
695d9e6103SBrian Somers #include "auth.h"
705d9e6103SBrian Somers #include "chap.h"
715d9e6103SBrian Somers #include "cbcp.h"
725d9e6103SBrian Somers #include "datalink.h"
73f5a99677SBrian Somers #include "main.h"
74fb11a9c2SBrian Somers #include "id.h"
755d9e6103SBrian Somers #include "tty.h"
765d9e6103SBrian Somers 
771d3a2f02SBrian Somers #if defined(__mac68k__) || defined(__macppc__)
781d3a2f02SBrian Somers #undef	CRTS_IFLOW
791d3a2f02SBrian Somers #undef	CCTS_OFLOW
801d3a2f02SBrian Somers #define	CRTS_IFLOW	CDTRCTS
811d3a2f02SBrian Somers #define	CCTS_OFLOW	CDTRCTS
821d3a2f02SBrian Somers #endif
831d3a2f02SBrian Somers 
846815097bSBrian Somers #define	Online(dev)	((dev)->mbits & TIOCM_CD)
856815097bSBrian Somers 
866815097bSBrian Somers struct ttydevice {
876815097bSBrian Somers   struct device dev;		/* What struct physical knows about */
886815097bSBrian Somers   struct pppTimer Timer;	/* CD checks */
896815097bSBrian Somers   int mbits;			/* Current DCD status */
90eb6e5e05SBrian Somers   int carrier_seconds;		/* seconds before CD is *required* */
91fb11a9c2SBrian Somers #ifndef NONETGRAPH
92fb11a9c2SBrian Somers   struct {
93fb11a9c2SBrian Somers     int speed;			/* Pre-line-discipline speed */
94fb11a9c2SBrian Somers     int fd;			/* Pre-line-discipline fd */
95fb11a9c2SBrian Somers     int disc;			/* Old line-discipline */
96fb11a9c2SBrian Somers   } real;
97fb11a9c2SBrian Somers   char hook[sizeof NG_ASYNC_HOOK_SYNC]; /* our ng_socket hook */
98fb11a9c2SBrian Somers   int cs;			/* A netgraph control socket (maybe) */
99fb11a9c2SBrian Somers #endif
1006815097bSBrian Somers   struct termios ios;		/* To be able to reset from raw mode */
1016815097bSBrian Somers };
1026815097bSBrian Somers 
1036815097bSBrian Somers #define device2tty(d) ((d)->type == TTY_DEVICE ? (struct ttydevice *)d : NULL)
1045d9e6103SBrian Somers 
105f5a99677SBrian Somers int
106f5a99677SBrian Somers tty_DeviceSize(void)
107f5a99677SBrian Somers {
108f5a99677SBrian Somers   return sizeof(struct ttydevice);
109f5a99677SBrian Somers }
110f5a99677SBrian Somers 
1115d9e6103SBrian Somers /*
1125d9e6103SBrian Somers  * tty_Timeout() watches the DCD signal and mentions it if it's status
1135d9e6103SBrian Somers  * changes.
1145d9e6103SBrian Somers  */
1155d9e6103SBrian Somers static void
1165d9e6103SBrian Somers tty_Timeout(void *data)
1175d9e6103SBrian Somers {
1185d9e6103SBrian Somers   struct physical *p = data;
1196815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1205d9e6103SBrian Somers   int ombits, change;
1215d9e6103SBrian Somers 
1226815097bSBrian Somers   timer_Stop(&dev->Timer);
1236815097bSBrian Somers   dev->Timer.load = SECTICKS;		/* Once a second please */
1246815097bSBrian Somers   timer_Start(&dev->Timer);
1256815097bSBrian Somers   ombits = dev->mbits;
1265d9e6103SBrian Somers 
1275d9e6103SBrian Somers   if (p->fd >= 0) {
1286815097bSBrian Somers     if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) {
129eb6e5e05SBrian Somers       /* we must be a pty ? */
130fdc29d54SBrian Somers       if (p->cfg.cd.necessity != CD_DEFAULT)
131fdc29d54SBrian Somers         log_Printf(LogWARN, "%s: Carrier ioctl not supported, "
132fdc29d54SBrian Somers                    "using ``set cd off''\n", p->link.name);
1336815097bSBrian Somers       timer_Stop(&dev->Timer);
1349acc8460SBrian Somers       dev->mbits = TIOCM_CD;
1355d9e6103SBrian Somers       return;
1365d9e6103SBrian Somers     }
1375d9e6103SBrian Somers   } else
1386815097bSBrian Somers     dev->mbits = 0;
1395d9e6103SBrian Somers 
1405d9e6103SBrian Somers   if (ombits == -1) {
1415d9e6103SBrian Somers     /* First time looking for carrier */
1426815097bSBrian Somers     if (Online(dev))
143eb6e5e05SBrian Somers       log_Printf(LogPHASE, "%s: %s: CD detected\n", p->link.name, p->name.full);
144fdc29d54SBrian Somers     else if (++dev->carrier_seconds >= dev->dev.cd.delay) {
145fdc29d54SBrian Somers       if (dev->dev.cd.necessity == CD_REQUIRED)
1465d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: %s: Required CD not detected\n",
1475d9e6103SBrian Somers                    p->link.name, p->name.full);
148eb6e5e05SBrian Somers       else {
1495d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: %s doesn't support CD\n",
1505d9e6103SBrian Somers                    p->link.name, p->name.full);
151eb6e5e05SBrian Somers         dev->mbits = TIOCM_CD;		/* Dodgy null-modem cable ? */
152eb6e5e05SBrian Somers       }
1536815097bSBrian Somers       timer_Stop(&dev->Timer);
154eb6e5e05SBrian Somers       /* tty_AwaitCarrier() will notice */
155eb6e5e05SBrian Somers     } else {
156eb6e5e05SBrian Somers       /* Keep waiting */
157eb6e5e05SBrian Somers       log_Printf(LogDEBUG, "%s: %s: Still no carrier (%d/%d)\n",
158eb6e5e05SBrian Somers                  p->link.name, p->name.full, dev->carrier_seconds,
159fdc29d54SBrian Somers                  dev->dev.cd.delay);
160eb6e5e05SBrian Somers       dev->mbits = -1;
1615d9e6103SBrian Somers     }
1625d9e6103SBrian Somers   } else {
1636815097bSBrian Somers     change = ombits ^ dev->mbits;
1645d9e6103SBrian Somers     if (change & TIOCM_CD) {
1656815097bSBrian Somers       if (dev->mbits & TIOCM_CD)
1665d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name);
1675d9e6103SBrian Somers       else {
1685d9e6103SBrian Somers         log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name);
1695d9e6103SBrian Somers         log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name);
1705d9e6103SBrian Somers         datalink_Down(p->dl, CLOSE_NORMAL);
1716815097bSBrian Somers         timer_Stop(&dev->Timer);
1725d9e6103SBrian Somers       }
1735d9e6103SBrian Somers     } else
1745d9e6103SBrian Somers       log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name,
1756815097bSBrian Somers                  Online(dev) ? "on" : "off");
1765d9e6103SBrian Somers   }
1775d9e6103SBrian Somers }
1785d9e6103SBrian Somers 
1795d9e6103SBrian Somers static void
1805d9e6103SBrian Somers tty_StartTimer(struct physical *p)
1815d9e6103SBrian Somers {
1826815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
1836815097bSBrian Somers 
1846815097bSBrian Somers   timer_Stop(&dev->Timer);
185eb6e5e05SBrian Somers   dev->Timer.load = SECTICKS;
1866815097bSBrian Somers   dev->Timer.func = tty_Timeout;
1876815097bSBrian Somers   dev->Timer.name = "tty CD";
1886815097bSBrian Somers   dev->Timer.arg = p;
1895d9e6103SBrian Somers   log_Printf(LogDEBUG, "%s: Using tty_Timeout [%p]\n",
1905d9e6103SBrian Somers              p->link.name, tty_Timeout);
1916815097bSBrian Somers   timer_Start(&dev->Timer);
1925d9e6103SBrian Somers }
1935d9e6103SBrian Somers 
1945d9e6103SBrian Somers static int
195eb6e5e05SBrian Somers tty_AwaitCarrier(struct physical *p)
196eb6e5e05SBrian Somers {
197eb6e5e05SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
198eb6e5e05SBrian Somers 
199fdc29d54SBrian Somers   if (dev->dev.cd.necessity == CD_NOTREQUIRED || physical_IsSync(p))
200eb6e5e05SBrian Somers     return CARRIER_OK;
201eb6e5e05SBrian Somers 
202eb6e5e05SBrian Somers   if (dev->mbits == -1) {
203eb6e5e05SBrian Somers     if (dev->Timer.state == TIMER_STOPPED) {
204eb6e5e05SBrian Somers       dev->carrier_seconds = 0;
205eb6e5e05SBrian Somers       tty_StartTimer(p);
206eb6e5e05SBrian Somers     }
207eb6e5e05SBrian Somers     return CARRIER_PENDING;			/* Not yet ! */
208eb6e5e05SBrian Somers   }
209eb6e5e05SBrian Somers 
2109acc8460SBrian Somers   return Online(dev) ? CARRIER_OK : CARRIER_LOST;
211eb6e5e05SBrian Somers }
212eb6e5e05SBrian Somers 
213fb11a9c2SBrian Somers #ifdef NONETGRAPH
214fb11a9c2SBrian Somers #define tty_SetAsyncParams	NULL
215fb11a9c2SBrian Somers #define tty_Write		NULL
216fb11a9c2SBrian Somers #define tty_Read		NULL
217fb11a9c2SBrian Somers #else
218fb11a9c2SBrian Somers 
219fb11a9c2SBrian Somers static int
220fb11a9c2SBrian Somers isngtty(struct ttydevice *dev)
221fb11a9c2SBrian Somers {
222fb11a9c2SBrian Somers   return dev->real.fd != -1;
223fb11a9c2SBrian Somers }
224fb11a9c2SBrian Somers 
225fb11a9c2SBrian Somers static void
226fb11a9c2SBrian Somers tty_SetAsyncParams(struct physical *p, u_int32_t mymap, u_int32_t hismap)
227fb11a9c2SBrian Somers {
228fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
229fb11a9c2SBrian Somers   char asyncpath[NG_PATHLEN + 1];
230fb11a9c2SBrian Somers   struct ng_async_cfg cfg;
231fb11a9c2SBrian Somers 
232fb11a9c2SBrian Somers   if (isngtty(dev)) {
233fb11a9c2SBrian Somers     /* Configure the async converter node */
234fb11a9c2SBrian Somers 
235fb11a9c2SBrian Somers     snprintf(asyncpath, sizeof asyncpath, ".:%s", dev->hook);
236fb11a9c2SBrian Somers     memset(&cfg, 0, sizeof cfg);
237fb11a9c2SBrian Somers     cfg.enabled = 1;
238fb11a9c2SBrian Somers     cfg.accm = mymap | hismap;
239fb11a9c2SBrian Somers     cfg.amru = MAX_MTU;
240fb11a9c2SBrian Somers     cfg.smru = MAX_MRU;
241fb11a9c2SBrian Somers     log_Printf(LogDEBUG, "Configure async node at %s\n", asyncpath);
242fb11a9c2SBrian Somers     if (NgSendMsg(dev->cs, asyncpath, NGM_ASYNC_COOKIE,
243fb11a9c2SBrian Somers                   NGM_ASYNC_CMD_SET_CONFIG, &cfg, sizeof cfg) < 0)
244fb11a9c2SBrian Somers       log_Printf(LogWARN, "%s: Can't configure async node at %s\n",
245fb11a9c2SBrian Somers                  p->link.name, asyncpath);
246fb11a9c2SBrian Somers   } else
247fb11a9c2SBrian Somers     /* No netgraph node, just config the async layer */
248fb11a9c2SBrian Somers     async_SetLinkParams(&p->async, mymap, hismap);
249fb11a9c2SBrian Somers }
250fb11a9c2SBrian Somers 
251fb11a9c2SBrian Somers static int
252fb11a9c2SBrian Somers LoadLineDiscipline(struct physical *p)
253fb11a9c2SBrian Somers {
254fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
255fb11a9c2SBrian Somers   u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
256fb11a9c2SBrian Somers   struct ng_mesg *reply;
257fb11a9c2SBrian Somers   struct nodeinfo *info;
258fb11a9c2SBrian Somers   char ttypath[NG_NODELEN + 1];
259fb11a9c2SBrian Somers   struct ngm_mkpeer ngm;
260fb11a9c2SBrian Somers   struct ngm_connect ngc;
261fb11a9c2SBrian Somers   int ldisc, cs, ds, hot, speed;
262fb11a9c2SBrian Somers 
263fb11a9c2SBrian Somers   reply = (struct ng_mesg *)rbuf;
264fb11a9c2SBrian Somers   info = (struct nodeinfo *)reply->data;
265fb11a9c2SBrian Somers 
266fb11a9c2SBrian Somers   loadmodules(LOAD_VERBOSLY, "netgraph", "ng_tty", "ng_async", "ng_socket",
267fb11a9c2SBrian Somers               NULL);
268fb11a9c2SBrian Somers 
269fb11a9c2SBrian Somers   /* Get the speed before loading the line discipline */
270fb11a9c2SBrian Somers   speed = physical_GetSpeed(p);
271fb11a9c2SBrian Somers 
272fb11a9c2SBrian Somers   if (ioctl(p->fd, TIOCGETD, &dev->real.disc) < 0) {
273fb11a9c2SBrian Somers     log_Printf(LogDEBUG, "%s: Couldn't get tty line discipline\n",
274fb11a9c2SBrian Somers                p->link.name);
275fb11a9c2SBrian Somers     return 0;
276fb11a9c2SBrian Somers   }
277fb11a9c2SBrian Somers   ldisc = NETGRAPHDISC;
278fb11a9c2SBrian Somers   if (ID0ioctl(p->fd, TIOCSETD, &ldisc) < 0) {
279fb11a9c2SBrian Somers     log_Printf(LogDEBUG, "%s: Couldn't set NETGRAPHDISC line discipline\n",
280fb11a9c2SBrian Somers                p->link.name);
281fb11a9c2SBrian Somers     return 0;
282fb11a9c2SBrian Somers   }
283fb11a9c2SBrian Somers 
284fb11a9c2SBrian Somers   /* Get the name of the tty node */
285fb11a9c2SBrian Somers   if (ioctl(p->fd, NGIOCGINFO, info) < 0) {
286fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: ioctl(NGIOCGINFO): %s\n", p->link.name,
287fb11a9c2SBrian Somers                strerror(errno));
288fb11a9c2SBrian Somers     ID0ioctl(p->fd, TIOCSETD, &dev->real.disc);
289fb11a9c2SBrian Somers     return 0;
290fb11a9c2SBrian Somers   }
291fb11a9c2SBrian Somers   snprintf(ttypath, sizeof ttypath, "%s:", info->name);
292fb11a9c2SBrian Somers 
293fb11a9c2SBrian Somers   /* Create a socket node for our endpoint (and to send messages via) */
294fb11a9c2SBrian Somers   if (ID0NgMkSockNode(NULL, &cs, &ds) == -1) {
295fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: NgMkSockNode: %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 
301fb11a9c2SBrian Somers   /* Set the ``hot char'' on the TTY node */
302fb11a9c2SBrian Somers   hot = HDLC_SYN;
303fb11a9c2SBrian Somers   log_Printf(LogDEBUG, "%s: Set tty hotchar to 0x%02x\n", p->link.name, hot);
304fb11a9c2SBrian Somers   if (NgSendMsg(cs, ttypath, NGM_TTY_COOKIE,
305fb11a9c2SBrian Somers       NGM_TTY_SET_HOTCHAR, &hot, sizeof hot) < 0) {
306fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't set hot char\n", p->link.name);
307fb11a9c2SBrian Somers     goto failed;
308fb11a9c2SBrian Somers   }
309fb11a9c2SBrian Somers 
310fb11a9c2SBrian Somers   /* Attach an async converter node */
311fb11a9c2SBrian Somers   snprintf(ngm.type, sizeof ngm.type, "%s", NG_ASYNC_NODE_TYPE);
312fb11a9c2SBrian Somers   snprintf(ngm.ourhook, sizeof ngm.ourhook, "%s", NG_TTY_HOOK);
313fb11a9c2SBrian Somers   snprintf(ngm.peerhook, sizeof ngm.peerhook, "%s", NG_ASYNC_HOOK_ASYNC);
314fb11a9c2SBrian Somers   log_Printf(LogDEBUG, "%s: Send mkpeer async:%s to %s:%s\n", p->link.name,
315fb11a9c2SBrian Somers              ngm.peerhook, ttypath, ngm.ourhook);
316fb11a9c2SBrian Somers   if (NgSendMsg(cs, ttypath, NGM_GENERIC_COOKIE,
317fb11a9c2SBrian Somers       NGM_MKPEER, &ngm, sizeof ngm) < 0) {
318fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't create %s node\n", p->link.name,
319fb11a9c2SBrian Somers                NG_ASYNC_NODE_TYPE);
320fb11a9c2SBrian Somers     goto failed;
321fb11a9c2SBrian Somers   }
322fb11a9c2SBrian Somers 
323fb11a9c2SBrian Somers   /* Connect the async node to our socket */
324fb11a9c2SBrian Somers   snprintf(ngc.path, sizeof ngc.path, "%s%s", ttypath, NG_TTY_HOOK);
325fb11a9c2SBrian Somers   snprintf(ngc.peerhook, sizeof ngc.peerhook, "%s", NG_ASYNC_HOOK_SYNC);
326fb11a9c2SBrian Somers   memcpy(ngc.ourhook, ngc.peerhook, sizeof ngc.ourhook);
327fb11a9c2SBrian Somers   log_Printf(LogDEBUG, "%s: Send connect %s:%s to .:%s\n", p->link.name,
328fb11a9c2SBrian Somers              ngc.path, ngc.peerhook, ngc.ourhook);
329fb11a9c2SBrian Somers   if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT,
330fb11a9c2SBrian Somers       &ngc, sizeof ngc) < 0) {
331fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't connect .:%s -> %s.%s: %s\n",
332fb11a9c2SBrian Somers                p->link.name, ngc.ourhook, ngc.path, ngc.peerhook,
333fb11a9c2SBrian Somers                strerror(errno));
334fb11a9c2SBrian Somers     goto failed;
335fb11a9c2SBrian Somers   }
336fb11a9c2SBrian Somers 
337fb11a9c2SBrian Somers   /* Get the async node id */
338fb11a9c2SBrian Somers   if (NgSendMsg(cs, ngc.path, NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) {
339fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't request async node info at %s: %s\n",
340fb11a9c2SBrian Somers                p->link.name, ngc.path, strerror(errno));
341fb11a9c2SBrian Somers     goto failed;
342fb11a9c2SBrian Somers   }
343fb11a9c2SBrian Somers   if (NgRecvMsg(cs, reply, sizeof rbuf, NULL) < 0) {
344fb11a9c2SBrian Somers     log_Printf(LogWARN, "%s: Can't obtain async node info at %s: %s\n",
345fb11a9c2SBrian Somers                p->link.name, ngc.path, strerror(errno));
346fb11a9c2SBrian Somers     goto failed;
347fb11a9c2SBrian Somers   }
348fb11a9c2SBrian Somers 
349fb11a9c2SBrian Somers   /* All done, set up our device state */
350fb11a9c2SBrian Somers   snprintf(dev->hook, sizeof dev->hook, "%s", ngc.ourhook);
351fb11a9c2SBrian Somers   dev->cs = cs;
352fb11a9c2SBrian Somers   dev->real.fd = p->fd;
353fb11a9c2SBrian Somers   p->fd = ds;
354fb11a9c2SBrian Somers   dev->real.speed = speed;
355fb11a9c2SBrian Somers   physical_SetSync(p);
356fb11a9c2SBrian Somers 
357fb11a9c2SBrian Somers   tty_SetAsyncParams(p, 0xffffffff, 0xffffffff);
358fb11a9c2SBrian Somers   physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
359fb11a9c2SBrian Somers   log_Printf(LogPHASE, "%s: Loaded netgraph tty line discipline\n",
360fb11a9c2SBrian Somers              p->link.name);
361fb11a9c2SBrian Somers 
362fb11a9c2SBrian Somers   return 1;
363fb11a9c2SBrian Somers 
364fb11a9c2SBrian Somers failed:
365fb11a9c2SBrian Somers   ID0ioctl(p->fd, TIOCSETD, &dev->real.disc);
366fb11a9c2SBrian Somers   close(ds);
367fb11a9c2SBrian Somers   close(cs);
368fb11a9c2SBrian Somers 
369fb11a9c2SBrian Somers   return 0;
370fb11a9c2SBrian Somers }
371fb11a9c2SBrian Somers 
372fb11a9c2SBrian Somers static void
373fb11a9c2SBrian Somers UnloadLineDiscipline(struct physical *p)
374fb11a9c2SBrian Somers {
375fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
376fb11a9c2SBrian Somers 
377fb11a9c2SBrian Somers   if (isngtty(dev)) {
378fb11a9c2SBrian Somers log_Printf(LogPHASE, "back to speed %d\n", dev->real.speed);
379fb11a9c2SBrian Somers     if (!physical_SetSpeed(p, dev->real.speed))
380fb11a9c2SBrian Somers       log_Printf(LogWARN, "Couldn't reset tty speed to %d\n", dev->real.speed);
381fb11a9c2SBrian Somers     dev->real.speed = 0;
382fb11a9c2SBrian Somers     close(p->fd);
383fb11a9c2SBrian Somers     p->fd = dev->real.fd;
384fb11a9c2SBrian Somers     dev->real.fd = -1;
385fb11a9c2SBrian Somers     close(dev->cs);
386fb11a9c2SBrian Somers     dev->cs = -1;
387fb11a9c2SBrian Somers     *dev->hook = '\0';
388fb11a9c2SBrian Somers     if (ID0ioctl(p->fd, TIOCSETD, &dev->real.disc) == 0) {
389fb11a9c2SBrian Somers       physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
390fb11a9c2SBrian Somers       log_Printf(LogPHASE, "%s: Unloaded netgraph tty line discipline\n",
391fb11a9c2SBrian Somers                  p->link.name);
392fb11a9c2SBrian Somers     } else
393fb11a9c2SBrian Somers       log_Printf(LogWARN, "%s: Failed to unload netgraph tty line discipline\n",
394fb11a9c2SBrian Somers                  p->link.name);
395fb11a9c2SBrian Somers   }
396fb11a9c2SBrian Somers }
397fb11a9c2SBrian Somers 
398fb11a9c2SBrian Somers static ssize_t
399fb11a9c2SBrian Somers tty_Write(struct physical *p, const void *v, size_t n)
400fb11a9c2SBrian Somers {
401fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
402fb11a9c2SBrian Somers 
403fb11a9c2SBrian Somers   if (isngtty(dev))
404fb11a9c2SBrian Somers     return NgSendData(p->fd, dev->hook, v, n) == -1 ? -1 : n;
405fb11a9c2SBrian Somers   else
406fb11a9c2SBrian Somers     return write(p->fd, v, n);
407fb11a9c2SBrian Somers }
408fb11a9c2SBrian Somers 
409fb11a9c2SBrian Somers static ssize_t
410fb11a9c2SBrian Somers tty_Read(struct physical *p, void *v, size_t n)
411fb11a9c2SBrian Somers {
412fb11a9c2SBrian Somers   struct ttydevice *dev = device2tty(p->handler);
413fb11a9c2SBrian Somers   char hook[sizeof NG_ASYNC_HOOK_SYNC];
414fb11a9c2SBrian Somers 
415fb11a9c2SBrian Somers   if (isngtty(dev))
416fb11a9c2SBrian Somers     return NgRecvData(p->fd, v, n, hook);
417fb11a9c2SBrian Somers   else
418fb11a9c2SBrian Somers     return read(p->fd, v, n);
419fb11a9c2SBrian Somers }
420fb11a9c2SBrian Somers 
421fb11a9c2SBrian Somers #endif /* NETGRAPH */
422fb11a9c2SBrian Somers 
423eb6e5e05SBrian Somers static int
4245d9e6103SBrian Somers tty_Raw(struct physical *p)
4255d9e6103SBrian Somers {
4266815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4278dbb1e2bSBrian Somers   struct termios ios;
4285d9e6103SBrian Somers   int oldflag;
4295d9e6103SBrian Somers 
430eb6e5e05SBrian Somers   log_Printf(LogDEBUG, "%s: Entering tty_Raw\n", p->link.name);
4315d9e6103SBrian Somers 
4326815097bSBrian Somers   if (p->type != PHYS_DIRECT && p->fd >= 0 && !Online(dev))
4338e7bd08eSBrian Somers     log_Printf(LogDEBUG, "%s: Raw: descriptor = %d, mbits = %x\n",
4346815097bSBrian Somers               p->link.name, p->fd, dev->mbits);
4355d9e6103SBrian Somers 
436eb6e5e05SBrian Somers   if (!physical_IsSync(p)) {
437fb11a9c2SBrian Somers #ifndef NONETGRAPH
438fb11a9c2SBrian Somers     if (!LoadLineDiscipline(p))
439fb11a9c2SBrian Somers #endif
440fb11a9c2SBrian Somers     {
4418dbb1e2bSBrian Somers       tcgetattr(p->fd, &ios);
4428dbb1e2bSBrian Somers       cfmakeraw(&ios);
4435d9e6103SBrian Somers       if (p->cfg.rts_cts)
4448dbb1e2bSBrian Somers         ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
4455d9e6103SBrian Somers       else
4468dbb1e2bSBrian Somers         ios.c_cflag |= CLOCAL;
4475d9e6103SBrian Somers 
448cde8638bSBrian Somers       if (p->type != PHYS_DEDICATED)
4498dbb1e2bSBrian Somers         ios.c_cflag |= HUPCL;
4505d9e6103SBrian Somers 
451fca09861SBrian Somers       if (tcsetattr(p->fd, TCSANOW, &ios) == -1)
452fca09861SBrian Somers         log_Printf(LogWARN, "%s: tcsetattr: Failed configuring device\n",
453fca09861SBrian Somers                    p->link.name);
454eb6e5e05SBrian Somers     }
455fb11a9c2SBrian Somers   }
4565d9e6103SBrian Somers 
4575d9e6103SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
4585d9e6103SBrian Somers   if (oldflag < 0)
4595d9e6103SBrian Somers     return 0;
4605d9e6103SBrian Somers   fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK);
4615d9e6103SBrian Somers 
4625d9e6103SBrian Somers   return 1;
4635d9e6103SBrian Somers }
4645d9e6103SBrian Somers 
4655d9e6103SBrian Somers static void
4665d9e6103SBrian Somers tty_Offline(struct physical *p)
4675d9e6103SBrian Somers {
4686815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4696815097bSBrian Somers 
4705d9e6103SBrian Somers   if (p->fd >= 0) {
4716815097bSBrian Somers     timer_Stop(&dev->Timer);
472eb6e5e05SBrian Somers     dev->mbits &= ~TIOCM_DTR;	/* XXX: Hmm, what's this supposed to do ? */
4736815097bSBrian Somers     if (Online(dev)) {
4745d9e6103SBrian Somers       struct termios tio;
4755d9e6103SBrian Somers 
4765d9e6103SBrian Somers       tcgetattr(p->fd, &tio);
477fca09861SBrian Somers       if (cfsetspeed(&tio, B0) == -1 || tcsetattr(p->fd, TCSANOW, &tio) == -1)
4785d9e6103SBrian Somers         log_Printf(LogWARN, "%s: Unable to set physical to speed 0\n",
4795d9e6103SBrian Somers                    p->link.name);
4805d9e6103SBrian Somers     }
4815d9e6103SBrian Somers   }
4825d9e6103SBrian Somers }
4835d9e6103SBrian Somers 
4845d9e6103SBrian Somers static void
4855d9e6103SBrian Somers tty_Cooked(struct physical *p)
4865d9e6103SBrian Somers {
4876815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
4885d9e6103SBrian Somers   int oldflag;
4895d9e6103SBrian Somers 
490d0b3b745SBrian Somers   tty_Offline(p);	/* In case of emergency close()s */
491d0b3b745SBrian Somers 
4925d9e6103SBrian Somers   tcflush(p->fd, TCIOFLUSH);
493eb6e5e05SBrian Somers 
494fca09861SBrian Somers   if (!physical_IsSync(p) && tcsetattr(p->fd, TCSAFLUSH, &dev->ios) == -1)
495fca09861SBrian Somers     log_Printf(LogWARN, "%s: tcsetattr: Unable to restore device settings\n",
496fca09861SBrian Somers                p->link.name);
497eb6e5e05SBrian Somers 
498fb11a9c2SBrian Somers #ifndef NONETGRAPH
499fb11a9c2SBrian Somers   UnloadLineDiscipline(p);
500fb11a9c2SBrian Somers #endif
501fb11a9c2SBrian Somers 
502eb6e5e05SBrian Somers   if ((oldflag = fcntl(p->fd, F_GETFL, 0)) != -1)
5035d9e6103SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
5045d9e6103SBrian Somers }
5055d9e6103SBrian Somers 
5065d9e6103SBrian Somers static void
5076815097bSBrian Somers tty_StopTimer(struct physical *p)
5085d9e6103SBrian Somers {
5096815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
5106815097bSBrian Somers 
5116815097bSBrian Somers   timer_Stop(&dev->Timer);
5125d9e6103SBrian Somers }
5135d9e6103SBrian Somers 
5145d9e6103SBrian Somers static void
5156815097bSBrian Somers tty_Free(struct physical *p)
5165d9e6103SBrian Somers {
5176815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
5186815097bSBrian Somers 
519d0b3b745SBrian Somers   tty_Offline(p);	/* In case of emergency close()s */
5206815097bSBrian Somers   free(dev);
5215d9e6103SBrian Somers }
5225d9e6103SBrian Somers 
5235d9e6103SBrian Somers static int
5245d9e6103SBrian Somers tty_Speed(struct physical *p)
5255d9e6103SBrian Somers {
5268dbb1e2bSBrian Somers   struct termios ios;
5275d9e6103SBrian Somers 
5288dbb1e2bSBrian Somers   if (tcgetattr(p->fd, &ios) == -1)
5295d9e6103SBrian Somers     return 0;
5305d9e6103SBrian Somers 
5318dbb1e2bSBrian Somers   return SpeedToInt(cfgetispeed(&ios));
5325d9e6103SBrian Somers }
5335d9e6103SBrian Somers 
5345d9e6103SBrian Somers static const char *
5355d9e6103SBrian Somers tty_OpenInfo(struct physical *p)
5365d9e6103SBrian Somers {
5376815097bSBrian Somers   struct ttydevice *dev = device2tty(p->handler);
5385d9e6103SBrian Somers   static char buf[13];
5395d9e6103SBrian Somers 
5406815097bSBrian Somers   if (Online(dev))
5415d9e6103SBrian Somers     strcpy(buf, "with");
5425d9e6103SBrian Somers   else
5435d9e6103SBrian Somers     strcpy(buf, "no");
5445d9e6103SBrian Somers   strcat(buf, " carrier");
545eb6e5e05SBrian Somers 
5465d9e6103SBrian Somers   return buf;
5475d9e6103SBrian Somers }
5485d9e6103SBrian Somers 
5496815097bSBrian Somers static void
550f5a99677SBrian Somers tty_device2iov(struct device *d, struct iovec *iov, int *niov,
5512cb305afSBrian Somers                int maxiov, int *auxfd, int *nauxfd)
5526815097bSBrian Somers {
553f5a99677SBrian Somers   struct ttydevice *dev = device2tty(d);
554f5a99677SBrian Somers   int sz = physical_MaxDeviceSize();
5556815097bSBrian Somers 
556f5a99677SBrian Somers   iov[*niov].iov_base = realloc(d, sz);
557f5a99677SBrian Somers   if (iov[*niov].iov_base == NULL) {
558f5a99677SBrian Somers     log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
559f5a99677SBrian Somers     AbortProgram(EX_OSERR);
560f5a99677SBrian Somers   }
561f5a99677SBrian Somers   iov[*niov].iov_len = sz;
5626815097bSBrian Somers   (*niov)++;
5636815097bSBrian Somers 
564fb11a9c2SBrian Somers #ifndef NONETGRAPH
565fb11a9c2SBrian Somers   if (dev->cs >= 0) {
566fb11a9c2SBrian Somers     *auxfd = dev->cs;
567fb11a9c2SBrian Somers     (*nauxfd)++;
568fb11a9c2SBrian Somers   }
569fb11a9c2SBrian Somers #endif
570fb11a9c2SBrian Somers 
5716815097bSBrian Somers   if (dev->Timer.state != TIMER_STOPPED) {
5726815097bSBrian Somers     timer_Stop(&dev->Timer);
5736815097bSBrian Somers     dev->Timer.state = TIMER_RUNNING;
5746815097bSBrian Somers   }
5756815097bSBrian Somers }
5766815097bSBrian Somers 
5776815097bSBrian Somers static struct device basettydevice = {
5785d9e6103SBrian Somers   TTY_DEVICE,
5795d9e6103SBrian Somers   "tty",
580c8b9fb53SBrian Somers   0,
581fdc29d54SBrian Somers   { CD_VARIABLE, DEF_TTYCDDELAY },
582eb6e5e05SBrian Somers   tty_AwaitCarrier,
58387c3786eSBrian Somers   NULL,
5845d9e6103SBrian Somers   tty_Raw,
5855d9e6103SBrian Somers   tty_Offline,
5865d9e6103SBrian Somers   tty_Cooked,
587fb11a9c2SBrian Somers   tty_SetAsyncParams,
5886815097bSBrian Somers   tty_StopTimer,
5896815097bSBrian Somers   tty_Free,
590fb11a9c2SBrian Somers   tty_Read,
591fb11a9c2SBrian Somers   tty_Write,
5926815097bSBrian Somers   tty_device2iov,
5935d9e6103SBrian Somers   tty_Speed,
5945d9e6103SBrian Somers   tty_OpenInfo
5955d9e6103SBrian Somers };
5966815097bSBrian Somers 
5979950fb2aSBrian Somers struct device *
5989950fb2aSBrian Somers tty_iov2device(int type, struct physical *p, struct iovec *iov, int *niov,
59987c3786eSBrian Somers                int maxiov, int *auxfd, int *nauxfd)
6009950fb2aSBrian Somers {
6019950fb2aSBrian Somers   if (type == TTY_DEVICE) {
602acbd1f00SBrian Somers     struct ttydevice *dev = (struct ttydevice *)iov[(*niov)++].iov_base;
6039950fb2aSBrian Somers 
604f5a99677SBrian Somers     dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
605f5a99677SBrian Somers     if (dev == NULL) {
606f5a99677SBrian Somers       log_Printf(LogALERT, "Failed to allocate memory: %d\n",
607f5a99677SBrian Somers                  (int)(sizeof *dev));
608f5a99677SBrian Somers       AbortProgram(EX_OSERR);
609f5a99677SBrian Somers     }
610f5a99677SBrian Somers 
611fb11a9c2SBrian Somers #ifndef NONETGRAPH
612fb11a9c2SBrian Somers     if (*nauxfd) {
613fb11a9c2SBrian Somers       dev->cs = *auxfd;
614fb11a9c2SBrian Somers       (*nauxfd)--;
615fb11a9c2SBrian Somers     } else
616fb11a9c2SBrian Somers       dev->cs = -1;
617fb11a9c2SBrian Somers #endif
618fb11a9c2SBrian Somers 
6199950fb2aSBrian Somers     /* Refresh function pointers etc */
6209950fb2aSBrian Somers     memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
6219950fb2aSBrian Somers 
622acbd1f00SBrian Somers     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
6239950fb2aSBrian Somers     if (dev->Timer.state != TIMER_STOPPED) {
6249950fb2aSBrian Somers       dev->Timer.state = TIMER_STOPPED;
625f5a99677SBrian Somers       p->handler = &dev->dev;		/* For the benefit of StartTimer */
6269950fb2aSBrian Somers       tty_StartTimer(p);
6279950fb2aSBrian Somers     }
6289950fb2aSBrian Somers     return &dev->dev;
6299950fb2aSBrian Somers   }
6309950fb2aSBrian Somers 
6319950fb2aSBrian Somers   return NULL;
6329950fb2aSBrian Somers }
6339950fb2aSBrian Somers 
6349950fb2aSBrian Somers struct device *
6359950fb2aSBrian Somers tty_Create(struct physical *p)
63627be3ac6SBrian Somers {
63727be3ac6SBrian Somers   struct ttydevice *dev;
63827be3ac6SBrian Somers   struct termios ios;
63927be3ac6SBrian Somers   int oldflag;
64027be3ac6SBrian Somers 
6419950fb2aSBrian Somers   if (p->fd < 0 || !isatty(p->fd))
6429950fb2aSBrian Somers     /* Don't want this */
64327be3ac6SBrian Somers     return NULL;
64427be3ac6SBrian Somers 
6459950fb2aSBrian Somers   if (*p->name.full == '\0') {
6469950fb2aSBrian Somers     physical_SetDevice(p, ttyname(p->fd));
6479950fb2aSBrian Somers     log_Printf(LogDEBUG, "%s: Input is a tty (%s)\n",
6489950fb2aSBrian Somers                p->link.name, p->name.full);
6499950fb2aSBrian Somers   } else
6509950fb2aSBrian Somers     log_Printf(LogDEBUG, "%s: Opened %s\n", p->link.name, p->name.full);
6519950fb2aSBrian Somers 
6529950fb2aSBrian Somers   /* We're gonna return a ttydevice (unless something goes horribly wrong) */
6539950fb2aSBrian Somers 
6549950fb2aSBrian Somers   if ((dev = malloc(sizeof *dev)) == NULL) {
6559950fb2aSBrian Somers     /* Complete failure - parent doesn't continue trying to ``create'' */
6569950fb2aSBrian Somers     close(p->fd);
6579950fb2aSBrian Somers     p->fd = -1;
6589950fb2aSBrian Somers     return NULL;
6599950fb2aSBrian Somers   }
6609950fb2aSBrian Somers 
66127be3ac6SBrian Somers   memcpy(&dev->dev, &basettydevice, sizeof dev->dev);
6624b698945SBrian Somers   memset(&dev->Timer, '\0', sizeof dev->Timer);
663eb6e5e05SBrian Somers   dev->mbits = -1;
664fb11a9c2SBrian Somers #ifndef NONETGRAPH
665fb11a9c2SBrian Somers   dev->real.speed = 0;
666fb11a9c2SBrian Somers   dev->real.fd = -1;
667fb11a9c2SBrian Somers   dev->real.disc = -1;
668fb11a9c2SBrian Somers   *dev->hook = '\0';
669fb11a9c2SBrian Somers #endif
67027be3ac6SBrian Somers   tcgetattr(p->fd, &ios);
67127be3ac6SBrian Somers   dev->ios = ios;
67227be3ac6SBrian Somers 
673fdc29d54SBrian Somers   if (p->cfg.cd.necessity != CD_DEFAULT)
674fdc29d54SBrian Somers     /* Any override is ok for the tty device */
675fdc29d54SBrian Somers     dev->dev.cd = p->cfg.cd;
676fdc29d54SBrian Somers 
6779950fb2aSBrian Somers   log_Printf(LogDEBUG, "%s: tty_Create: physical (get): fd = %d,"
67827be3ac6SBrian Somers              " iflag = %lx, oflag = %lx, cflag = %lx\n", p->link.name, p->fd,
67927be3ac6SBrian Somers              (u_long)ios.c_iflag, (u_long)ios.c_oflag, (u_long)ios.c_cflag);
68027be3ac6SBrian Somers 
68127be3ac6SBrian Somers   cfmakeraw(&ios);
68227be3ac6SBrian Somers   if (p->cfg.rts_cts)
68327be3ac6SBrian Somers     ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW;
68427be3ac6SBrian Somers   else {
68527be3ac6SBrian Somers     ios.c_cflag |= CLOCAL;
68627be3ac6SBrian Somers     ios.c_iflag |= IXOFF;
68727be3ac6SBrian Somers   }
68827be3ac6SBrian Somers   ios.c_iflag |= IXON;
689cde8638bSBrian Somers   if (p->type != PHYS_DEDICATED)
69027be3ac6SBrian Somers     ios.c_cflag |= HUPCL;
69127be3ac6SBrian Somers 
69227be3ac6SBrian Somers   if (p->type != PHYS_DIRECT) {
69327be3ac6SBrian Somers       /* Change tty speed when we're not in -direct mode */
69427be3ac6SBrian Somers       ios.c_cflag &= ~(CSIZE | PARODD | PARENB);
69527be3ac6SBrian Somers       ios.c_cflag |= p->cfg.parity;
69627be3ac6SBrian Somers       if (cfsetspeed(&ios, IntToSpeed(p->cfg.speed)) == -1)
69727be3ac6SBrian Somers 	log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n",
69827be3ac6SBrian Somers 		  p->link.name, p->name.full, p->cfg.speed);
69927be3ac6SBrian Somers   }
700fca09861SBrian Somers 
701fca09861SBrian Somers   if (tcsetattr(p->fd, TCSADRAIN, &ios) == -1) {
702fca09861SBrian Somers     log_Printf(LogWARN, "%s: tcsetattr: Failed configuring device\n",
703fca09861SBrian Somers                p->link.name);
704fca09861SBrian Somers     if (p->type != PHYS_DIRECT && p->cfg.speed > 115200)
705fca09861SBrian Somers       log_Printf(LogWARN, "%.*s             Perhaps the speed is unsupported\n",
706fca09861SBrian Somers                  (int)strlen(p->link.name), "");
707fca09861SBrian Somers   }
708fca09861SBrian Somers 
70927be3ac6SBrian Somers   log_Printf(LogDEBUG, "%s: physical (put): iflag = %lx, oflag = %lx, "
71027be3ac6SBrian Somers             "cflag = %lx\n", p->link.name, (u_long)ios.c_iflag,
71127be3ac6SBrian Somers             (u_long)ios.c_oflag, (u_long)ios.c_cflag);
71227be3ac6SBrian Somers 
71327be3ac6SBrian Somers   oldflag = fcntl(p->fd, F_GETFL, 0);
71427be3ac6SBrian Somers   if (oldflag < 0) {
7159950fb2aSBrian Somers     /* Complete failure - parent doesn't continue trying to ``create'' */
7169950fb2aSBrian Somers 
71727be3ac6SBrian Somers     log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n",
71827be3ac6SBrian Somers                p->link.name, strerror(errno));
7199950fb2aSBrian Somers     tty_Cooked(p);
7209950fb2aSBrian Somers     close(p->fd);
7219950fb2aSBrian Somers     p->fd = -1;
722eb6e5e05SBrian Somers     free(dev);
72327be3ac6SBrian Somers     return NULL;
72427be3ac6SBrian Somers   } else
72527be3ac6SBrian Somers     fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK);
72627be3ac6SBrian Somers 
727acbd1f00SBrian Somers   physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
72827be3ac6SBrian Somers 
72927be3ac6SBrian Somers   return &dev->dev;
73027be3ac6SBrian Somers }
731