146686Sbrian/*- 246686Sbrian * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 346686Sbrian * All rights reserved. 446686Sbrian * 546686Sbrian * Redistribution and use in source and binary forms, with or without 646686Sbrian * modification, are permitted provided that the following conditions 746686Sbrian * are met: 846686Sbrian * 1. Redistributions of source code must retain the above copyright 946686Sbrian * notice, this list of conditions and the following disclaimer. 1046686Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1146686Sbrian * notice, this list of conditions and the following disclaimer in the 1246686Sbrian * documentation and/or other materials provided with the distribution. 1346686Sbrian * 1446686Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1546686Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1646686Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1746686Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1846686Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1946686Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2046686Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2146686Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2246686Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2346686Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2446686Sbrian * SUCH DAMAGE. 2546686Sbrian * 2650479Speter * $FreeBSD$ 2746686Sbrian */ 2846686Sbrian 2946686Sbrian#include <sys/param.h> 3046686Sbrian#include <sys/un.h> 3146686Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__) 3246686Sbrian#include <sys/ioctl.h> 3346686Sbrian#endif 3446686Sbrian 3546686Sbrian#include <errno.h> 3646686Sbrian#include <fcntl.h> 3793418Sbrian#include <stdio.h> 3846686Sbrian#include <stdlib.h> 3946686Sbrian#include <string.h> 4047769Sbrian#include <sysexits.h> 4147061Sbrian#include <sys/uio.h> 4246686Sbrian#include <termios.h> 4396582Sbrian#include <ttyent.h> 4446686Sbrian#include <unistd.h> 4593464Sbrian#ifndef NONETGRAPH 4693418Sbrian#include <netgraph.h> 4793418Sbrian#include <netgraph/ng_async.h> 4893418Sbrian#include <netgraph/ng_message.h> 4993418Sbrian#include <netgraph/ng_ppp.h> 5093418Sbrian#include <netgraph/ng_tty.h> 5193464Sbrian#endif 5246686Sbrian 5346686Sbrian#include "layer.h" 5446686Sbrian#include "defs.h" 5546686Sbrian#include "mbuf.h" 5646686Sbrian#include "log.h" 5746686Sbrian#include "timer.h" 5846686Sbrian#include "lqr.h" 5946686Sbrian#include "hdlc.h" 6046686Sbrian#include "throughput.h" 6146686Sbrian#include "fsm.h" 6246686Sbrian#include "lcp.h" 6346686Sbrian#include "ccp.h" 6446686Sbrian#include "link.h" 6546686Sbrian#include "async.h" 6646686Sbrian#include "descriptor.h" 6746686Sbrian#include "physical.h" 6846686Sbrian#include "mp.h" 6946686Sbrian#include "chat.h" 7046686Sbrian#include "auth.h" 7146686Sbrian#include "chap.h" 7246686Sbrian#include "cbcp.h" 7346686Sbrian#include "datalink.h" 7447769Sbrian#include "main.h" 7593418Sbrian#include "id.h" 7646686Sbrian#include "tty.h" 7746686Sbrian 7852265Sbrian#if defined(__mac68k__) || defined(__macppc__) 7952265Sbrian#undef CRTS_IFLOW 8052265Sbrian#undef CCTS_OFLOW 8152265Sbrian#define CRTS_IFLOW CDTRCTS 8252265Sbrian#define CCTS_OFLOW CDTRCTS 8352265Sbrian#endif 8452265Sbrian 8547061Sbrian#define Online(dev) ((dev)->mbits & TIOCM_CD) 8646686Sbrian 8747061Sbrianstruct ttydevice { 8847061Sbrian struct device dev; /* What struct physical knows about */ 8947061Sbrian struct pppTimer Timer; /* CD checks */ 9047061Sbrian int mbits; /* Current DCD status */ 9149472Sbrian int carrier_seconds; /* seconds before CD is *required* */ 9293418Sbrian#ifndef NONETGRAPH 9393418Sbrian struct { 94134789Sbrian unsigned speed; /* Pre-line-discipline speed */ 9593418Sbrian int fd; /* Pre-line-discipline fd */ 9693418Sbrian int disc; /* Old line-discipline */ 9793418Sbrian } real; 9893418Sbrian char hook[sizeof NG_ASYNC_HOOK_SYNC]; /* our ng_socket hook */ 9993418Sbrian int cs; /* A netgraph control socket (maybe) */ 10093418Sbrian#endif 10147061Sbrian struct termios ios; /* To be able to reset from raw mode */ 10247061Sbrian}; 10347061Sbrian 10447061Sbrian#define device2tty(d) ((d)->type == TTY_DEVICE ? (struct ttydevice *)d : NULL) 10547061Sbrian 106134789Sbrianunsigned 10747769Sbriantty_DeviceSize(void) 10847769Sbrian{ 10947769Sbrian return sizeof(struct ttydevice); 11047769Sbrian} 11147769Sbrian 11246686Sbrian/* 11346686Sbrian * tty_Timeout() watches the DCD signal and mentions it if it's status 11446686Sbrian * changes. 11546686Sbrian */ 11646686Sbrianstatic void 11746686Sbriantty_Timeout(void *data) 11846686Sbrian{ 11946686Sbrian struct physical *p = data; 12047061Sbrian struct ttydevice *dev = device2tty(p->handler); 12146686Sbrian int ombits, change; 12246686Sbrian 12347061Sbrian timer_Stop(&dev->Timer); 12447061Sbrian dev->Timer.load = SECTICKS; /* Once a second please */ 12547061Sbrian timer_Start(&dev->Timer); 12647061Sbrian ombits = dev->mbits; 12746686Sbrian 12846686Sbrian if (p->fd >= 0) { 12947061Sbrian if (ioctl(p->fd, TIOCMGET, &dev->mbits) < 0) { 13049472Sbrian /* we must be a pty ? */ 13153733Sbrian if (p->cfg.cd.necessity != CD_DEFAULT) 13253733Sbrian log_Printf(LogWARN, "%s: Carrier ioctl not supported, " 13353733Sbrian "using ``set cd off''\n", p->link.name); 13447061Sbrian timer_Stop(&dev->Timer); 13554569Sbrian dev->mbits = TIOCM_CD; 13646686Sbrian return; 13746686Sbrian } 13846686Sbrian } else 13947061Sbrian dev->mbits = 0; 14046686Sbrian 14146686Sbrian if (ombits == -1) { 14246686Sbrian /* First time looking for carrier */ 14347061Sbrian if (Online(dev)) 14449472Sbrian log_Printf(LogPHASE, "%s: %s: CD detected\n", p->link.name, p->name.full); 14553733Sbrian else if (++dev->carrier_seconds >= dev->dev.cd.delay) { 14653733Sbrian if (dev->dev.cd.necessity == CD_REQUIRED) 14749472Sbrian log_Printf(LogPHASE, "%s: %s: Required CD not detected\n", 14849472Sbrian p->link.name, p->name.full); 14949472Sbrian else { 15049472Sbrian log_Printf(LogPHASE, "%s: %s doesn't support CD\n", 15149472Sbrian p->link.name, p->name.full); 15249472Sbrian dev->mbits = TIOCM_CD; /* Dodgy null-modem cable ? */ 15349472Sbrian } 15449472Sbrian timer_Stop(&dev->Timer); 15549472Sbrian /* tty_AwaitCarrier() will notice */ 15646686Sbrian } else { 15749472Sbrian /* Keep waiting */ 15849472Sbrian log_Printf(LogDEBUG, "%s: %s: Still no carrier (%d/%d)\n", 15949472Sbrian p->link.name, p->name.full, dev->carrier_seconds, 16053733Sbrian dev->dev.cd.delay); 16149472Sbrian dev->mbits = -1; 16246686Sbrian } 16346686Sbrian } else { 16447061Sbrian change = ombits ^ dev->mbits; 16546686Sbrian if (change & TIOCM_CD) { 16647061Sbrian if (dev->mbits & TIOCM_CD) 16746686Sbrian log_Printf(LogDEBUG, "%s: offline -> online\n", p->link.name); 16846686Sbrian else { 16946686Sbrian log_Printf(LogDEBUG, "%s: online -> offline\n", p->link.name); 17046686Sbrian log_Printf(LogPHASE, "%s: Carrier lost\n", p->link.name); 17146686Sbrian datalink_Down(p->dl, CLOSE_NORMAL); 17247061Sbrian timer_Stop(&dev->Timer); 17346686Sbrian } 17446686Sbrian } else 17546686Sbrian log_Printf(LogDEBUG, "%s: Still %sline\n", p->link.name, 17647061Sbrian Online(dev) ? "on" : "off"); 17746686Sbrian } 17846686Sbrian} 17946686Sbrian 18046686Sbrianstatic void 18146686Sbriantty_StartTimer(struct physical *p) 18246686Sbrian{ 18347061Sbrian struct ttydevice *dev = device2tty(p->handler); 18447061Sbrian 18547061Sbrian timer_Stop(&dev->Timer); 18649472Sbrian dev->Timer.load = SECTICKS; 18747061Sbrian dev->Timer.func = tty_Timeout; 18847061Sbrian dev->Timer.name = "tty CD"; 18947061Sbrian dev->Timer.arg = p; 19046686Sbrian log_Printf(LogDEBUG, "%s: Using tty_Timeout [%p]\n", 19146686Sbrian p->link.name, tty_Timeout); 19247061Sbrian timer_Start(&dev->Timer); 19346686Sbrian} 19446686Sbrian 19546686Sbrianstatic int 19649472Sbriantty_AwaitCarrier(struct physical *p) 19749472Sbrian{ 19849472Sbrian struct ttydevice *dev = device2tty(p->handler); 19949472Sbrian 20053733Sbrian if (dev->dev.cd.necessity == CD_NOTREQUIRED || physical_IsSync(p)) 20149472Sbrian return CARRIER_OK; 20249472Sbrian 20349472Sbrian if (dev->mbits == -1) { 20449472Sbrian if (dev->Timer.state == TIMER_STOPPED) { 20549472Sbrian dev->carrier_seconds = 0; 20649472Sbrian tty_StartTimer(p); 20749472Sbrian } 20849472Sbrian return CARRIER_PENDING; /* Not yet ! */ 20949472Sbrian } 21049472Sbrian 21154569Sbrian return Online(dev) ? CARRIER_OK : CARRIER_LOST; 21249472Sbrian} 21349472Sbrian 21493418Sbrian#ifdef NONETGRAPH 21593418Sbrian#define tty_SetAsyncParams NULL 21693418Sbrian#define tty_Write NULL 21793418Sbrian#define tty_Read NULL 21893418Sbrian#else 21993418Sbrian 22049472Sbrianstatic int 22193418Sbrianisngtty(struct ttydevice *dev) 22293418Sbrian{ 22393418Sbrian return dev->real.fd != -1; 22493418Sbrian} 22593418Sbrian 22693418Sbrianstatic void 22793418Sbriantty_SetAsyncParams(struct physical *p, u_int32_t mymap, u_int32_t hismap) 22893418Sbrian{ 22993418Sbrian struct ttydevice *dev = device2tty(p->handler); 230122758Sharti char asyncpath[NG_PATHSIZ]; 23193418Sbrian struct ng_async_cfg cfg; 23293418Sbrian 23393418Sbrian if (isngtty(dev)) { 23493418Sbrian /* Configure the async converter node */ 23593418Sbrian 23693418Sbrian snprintf(asyncpath, sizeof asyncpath, ".:%s", dev->hook); 23793418Sbrian memset(&cfg, 0, sizeof cfg); 23893418Sbrian cfg.enabled = 1; 23993418Sbrian cfg.accm = mymap | hismap; 24093418Sbrian cfg.amru = MAX_MTU; 24193418Sbrian cfg.smru = MAX_MRU; 24293418Sbrian log_Printf(LogDEBUG, "Configure async node at %s\n", asyncpath); 24393418Sbrian if (NgSendMsg(dev->cs, asyncpath, NGM_ASYNC_COOKIE, 24493418Sbrian NGM_ASYNC_CMD_SET_CONFIG, &cfg, sizeof cfg) < 0) 24593418Sbrian log_Printf(LogWARN, "%s: Can't configure async node at %s\n", 24693418Sbrian p->link.name, asyncpath); 24793418Sbrian } else 24893418Sbrian /* No netgraph node, just config the async layer */ 24993418Sbrian async_SetLinkParams(&p->async, mymap, hismap); 25093418Sbrian} 25193418Sbrian 25293418Sbrianstatic int 25393418SbrianLoadLineDiscipline(struct physical *p) 25493418Sbrian{ 25593418Sbrian struct ttydevice *dev = device2tty(p->handler); 25693418Sbrian u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)]; 25793418Sbrian struct ng_mesg *reply; 25893418Sbrian struct nodeinfo *info; 259122758Sharti char ttypath[NG_NODESIZ]; 26093418Sbrian struct ngm_mkpeer ngm; 26193418Sbrian struct ngm_connect ngc; 262134789Sbrian int ldisc, cs, ds, hot; 263134789Sbrian unsigned speed; 26493418Sbrian 26595171Sbrian /* 26695171Sbrian * Don't use the netgraph line discipline for now. Using it works, but 26795171Sbrian * carrier cannot be detected via TIOCMGET and the device doesn't become 26895171Sbrian * selectable with 0 bytes to read when carrier is lost :( 26995171Sbrian */ 27095171Sbrian return 0; 27195171Sbrian 27293418Sbrian reply = (struct ng_mesg *)rbuf; 27393418Sbrian info = (struct nodeinfo *)reply->data; 27493418Sbrian 27593418Sbrian loadmodules(LOAD_VERBOSLY, "netgraph", "ng_tty", "ng_async", "ng_socket", 27693418Sbrian NULL); 27793418Sbrian 27893418Sbrian /* Get the speed before loading the line discipline */ 27993418Sbrian speed = physical_GetSpeed(p); 28093418Sbrian 28193418Sbrian if (ioctl(p->fd, TIOCGETD, &dev->real.disc) < 0) { 28293418Sbrian log_Printf(LogDEBUG, "%s: Couldn't get tty line discipline\n", 28393418Sbrian p->link.name); 28493418Sbrian return 0; 28593418Sbrian } 28693418Sbrian ldisc = NETGRAPHDISC; 28793418Sbrian if (ID0ioctl(p->fd, TIOCSETD, &ldisc) < 0) { 28893418Sbrian log_Printf(LogDEBUG, "%s: Couldn't set NETGRAPHDISC line discipline\n", 28993418Sbrian p->link.name); 29093418Sbrian return 0; 29193418Sbrian } 29293418Sbrian 29393418Sbrian /* Get the name of the tty node */ 29493418Sbrian if (ioctl(p->fd, NGIOCGINFO, info) < 0) { 29593418Sbrian log_Printf(LogWARN, "%s: ioctl(NGIOCGINFO): %s\n", p->link.name, 29693418Sbrian strerror(errno)); 29793418Sbrian ID0ioctl(p->fd, TIOCSETD, &dev->real.disc); 29893418Sbrian return 0; 29993418Sbrian } 30093418Sbrian snprintf(ttypath, sizeof ttypath, "%s:", info->name); 30193418Sbrian 30293418Sbrian /* Create a socket node for our endpoint (and to send messages via) */ 30393418Sbrian if (ID0NgMkSockNode(NULL, &cs, &ds) == -1) { 30493418Sbrian log_Printf(LogWARN, "%s: NgMkSockNode: %s\n", p->link.name, 30593418Sbrian strerror(errno)); 30693418Sbrian ID0ioctl(p->fd, TIOCSETD, &dev->real.disc); 30793418Sbrian return 0; 30893418Sbrian } 30993418Sbrian 31093418Sbrian /* Set the ``hot char'' on the TTY node */ 31193418Sbrian hot = HDLC_SYN; 31293418Sbrian log_Printf(LogDEBUG, "%s: Set tty hotchar to 0x%02x\n", p->link.name, hot); 31393418Sbrian if (NgSendMsg(cs, ttypath, NGM_TTY_COOKIE, 31493418Sbrian NGM_TTY_SET_HOTCHAR, &hot, sizeof hot) < 0) { 31593418Sbrian log_Printf(LogWARN, "%s: Can't set hot char\n", p->link.name); 31693418Sbrian goto failed; 31793418Sbrian } 31893418Sbrian 31993418Sbrian /* Attach an async converter node */ 32093418Sbrian snprintf(ngm.type, sizeof ngm.type, "%s", NG_ASYNC_NODE_TYPE); 32193418Sbrian snprintf(ngm.ourhook, sizeof ngm.ourhook, "%s", NG_TTY_HOOK); 32293418Sbrian snprintf(ngm.peerhook, sizeof ngm.peerhook, "%s", NG_ASYNC_HOOK_ASYNC); 32393418Sbrian log_Printf(LogDEBUG, "%s: Send mkpeer async:%s to %s:%s\n", p->link.name, 32493418Sbrian ngm.peerhook, ttypath, ngm.ourhook); 32593418Sbrian if (NgSendMsg(cs, ttypath, NGM_GENERIC_COOKIE, 32693418Sbrian NGM_MKPEER, &ngm, sizeof ngm) < 0) { 32793418Sbrian log_Printf(LogWARN, "%s: Can't create %s node\n", p->link.name, 32893418Sbrian NG_ASYNC_NODE_TYPE); 32993418Sbrian goto failed; 33093418Sbrian } 33193418Sbrian 33293418Sbrian /* Connect the async node to our socket */ 33393418Sbrian snprintf(ngc.path, sizeof ngc.path, "%s%s", ttypath, NG_TTY_HOOK); 33493418Sbrian snprintf(ngc.peerhook, sizeof ngc.peerhook, "%s", NG_ASYNC_HOOK_SYNC); 33593418Sbrian memcpy(ngc.ourhook, ngc.peerhook, sizeof ngc.ourhook); 33693418Sbrian log_Printf(LogDEBUG, "%s: Send connect %s:%s to .:%s\n", p->link.name, 33793418Sbrian ngc.path, ngc.peerhook, ngc.ourhook); 33893418Sbrian if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, 33993418Sbrian &ngc, sizeof ngc) < 0) { 34093418Sbrian log_Printf(LogWARN, "%s: Can't connect .:%s -> %s.%s: %s\n", 34193418Sbrian p->link.name, ngc.ourhook, ngc.path, ngc.peerhook, 34293418Sbrian strerror(errno)); 34393418Sbrian goto failed; 34493418Sbrian } 34593418Sbrian 34693418Sbrian /* Get the async node id */ 34793418Sbrian if (NgSendMsg(cs, ngc.path, NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0) { 34893418Sbrian log_Printf(LogWARN, "%s: Can't request async node info at %s: %s\n", 34993418Sbrian p->link.name, ngc.path, strerror(errno)); 35093418Sbrian goto failed; 35193418Sbrian } 35293418Sbrian if (NgRecvMsg(cs, reply, sizeof rbuf, NULL) < 0) { 35393418Sbrian log_Printf(LogWARN, "%s: Can't obtain async node info at %s: %s\n", 35493418Sbrian p->link.name, ngc.path, strerror(errno)); 35593418Sbrian goto failed; 35693418Sbrian } 35793418Sbrian 35893418Sbrian /* All done, set up our device state */ 35993418Sbrian snprintf(dev->hook, sizeof dev->hook, "%s", ngc.ourhook); 36093418Sbrian dev->cs = cs; 36193418Sbrian dev->real.fd = p->fd; 36293418Sbrian p->fd = ds; 36393418Sbrian dev->real.speed = speed; 36493418Sbrian physical_SetSync(p); 36593418Sbrian 36693418Sbrian tty_SetAsyncParams(p, 0xffffffff, 0xffffffff); 36793418Sbrian physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE); 36893418Sbrian log_Printf(LogPHASE, "%s: Loaded netgraph tty line discipline\n", 36993418Sbrian p->link.name); 37093418Sbrian 37193418Sbrian return 1; 37293418Sbrian 37393418Sbrianfailed: 37493418Sbrian ID0ioctl(p->fd, TIOCSETD, &dev->real.disc); 37593418Sbrian close(ds); 37693418Sbrian close(cs); 37793418Sbrian 37893418Sbrian return 0; 37993418Sbrian} 38093418Sbrian 38193418Sbrianstatic void 38293418SbrianUnloadLineDiscipline(struct physical *p) 38393418Sbrian{ 38493418Sbrian struct ttydevice *dev = device2tty(p->handler); 38593418Sbrian 38693418Sbrian if (isngtty(dev)) { 38793418Sbrian if (!physical_SetSpeed(p, dev->real.speed)) 38893418Sbrian log_Printf(LogWARN, "Couldn't reset tty speed to %d\n", dev->real.speed); 38993418Sbrian dev->real.speed = 0; 39093418Sbrian close(p->fd); 39193418Sbrian p->fd = dev->real.fd; 39293418Sbrian dev->real.fd = -1; 39393418Sbrian close(dev->cs); 39493418Sbrian dev->cs = -1; 39593418Sbrian *dev->hook = '\0'; 39693418Sbrian if (ID0ioctl(p->fd, TIOCSETD, &dev->real.disc) == 0) { 39793418Sbrian physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE); 39893418Sbrian log_Printf(LogPHASE, "%s: Unloaded netgraph tty line discipline\n", 39993418Sbrian p->link.name); 40093418Sbrian } else 40193418Sbrian log_Printf(LogWARN, "%s: Failed to unload netgraph tty line discipline\n", 40293418Sbrian p->link.name); 40393418Sbrian } 40493418Sbrian} 40593418Sbrian 40693418Sbrianstatic ssize_t 40793418Sbriantty_Write(struct physical *p, const void *v, size_t n) 40893418Sbrian{ 40993418Sbrian struct ttydevice *dev = device2tty(p->handler); 41093418Sbrian 41193418Sbrian if (isngtty(dev)) 412134789Sbrian return NgSendData(p->fd, dev->hook, v, n) == -1 ? -1 : (ssize_t)n; 41393418Sbrian else 41493418Sbrian return write(p->fd, v, n); 41593418Sbrian} 41693418Sbrian 41793418Sbrianstatic ssize_t 41893418Sbriantty_Read(struct physical *p, void *v, size_t n) 41993418Sbrian{ 42093418Sbrian struct ttydevice *dev = device2tty(p->handler); 42193418Sbrian char hook[sizeof NG_ASYNC_HOOK_SYNC]; 42293418Sbrian 42393418Sbrian if (isngtty(dev)) 42493418Sbrian return NgRecvData(p->fd, v, n, hook); 42593418Sbrian else 42693418Sbrian return read(p->fd, v, n); 42793418Sbrian} 42893418Sbrian 42993418Sbrian#endif /* NETGRAPH */ 43093418Sbrian 43193418Sbrianstatic int 43246686Sbriantty_Raw(struct physical *p) 43346686Sbrian{ 43447061Sbrian struct ttydevice *dev = device2tty(p->handler); 43547120Sbrian struct termios ios; 43646686Sbrian int oldflag; 43746686Sbrian 43849472Sbrian log_Printf(LogDEBUG, "%s: Entering tty_Raw\n", p->link.name); 43946686Sbrian 44047061Sbrian if (p->type != PHYS_DIRECT && p->fd >= 0 && !Online(dev)) 44158038Sbrian log_Printf(LogDEBUG, "%s: Raw: descriptor = %d, mbits = %x\n", 44247061Sbrian p->link.name, p->fd, dev->mbits); 44346686Sbrian 44449472Sbrian if (!physical_IsSync(p)) { 44593418Sbrian#ifndef NONETGRAPH 44693418Sbrian if (!LoadLineDiscipline(p)) 44793418Sbrian#endif 44893418Sbrian { 44993418Sbrian tcgetattr(p->fd, &ios); 45093418Sbrian cfmakeraw(&ios); 45193418Sbrian if (p->cfg.rts_cts) 45293418Sbrian ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW; 45393418Sbrian else 45493418Sbrian ios.c_cflag |= CLOCAL; 45546686Sbrian 45693418Sbrian if (p->type != PHYS_DEDICATED) 45793418Sbrian ios.c_cflag |= HUPCL; 45846686Sbrian 45993418Sbrian if (tcsetattr(p->fd, TCSANOW, &ios) == -1) 46093418Sbrian log_Printf(LogWARN, "%s: tcsetattr: Failed configuring device\n", 46193418Sbrian p->link.name); 46293418Sbrian } 46349472Sbrian } 46446686Sbrian 46546686Sbrian oldflag = fcntl(p->fd, F_GETFL, 0); 46646686Sbrian if (oldflag < 0) 46746686Sbrian return 0; 46846686Sbrian fcntl(p->fd, F_SETFL, oldflag | O_NONBLOCK); 46946686Sbrian 47046686Sbrian return 1; 47146686Sbrian} 47246686Sbrian 47346686Sbrianstatic void 47446686Sbriantty_Offline(struct physical *p) 47546686Sbrian{ 47647061Sbrian struct ttydevice *dev = device2tty(p->handler); 47747061Sbrian 47846686Sbrian if (p->fd >= 0) { 47947061Sbrian timer_Stop(&dev->Timer); 48049472Sbrian dev->mbits &= ~TIOCM_DTR; /* XXX: Hmm, what's this supposed to do ? */ 48147061Sbrian if (Online(dev)) { 48246686Sbrian struct termios tio; 48346686Sbrian 48446686Sbrian tcgetattr(p->fd, &tio); 48568127Sbrian if (cfsetspeed(&tio, B0) == -1 || tcsetattr(p->fd, TCSANOW, &tio) == -1) 48646686Sbrian log_Printf(LogWARN, "%s: Unable to set physical to speed 0\n", 48746686Sbrian p->link.name); 48846686Sbrian } 48946686Sbrian } 49046686Sbrian} 49146686Sbrian 49246686Sbrianstatic void 49346686Sbriantty_Cooked(struct physical *p) 49446686Sbrian{ 49547061Sbrian struct ttydevice *dev = device2tty(p->handler); 49646686Sbrian int oldflag; 49746686Sbrian 49847539Sbrian tty_Offline(p); /* In case of emergency close()s */ 49947539Sbrian 50046686Sbrian tcflush(p->fd, TCIOFLUSH); 50149472Sbrian 50268127Sbrian if (!physical_IsSync(p) && tcsetattr(p->fd, TCSAFLUSH, &dev->ios) == -1) 50368127Sbrian log_Printf(LogWARN, "%s: tcsetattr: Unable to restore device settings\n", 50468127Sbrian p->link.name); 50549472Sbrian 50693418Sbrian#ifndef NONETGRAPH 50793418Sbrian UnloadLineDiscipline(p); 50893418Sbrian#endif 50993418Sbrian 51049472Sbrian if ((oldflag = fcntl(p->fd, F_GETFL, 0)) != -1) 51149472Sbrian fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK); 51246686Sbrian} 51346686Sbrian 51446686Sbrianstatic void 51547061Sbriantty_StopTimer(struct physical *p) 51646686Sbrian{ 51747061Sbrian struct ttydevice *dev = device2tty(p->handler); 51847061Sbrian 51947061Sbrian timer_Stop(&dev->Timer); 52046686Sbrian} 52146686Sbrian 52246686Sbrianstatic void 52347061Sbriantty_Free(struct physical *p) 52446686Sbrian{ 52547061Sbrian struct ttydevice *dev = device2tty(p->handler); 52647061Sbrian 52747539Sbrian tty_Offline(p); /* In case of emergency close()s */ 52847061Sbrian free(dev); 52946686Sbrian} 53046686Sbrian 531134789Sbrianstatic unsigned 53246686Sbriantty_Speed(struct physical *p) 53346686Sbrian{ 53447120Sbrian struct termios ios; 53546686Sbrian 53647120Sbrian if (tcgetattr(p->fd, &ios) == -1) 53746686Sbrian return 0; 53846686Sbrian 539134789Sbrian return SpeedToUnsigned(cfgetispeed(&ios)); 54046686Sbrian} 54146686Sbrian 54246686Sbrianstatic const char * 54346686Sbriantty_OpenInfo(struct physical *p) 54446686Sbrian{ 54547061Sbrian struct ttydevice *dev = device2tty(p->handler); 54646686Sbrian static char buf[13]; 54746686Sbrian 54847061Sbrian if (Online(dev)) 54946686Sbrian strcpy(buf, "with"); 55046686Sbrian else 55146686Sbrian strcpy(buf, "no"); 55246686Sbrian strcat(buf, " carrier"); 55349472Sbrian 55446686Sbrian return buf; 55546686Sbrian} 55646686Sbrian 55796582Sbrianstatic int 55896582Sbriantty_Slot(struct physical *p) 55996582Sbrian{ 56096582Sbrian struct ttyent *ttyp; 56196582Sbrian int slot; 56296582Sbrian 56396582Sbrian setttyent(); 56496582Sbrian for (slot = 1; (ttyp = getttyent()); ++slot) 56596582Sbrian if (!strcmp(ttyp->ty_name, p->name.base)) { 56696582Sbrian endttyent(); 56796582Sbrian return slot; 56896582Sbrian } 56996582Sbrian 57096582Sbrian endttyent(); 57196582Sbrian return -1; 57296582Sbrian} 57396582Sbrian 57447061Sbrianstatic void 57547769Sbriantty_device2iov(struct device *d, struct iovec *iov, int *niov, 576135166Sru int maxiov __unused, 577135166Sru#ifndef NONETGRAPH 578135166Sru int *auxfd, int *nauxfd 579135166Sru#else 580135166Sru int *auxfd __unused, int *nauxfd __unused 581135166Sru#endif 582135166Sru ) 58347061Sbrian{ 584196513Sbrian struct ttydevice *dev; 58547769Sbrian int sz = physical_MaxDeviceSize(); 58647061Sbrian 587196513Sbrian iov[*niov].iov_base = d = realloc(d, sz); 588196513Sbrian if (d == NULL) { 58947769Sbrian log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz); 59047769Sbrian AbortProgram(EX_OSERR); 59147769Sbrian } 59247769Sbrian iov[*niov].iov_len = sz; 59347061Sbrian (*niov)++; 59447061Sbrian 595196513Sbrian dev = device2tty(d); 596196513Sbrian 59793418Sbrian#ifndef NONETGRAPH 59893418Sbrian if (dev->cs >= 0) { 59993418Sbrian *auxfd = dev->cs; 60093418Sbrian (*nauxfd)++; 60193418Sbrian } 60293418Sbrian#endif 60393418Sbrian 60447061Sbrian if (dev->Timer.state != TIMER_STOPPED) { 60547061Sbrian timer_Stop(&dev->Timer); 60647061Sbrian dev->Timer.state = TIMER_RUNNING; 60747061Sbrian } 60847061Sbrian} 60947061Sbrian 61047061Sbrianstatic struct device basettydevice = { 61146686Sbrian TTY_DEVICE, 61246686Sbrian "tty", 61378410Sbrian 0, 61453733Sbrian { CD_VARIABLE, DEF_TTYCDDELAY }, 61549472Sbrian tty_AwaitCarrier, 61652942Sbrian NULL, 61746686Sbrian tty_Raw, 61846686Sbrian tty_Offline, 61946686Sbrian tty_Cooked, 62093418Sbrian tty_SetAsyncParams, 62147061Sbrian tty_StopTimer, 62247061Sbrian tty_Free, 62393418Sbrian tty_Read, 62493418Sbrian tty_Write, 62547061Sbrian tty_device2iov, 62646686Sbrian tty_Speed, 62796582Sbrian tty_OpenInfo, 62896582Sbrian tty_Slot 62946686Sbrian}; 63047061Sbrian 63147286Sbrianstruct device * 63247286Sbriantty_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 633135166Sru int maxiov __unused, 634135166Sru#ifndef NONETGRAPH 635135166Sru int *auxfd, int *nauxfd 636135166Sru#else 637135166Sru int *auxfd __unused, int *nauxfd __unused 638135166Sru#endif 639135166Sru ) 64047124Sbrian{ 64147286Sbrian if (type == TTY_DEVICE) { 64247461Sbrian struct ttydevice *dev = (struct ttydevice *)iov[(*niov)++].iov_base; 64347286Sbrian 64447769Sbrian dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */ 64547769Sbrian if (dev == NULL) { 64647769Sbrian log_Printf(LogALERT, "Failed to allocate memory: %d\n", 64747769Sbrian (int)(sizeof *dev)); 64847769Sbrian AbortProgram(EX_OSERR); 64947769Sbrian } 65047769Sbrian 65193418Sbrian#ifndef NONETGRAPH 65293418Sbrian if (*nauxfd) { 65393418Sbrian dev->cs = *auxfd; 65493418Sbrian (*nauxfd)--; 65593418Sbrian } else 65693418Sbrian dev->cs = -1; 65793418Sbrian#endif 65893418Sbrian 65947286Sbrian /* Refresh function pointers etc */ 66047286Sbrian memcpy(&dev->dev, &basettydevice, sizeof dev->dev); 66147286Sbrian 66247461Sbrian physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE); 66347286Sbrian if (dev->Timer.state != TIMER_STOPPED) { 66447286Sbrian dev->Timer.state = TIMER_STOPPED; 66547769Sbrian p->handler = &dev->dev; /* For the benefit of StartTimer */ 66647286Sbrian tty_StartTimer(p); 66747286Sbrian } 66847286Sbrian return &dev->dev; 66947286Sbrian } 67047286Sbrian 67147286Sbrian return NULL; 67247286Sbrian} 67347286Sbrian 67447286Sbrianstruct device * 67547286Sbriantty_Create(struct physical *p) 67647286Sbrian{ 67747124Sbrian struct ttydevice *dev; 67847124Sbrian struct termios ios; 67947124Sbrian int oldflag; 68047124Sbrian 68147286Sbrian if (p->fd < 0 || !isatty(p->fd)) 68247286Sbrian /* Don't want this */ 68347124Sbrian return NULL; 68447124Sbrian 68547286Sbrian if (*p->name.full == '\0') { 68647286Sbrian physical_SetDevice(p, ttyname(p->fd)); 68747286Sbrian log_Printf(LogDEBUG, "%s: Input is a tty (%s)\n", 68847286Sbrian p->link.name, p->name.full); 68947286Sbrian } else 69047286Sbrian log_Printf(LogDEBUG, "%s: Opened %s\n", p->link.name, p->name.full); 69147286Sbrian 69247286Sbrian /* We're gonna return a ttydevice (unless something goes horribly wrong) */ 69347286Sbrian 69447286Sbrian if ((dev = malloc(sizeof *dev)) == NULL) { 69547286Sbrian /* Complete failure - parent doesn't continue trying to ``create'' */ 69647286Sbrian close(p->fd); 69747286Sbrian p->fd = -1; 69847286Sbrian return NULL; 69947286Sbrian } 70047286Sbrian 70147124Sbrian memcpy(&dev->dev, &basettydevice, sizeof dev->dev); 70247250Sbrian memset(&dev->Timer, '\0', sizeof dev->Timer); 70349472Sbrian dev->mbits = -1; 70493418Sbrian#ifndef NONETGRAPH 70593418Sbrian dev->real.speed = 0; 70693418Sbrian dev->real.fd = -1; 70793418Sbrian dev->real.disc = -1; 70893418Sbrian *dev->hook = '\0'; 70993418Sbrian#endif 71047124Sbrian tcgetattr(p->fd, &ios); 71147124Sbrian dev->ios = ios; 71247124Sbrian 71353733Sbrian if (p->cfg.cd.necessity != CD_DEFAULT) 71453733Sbrian /* Any override is ok for the tty device */ 71553733Sbrian dev->dev.cd = p->cfg.cd; 71653733Sbrian 71747286Sbrian log_Printf(LogDEBUG, "%s: tty_Create: physical (get): fd = %d," 71847124Sbrian " iflag = %lx, oflag = %lx, cflag = %lx\n", p->link.name, p->fd, 71947124Sbrian (u_long)ios.c_iflag, (u_long)ios.c_oflag, (u_long)ios.c_cflag); 72047124Sbrian 72147124Sbrian cfmakeraw(&ios); 72247124Sbrian if (p->cfg.rts_cts) 72347124Sbrian ios.c_cflag |= CLOCAL | CCTS_OFLOW | CRTS_IFLOW; 72447124Sbrian else { 72547124Sbrian ios.c_cflag |= CLOCAL; 72647124Sbrian ios.c_iflag |= IXOFF; 72747124Sbrian } 72847124Sbrian ios.c_iflag |= IXON; 72949588Sbrian if (p->type != PHYS_DEDICATED) 73047124Sbrian ios.c_cflag |= HUPCL; 73147124Sbrian 73247124Sbrian if (p->type != PHYS_DIRECT) { 73347124Sbrian /* Change tty speed when we're not in -direct mode */ 73447124Sbrian ios.c_cflag &= ~(CSIZE | PARODD | PARENB); 73547124Sbrian ios.c_cflag |= p->cfg.parity; 736134789Sbrian if (cfsetspeed(&ios, UnsignedToSpeed(p->cfg.speed)) == -1) 73747124Sbrian log_Printf(LogWARN, "%s: %s: Unable to set speed to %d\n", 73847124Sbrian p->link.name, p->name.full, p->cfg.speed); 73947124Sbrian } 74068127Sbrian 74168127Sbrian if (tcsetattr(p->fd, TCSADRAIN, &ios) == -1) { 74268127Sbrian log_Printf(LogWARN, "%s: tcsetattr: Failed configuring device\n", 74368127Sbrian p->link.name); 74468127Sbrian if (p->type != PHYS_DIRECT && p->cfg.speed > 115200) 74568127Sbrian log_Printf(LogWARN, "%.*s Perhaps the speed is unsupported\n", 74668127Sbrian (int)strlen(p->link.name), ""); 74768127Sbrian } 74868127Sbrian 74947124Sbrian log_Printf(LogDEBUG, "%s: physical (put): iflag = %lx, oflag = %lx, " 75047124Sbrian "cflag = %lx\n", p->link.name, (u_long)ios.c_iflag, 75147124Sbrian (u_long)ios.c_oflag, (u_long)ios.c_cflag); 75247124Sbrian 75347124Sbrian oldflag = fcntl(p->fd, F_GETFL, 0); 75447124Sbrian if (oldflag < 0) { 75547286Sbrian /* Complete failure - parent doesn't continue trying to ``create'' */ 75647286Sbrian 75747124Sbrian log_Printf(LogWARN, "%s: Open: Cannot get physical flags: %s\n", 75847124Sbrian p->link.name, strerror(errno)); 75947286Sbrian tty_Cooked(p); 76047286Sbrian close(p->fd); 76147286Sbrian p->fd = -1; 76249472Sbrian free(dev); 76347124Sbrian return NULL; 76447124Sbrian } else 76547124Sbrian fcntl(p->fd, F_SETFL, oldflag & ~O_NONBLOCK); 76647124Sbrian 76747461Sbrian physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE); 76847124Sbrian 76947124Sbrian return &dev->dev; 77047124Sbrian} 771