physical.c revision 46686
136285Sbrian/* 236285Sbrian * Written by Eivind Eklund <eivind@yes.no> 336285Sbrian * for Yes Interactive 436285Sbrian * 536285Sbrian * Copyright (C) 1998, Yes Interactive. All rights reserved. 636285Sbrian * 736285Sbrian * Redistribution and use in any form is permitted. Redistribution in 836285Sbrian * source form should include the above copyright and this set of 936285Sbrian * conditions, because large sections american law seems to have been 1036285Sbrian * created by a bunch of jerks on drugs that are now illegal, forcing 1136285Sbrian * me to include this copyright-stuff instead of placing this in the 1236285Sbrian * public domain. The name of of 'Yes Interactive' or 'Eivind Eklund' 1336285Sbrian * may not be used to endorse or promote products derived from this 1436285Sbrian * software without specific prior written permission. 1536285Sbrian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1636285Sbrian * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1736285Sbrian * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1836285Sbrian * 1946686Sbrian * $Id: physical.c,v 1.8 1999/04/27 00:23:56 brian Exp $ 2036285Sbrian * 2136285Sbrian */ 2236285Sbrian 2346686Sbrian#include <sys/param.h> 2446686Sbrian#include <sys/socket.h> 2546686Sbrian#include <netinet/in.h> 2646686Sbrian#include <arpa/inet.h> 2746686Sbrian#include <netdb.h> 2846686Sbrian#include <netinet/in_systm.h> 2946686Sbrian#include <netinet/ip.h> 3046686Sbrian#include <sys/un.h> 3146686Sbrian 3246686Sbrian#include <errno.h> 3346686Sbrian#include <fcntl.h> 3446686Sbrian#include <paths.h> 3536285Sbrian#include <stdio.h> 3636285Sbrian#include <stdlib.h> 3736285Sbrian#include <string.h> 3846686Sbrian#include <sys/tty.h> /* TIOCOUTQ */ 3946686Sbrian#include <sys/uio.h> 4046686Sbrian#include <sys/wait.h> 4136285Sbrian#include <time.h> 4236285Sbrian#include <unistd.h> 4336285Sbrian#include <utmp.h> 4446686Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__) 4546686Sbrian#include <sys/ioctl.h> 4646686Sbrian#include <util.h> 4746686Sbrian#else 4846686Sbrian#include <libutil.h> 4946686Sbrian#endif 5036285Sbrian 5146686Sbrian#include "layer.h" 5246686Sbrian#ifndef NOALIAS 5346686Sbrian#include "alias_cmd.h" 5446686Sbrian#endif 5546686Sbrian#include "proto.h" 5646686Sbrian#include "acf.h" 5746686Sbrian#include "vjcomp.h" 5836285Sbrian#include "defs.h" 5946686Sbrian#include "command.h" 6036285Sbrian#include "mbuf.h" 6146686Sbrian#include "log.h" 6246686Sbrian#include "id.h" 6336285Sbrian#include "timer.h" 6446686Sbrian#include "fsm.h" 6536285Sbrian#include "lqr.h" 6636285Sbrian#include "hdlc.h" 6746686Sbrian#include "lcp.h" 6836285Sbrian#include "throughput.h" 6946686Sbrian#include "sync.h" 7036285Sbrian#include "async.h" 7146686Sbrian#include "iplist.h" 7246686Sbrian#include "slcompress.h" 7346686Sbrian#include "ipcp.h" 7446686Sbrian#include "filter.h" 7546686Sbrian#include "descriptor.h" 7636285Sbrian#include "ccp.h" 7736285Sbrian#include "link.h" 7836285Sbrian#include "physical.h" 7946686Sbrian#include "mp.h" 8046686Sbrian#ifndef NORADIUS 8146686Sbrian#include "radius.h" 8246686Sbrian#endif 8346686Sbrian#include "bundle.h" 8446686Sbrian#include "prompt.h" 8546686Sbrian#include "chat.h" 8646686Sbrian#include "auth.h" 8746686Sbrian#include "chap.h" 8846686Sbrian#include "cbcp.h" 8946686Sbrian#include "datalink.h" 9046686Sbrian#include "tcp.h" 9146686Sbrian#include "exec.h" 9246686Sbrian#include "tty.h" 9336285Sbrian 9436285Sbrian 9546686Sbrianstatic int physical_DescriptorWrite(struct descriptor *, struct bundle *, 9646686Sbrian const fd_set *); 9746686Sbrianstatic void physical_DescriptorRead(struct descriptor *, struct bundle *, 9846686Sbrian const fd_set *); 9936285Sbrian 10046686Sbrianstatic const struct device *handlers[] = { 10146686Sbrian &ttydevice, &tcpdevice, &execdevice 10246686Sbrian}; 10346686Sbrian 10446686Sbrian#define NHANDLERS (sizeof handlers / sizeof handlers[0]) 10546686Sbrian 10646686Sbrianstatic int 10746686Sbrianphysical_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 10846686Sbrian int *n) 10946686Sbrian{ 11046686Sbrian return physical_doUpdateSet(d, r, w, e, n, 0); 11146686Sbrian} 11246686Sbrian 11346686Sbrianstruct physical * 11446686Sbrianphysical_Create(struct datalink *dl, int type) 11546686Sbrian{ 11646686Sbrian struct physical *p; 11746686Sbrian 11846686Sbrian p = (struct physical *)malloc(sizeof(struct physical)); 11946686Sbrian if (!p) 12046686Sbrian return NULL; 12146686Sbrian 12246686Sbrian p->link.type = PHYSICAL_LINK; 12346686Sbrian p->link.name = dl->name; 12446686Sbrian p->link.len = sizeof *p; 12546686Sbrian throughput_init(&p->link.throughput); 12646686Sbrian 12746686Sbrian memset(p->link.Queue, '\0', sizeof p->link.Queue); 12846686Sbrian memset(p->link.proto_in, '\0', sizeof p->link.proto_in); 12946686Sbrian memset(p->link.proto_out, '\0', sizeof p->link.proto_out); 13046686Sbrian link_EmptyStack(&p->link); 13146686Sbrian 13246686Sbrian memset(&p->Timer, '\0', sizeof p->Timer); 13346686Sbrian p->handler = NULL; 13446686Sbrian p->desc.type = PHYSICAL_DESCRIPTOR; 13546686Sbrian p->desc.UpdateSet = physical_UpdateSet; 13646686Sbrian p->desc.IsSet = physical_IsSet; 13746686Sbrian p->desc.Read = physical_DescriptorRead; 13846686Sbrian p->desc.Write = physical_DescriptorWrite; 13946686Sbrian p->type = type; 14046686Sbrian 14146686Sbrian hdlc_Init(&p->hdlc, &p->link.lcp); 14246686Sbrian async_Init(&p->async); 14346686Sbrian 14446686Sbrian p->fd = -1; 14546686Sbrian p->out = NULL; 14646686Sbrian p->connect_count = 0; 14746686Sbrian p->dl = dl; 14846686Sbrian p->input.sz = 0; 14946686Sbrian *p->name.full = '\0'; 15046686Sbrian p->name.base = p->name.full; 15146686Sbrian 15246686Sbrian p->Utmp = 0; 15346686Sbrian p->session_owner = (pid_t)-1; 15446686Sbrian 15546686Sbrian p->cfg.rts_cts = MODEM_CTSRTS; 15646686Sbrian p->cfg.speed = MODEM_SPEED; 15746686Sbrian p->cfg.parity = CS8; 15846686Sbrian memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST); 15946686Sbrian p->cfg.ndev = NMODEMS; 16046686Sbrian p->cfg.cd.required = 0; 16146686Sbrian p->cfg.cd.delay = DEF_CDDELAY; 16246686Sbrian 16346686Sbrian lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp); 16446686Sbrian ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp); 16546686Sbrian 16646686Sbrian return p; 16746686Sbrian} 16846686Sbrian 16946686Sbrianstatic const struct parity { 17046686Sbrian const char *name; 17146686Sbrian const char *name1; 17246686Sbrian int set; 17346686Sbrian} validparity[] = { 17446686Sbrian { "even", "P_EVEN", CS7 | PARENB }, 17546686Sbrian { "odd", "P_ODD", CS7 | PARENB | PARODD }, 17646686Sbrian { "none", "P_ZERO", CS8 }, 17746686Sbrian { NULL, 0 }, 17846686Sbrian}; 17946686Sbrian 18046686Sbrianstatic int 18146686SbrianGetParityValue(const char *str) 18246686Sbrian{ 18346686Sbrian const struct parity *pp; 18446686Sbrian 18546686Sbrian for (pp = validparity; pp->name; pp++) { 18646686Sbrian if (strcasecmp(pp->name, str) == 0 || 18746686Sbrian strcasecmp(pp->name1, str) == 0) { 18846686Sbrian return pp->set; 18946686Sbrian } 19046686Sbrian } 19146686Sbrian return (-1); 19246686Sbrian} 19346686Sbrian 19436285Sbrianint 19546686Sbrianphysical_SetParity(struct physical *p, const char *str) 19646686Sbrian{ 19746686Sbrian struct termios rstio; 19846686Sbrian int val; 19946686Sbrian 20046686Sbrian val = GetParityValue(str); 20146686Sbrian if (val > 0) { 20246686Sbrian p->cfg.parity = val; 20346686Sbrian if (p->fd >= 0) { 20446686Sbrian tcgetattr(p->fd, &rstio); 20546686Sbrian rstio.c_cflag &= ~(CSIZE | PARODD | PARENB); 20646686Sbrian rstio.c_cflag |= val; 20746686Sbrian tcsetattr(p->fd, TCSADRAIN, &rstio); 20846686Sbrian } 20946686Sbrian return 0; 21046686Sbrian } 21146686Sbrian log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str); 21246686Sbrian return -1; 21336285Sbrian} 21436285Sbrian 21536285Sbrianint 21646686Sbrianphysical_GetSpeed(struct physical *p) 21746686Sbrian{ 21846686Sbrian if (p->handler && p->handler->speed) 21946686Sbrian return (*p->handler->speed)(p); 22046686Sbrian 22146686Sbrian return 115200; 22236285Sbrian} 22336285Sbrian 22446686Sbrianint 22546686Sbrianphysical_SetSpeed(struct physical *p, int speed) 22636285Sbrian{ 22746686Sbrian if (IntToSpeed(speed) != B0) { 22846686Sbrian p->cfg.speed = speed; 22946686Sbrian return 1; 23046686Sbrian } 23146686Sbrian 23246686Sbrian return 0; 23336285Sbrian} 23436285Sbrian 23546686Sbrianint 23646686Sbrianphysical_Raw(struct physical *p) 23746686Sbrian{ 23846686Sbrian if (p->handler && p->handler->raw) 23946686Sbrian return (*p->handler->raw)(p); 24046686Sbrian 24146686Sbrian return 1; 24246686Sbrian} 24346686Sbrian 24436285Sbrianvoid 24546686Sbrianphysical_Offline(struct physical *p) 24646686Sbrian{ 24746686Sbrian if (p->handler && p->handler->offline) 24846686Sbrian (*p->handler->offline)(p); 24946686Sbrian log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name); 25046686Sbrian} 25146686Sbrian 25246686Sbrianstatic void 25346686Sbrianphysical_ReallyClose(struct physical *p) 25446686Sbrian{ 25546686Sbrian int newsid; 25646686Sbrian 25746686Sbrian log_Printf(LogDEBUG, "%s: Really close %d\n", p->link.name, p->fd); 25846686Sbrian if (p->fd >= 0) { 25946686Sbrian timer_Stop(&p->Timer); 26046686Sbrian if (p->Utmp) { 26146686Sbrian ID0logout(p->name.base); 26246686Sbrian p->Utmp = 0; 26346686Sbrian } 26446686Sbrian newsid = tcgetpgrp(p->fd) == getpgrp(); 26546686Sbrian close(p->fd); 26646686Sbrian p->fd = -1; 26746686Sbrian log_SetTtyCommandMode(p->dl); 26846686Sbrian throughput_stop(&p->link.throughput); 26946686Sbrian throughput_log(&p->link.throughput, LogPHASE, p->link.name); 27046686Sbrian if (p->session_owner != (pid_t)-1) { 27146686Sbrian ID0kill(p->session_owner, SIGHUP); 27246686Sbrian p->session_owner = (pid_t)-1; 27346686Sbrian } 27446686Sbrian if (newsid) 27546686Sbrian bundle_setsid(p->dl->bundle, 0); 27646686Sbrian if (p->handler && p->handler->postclose) 27746686Sbrian (*p->handler->postclose)(p); 27846686Sbrian p->handler = NULL; 27946686Sbrian } 28046686Sbrian *p->name.full = '\0'; 28146686Sbrian p->name.base = p->name.full; 28246686Sbrian} 28346686Sbrian 28446686Sbrianvoid 28546686Sbrianphysical_Close(struct physical *p) 28646686Sbrian{ 28746686Sbrian if (p->fd < 0) 28846686Sbrian return; 28946686Sbrian 29046686Sbrian log_Printf(LogDEBUG, "%s: Close\n", p->link.name); 29146686Sbrian 29246686Sbrian if (p->handler && p->handler->cooked) 29346686Sbrian (*p->handler->cooked)(p); 29446686Sbrian 29546686Sbrian physical_ReallyClose(p); 29646686Sbrian} 29746686Sbrian 29846686Sbrianvoid 29946686Sbrianphysical_Destroy(struct physical *p) 30046686Sbrian{ 30146686Sbrian physical_Close(p); 30246686Sbrian free(p); 30346686Sbrian} 30446686Sbrian 30546686Sbrianstatic int 30646686Sbrianphysical_DescriptorWrite(struct descriptor *d, struct bundle *bundle, 30746686Sbrian const fd_set *fdset) 30846686Sbrian{ 30946686Sbrian struct physical *p = descriptor2physical(d); 31046686Sbrian int nw, result = 0; 31146686Sbrian 31246686Sbrian if (p->out == NULL) 31346686Sbrian p->out = link_Dequeue(&p->link); 31446686Sbrian 31546686Sbrian if (p->out) { 31646686Sbrian nw = physical_Write(p, MBUF_CTOP(p->out), p->out->cnt); 31746686Sbrian log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%d) to %d\n", 31846686Sbrian p->link.name, nw, p->out->cnt, p->fd); 31946686Sbrian if (nw > 0) { 32046686Sbrian p->out->cnt -= nw; 32146686Sbrian p->out->offset += nw; 32246686Sbrian if (p->out->cnt == 0) 32346686Sbrian p->out = mbuf_FreeSeg(p->out); 32446686Sbrian result = 1; 32546686Sbrian } else if (nw < 0) { 32646686Sbrian if (errno != EAGAIN) { 32746686Sbrian log_Printf(LogPHASE, "%s: write (%d): %s\n", p->link.name, 32846686Sbrian p->fd, strerror(errno)); 32946686Sbrian datalink_Down(p->dl, CLOSE_NORMAL); 33046686Sbrian } 33146686Sbrian result = 1; 33246686Sbrian } 33346686Sbrian /* else we shouldn't really have been called ! select() is broken ! */ 33446686Sbrian } 33546686Sbrian 33646686Sbrian return result; 33746686Sbrian} 33846686Sbrian 33946686Sbrianint 34046686Sbrianphysical_ShowStatus(struct cmdargs const *arg) 34146686Sbrian{ 34246686Sbrian struct physical *p = arg->cx->physical; 34346686Sbrian const char *dev; 34446686Sbrian int n; 34546686Sbrian 34646686Sbrian prompt_Printf(arg->prompt, "Name: %s\n", p->link.name); 34746686Sbrian prompt_Printf(arg->prompt, " State: "); 34846686Sbrian if (p->fd < 0) 34946686Sbrian prompt_Printf(arg->prompt, "closed\n"); 35046686Sbrian else if (p->handler && p->handler->openinfo) 35146686Sbrian prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p)); 35246686Sbrian else 35346686Sbrian prompt_Printf(arg->prompt, "open\n"); 35446686Sbrian 35546686Sbrian prompt_Printf(arg->prompt, " Device: %s", 35646686Sbrian *p->name.full ? p->name.full : 35746686Sbrian p->type == PHYS_DIRECT ? "unknown" : "N/A"); 35846686Sbrian if (p->session_owner != (pid_t)-1) 35946686Sbrian prompt_Printf(arg->prompt, " (session owner: %d)", (int)p->session_owner); 36046686Sbrian 36146686Sbrian prompt_Printf(arg->prompt, "\n Link Type: %s\n", mode2Nam(p->type)); 36246686Sbrian prompt_Printf(arg->prompt, " Connect Count: %d\n", p->connect_count); 36346686Sbrian#ifdef TIOCOUTQ 36446686Sbrian if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0) 36546686Sbrian prompt_Printf(arg->prompt, " Physical outq: %d\n", n); 36646686Sbrian#endif 36746686Sbrian 36846686Sbrian prompt_Printf(arg->prompt, " Queued Packets: %d\n", 36946686Sbrian link_QueueLen(&p->link)); 37046686Sbrian prompt_Printf(arg->prompt, " Phone Number: %s\n", arg->cx->phone.chosen); 37146686Sbrian 37246686Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 37346686Sbrian 37446686Sbrian prompt_Printf(arg->prompt, " Device List: "); 37546686Sbrian dev = p->cfg.devlist; 37646686Sbrian for (n = 0; n < p->cfg.ndev; n++) { 37746686Sbrian if (n) 37846686Sbrian prompt_Printf(arg->prompt, ", "); 37946686Sbrian prompt_Printf(arg->prompt, "\"%s\"", dev); 38046686Sbrian dev += strlen(dev) + 1; 38146686Sbrian } 38246686Sbrian 38346686Sbrian prompt_Printf(arg->prompt, "\n Characteristics: "); 38446686Sbrian if (physical_IsSync(arg->cx->physical)) 38546686Sbrian prompt_Printf(arg->prompt, "sync"); 38646686Sbrian else 38746686Sbrian prompt_Printf(arg->prompt, "%dbps", p->cfg.speed); 38846686Sbrian 38946686Sbrian switch (p->cfg.parity & CSIZE) { 39046686Sbrian case CS7: 39146686Sbrian prompt_Printf(arg->prompt, ", cs7"); 39246686Sbrian break; 39346686Sbrian case CS8: 39446686Sbrian prompt_Printf(arg->prompt, ", cs8"); 39546686Sbrian break; 39646686Sbrian } 39746686Sbrian if (p->cfg.parity & PARENB) { 39846686Sbrian if (p->cfg.parity & PARODD) 39946686Sbrian prompt_Printf(arg->prompt, ", odd parity"); 40046686Sbrian else 40146686Sbrian prompt_Printf(arg->prompt, ", even parity"); 40246686Sbrian } else 40346686Sbrian prompt_Printf(arg->prompt, ", no parity"); 40446686Sbrian 40546686Sbrian prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off")); 40646686Sbrian 40746686Sbrian prompt_Printf(arg->prompt, " CD check delay: %d second%s", 40846686Sbrian p->cfg.cd.delay, p->cfg.cd.delay == 1 ? "" : "s"); 40946686Sbrian if (p->cfg.cd.required) 41046686Sbrian prompt_Printf(arg->prompt, " (required!)\n\n"); 41146686Sbrian else 41246686Sbrian prompt_Printf(arg->prompt, "\n\n"); 41346686Sbrian 41446686Sbrian throughput_disp(&p->link.throughput, arg->prompt); 41546686Sbrian 41646686Sbrian return 0; 41746686Sbrian} 41846686Sbrian 41946686Sbrianstatic void 42046686Sbrianphysical_DescriptorRead(struct descriptor *d, struct bundle *bundle, 42146686Sbrian const fd_set *fdset) 42246686Sbrian{ 42346686Sbrian struct physical *p = descriptor2physical(d); 42446686Sbrian u_char *rbuff; 42546686Sbrian int n, found; 42646686Sbrian 42746686Sbrian rbuff = p->input.buf + p->input.sz; 42846686Sbrian 42946686Sbrian /* something to read */ 43046686Sbrian n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz); 43146686Sbrian log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n", 43246686Sbrian p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd); 43346686Sbrian if (n <= 0) { 43446686Sbrian if (n < 0) 43546686Sbrian log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd, 43646686Sbrian strerror(errno)); 43746686Sbrian else 43846686Sbrian log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n", 43946686Sbrian p->link.name, p->fd); 44046686Sbrian datalink_Down(p->dl, CLOSE_NORMAL); 44146686Sbrian return; 44246686Sbrian } 44346686Sbrian 44446686Sbrian log_DumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 44546686Sbrian rbuff -= p->input.sz; 44646686Sbrian n += p->input.sz; 44746686Sbrian 44846686Sbrian if (p->link.lcp.fsm.state <= ST_CLOSED) { 44946686Sbrian if (p->type != PHYS_DEDICATED) { 45046686Sbrian found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p)); 45146686Sbrian if (rbuff != p->input.buf) 45246686Sbrian log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf), 45346686Sbrian p->input.buf); 45446686Sbrian p->input.sz = n - (rbuff - p->input.buf); 45546686Sbrian 45646686Sbrian if (found) { 45746686Sbrian /* LCP packet is detected. Turn ourselves into packet mode */ 45846686Sbrian log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n", 45946686Sbrian p->link.name); 46046686Sbrian log_SetTtyCommandMode(p->dl); 46146686Sbrian datalink_Up(p->dl, 0, 1); 46246686Sbrian link_PullPacket(&p->link, rbuff, p->input.sz, bundle); 46346686Sbrian p->input.sz = 0; 46446686Sbrian } else 46546686Sbrian bcopy(rbuff, p->input.buf, p->input.sz); 46646686Sbrian } else 46746686Sbrian /* In -dedicated mode, we just discard input until LCP is started */ 46846686Sbrian p->input.sz = 0; 46946686Sbrian } else if (n > 0) 47046686Sbrian link_PullPacket(&p->link, rbuff, n, bundle); 47146686Sbrian} 47246686Sbrian 47346686Sbrianstruct physical * 47446686Sbrianiov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 47546686Sbrian int fd) 47646686Sbrian{ 47746686Sbrian struct physical *p; 47846686Sbrian int len, h; 47946686Sbrian 48046686Sbrian p = (struct physical *)iov[(*niov)++].iov_base; 48146686Sbrian p->link.name = dl->name; 48246686Sbrian throughput_init(&p->link.throughput); 48346686Sbrian memset(&p->Timer, '\0', sizeof p->Timer); 48446686Sbrian memset(p->link.Queue, '\0', sizeof p->link.Queue); 48546686Sbrian 48646686Sbrian p->desc.UpdateSet = physical_UpdateSet; 48746686Sbrian p->desc.IsSet = physical_IsSet; 48846686Sbrian p->desc.Read = physical_DescriptorRead; 48946686Sbrian p->desc.Write = physical_DescriptorWrite; 49046686Sbrian p->type = PHYS_DIRECT; 49146686Sbrian p->dl = dl; 49246686Sbrian len = strlen(_PATH_DEV); 49346686Sbrian p->name.base = strncmp(p->name.full, _PATH_DEV, len) ? 49446686Sbrian p->name.full : p->name.full + len; 49546686Sbrian p->out = NULL; 49646686Sbrian p->connect_count = 1; 49746686Sbrian 49846686Sbrian if (p->handler) { 49946686Sbrian for (h = 0; h < NHANDLERS; h++) 50046686Sbrian if (p->handler == (const struct device *)(long)handlers[h]->type) { 50146686Sbrian p->handler = handlers[h]; 50246686Sbrian break; 50346686Sbrian } 50446686Sbrian if (h == NHANDLERS) { 50546686Sbrian log_Printf(LogERROR, "iov2physical: Can't find device hander !\n"); 50646686Sbrian p->handler = NULL; 50746686Sbrian } 50846686Sbrian } 50946686Sbrian 51046686Sbrian p->link.lcp.fsm.bundle = dl->bundle; 51146686Sbrian p->link.lcp.fsm.link = &p->link; 51246686Sbrian memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer); 51346686Sbrian memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer); 51446686Sbrian memset(&p->link.lcp.fsm.StoppedTimer, '\0', 51546686Sbrian sizeof p->link.lcp.fsm.StoppedTimer); 51646686Sbrian p->link.lcp.fsm.parent = &dl->fsmp; 51746686Sbrian lcp_SetupCallbacks(&p->link.lcp); 51846686Sbrian 51946686Sbrian p->link.ccp.fsm.bundle = dl->bundle; 52046686Sbrian p->link.ccp.fsm.link = &p->link; 52146686Sbrian /* Our in.state & out.state are NULL (no link-level ccp yet) */ 52246686Sbrian memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer); 52346686Sbrian memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer); 52446686Sbrian memset(&p->link.ccp.fsm.StoppedTimer, '\0', 52546686Sbrian sizeof p->link.ccp.fsm.StoppedTimer); 52646686Sbrian p->link.ccp.fsm.parent = &dl->fsmp; 52746686Sbrian ccp_SetupCallbacks(&p->link.ccp); 52846686Sbrian 52946686Sbrian p->hdlc.lqm.owner = &p->link.lcp; 53046686Sbrian p->hdlc.ReportTimer.state = TIMER_STOPPED; 53146686Sbrian p->hdlc.lqm.timer.state = TIMER_STOPPED; 53246686Sbrian 53346686Sbrian p->fd = fd; 53446686Sbrian 53546686Sbrian if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load) 53646686Sbrian lqr_reStart(&p->link.lcp); 53746686Sbrian hdlc_StartTimer(&p->hdlc); 53846686Sbrian 53946686Sbrian throughput_start(&p->link.throughput, "physical throughput", 54046686Sbrian Enabled(dl->bundle, OPT_THROUGHPUT)); 54146686Sbrian if (p->handler && p->handler->restored) 54246686Sbrian (*p->handler->restored)(p); 54346686Sbrian 54446686Sbrian return p; 54546686Sbrian} 54646686Sbrian 54746686Sbrianint 54846686Sbrianphysical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov, 54946686Sbrian pid_t newpid) 55046686Sbrian{ 55146686Sbrian if (p) { 55246686Sbrian hdlc_StopTimer(&p->hdlc); 55346686Sbrian lqr_StopTimer(p); 55446686Sbrian timer_Stop(&p->link.lcp.fsm.FsmTimer); 55546686Sbrian timer_Stop(&p->link.ccp.fsm.FsmTimer); 55646686Sbrian timer_Stop(&p->link.lcp.fsm.OpenTimer); 55746686Sbrian timer_Stop(&p->link.ccp.fsm.OpenTimer); 55846686Sbrian timer_Stop(&p->link.lcp.fsm.StoppedTimer); 55946686Sbrian timer_Stop(&p->link.ccp.fsm.StoppedTimer); 56046686Sbrian if (p->handler) 56146686Sbrian p->handler = (const struct device *)(long)p->handler->type; 56246686Sbrian if (p->Timer.state != TIMER_STOPPED) { 56346686Sbrian timer_Stop(&p->Timer); 56446686Sbrian p->Timer.state = TIMER_RUNNING; /* Special - see iov2physical() */ 56546686Sbrian } 56646686Sbrian if (tcgetpgrp(p->fd) == getpgrp()) 56746686Sbrian p->session_owner = getpid(); /* So I'll eventually get HUP'd */ 56846686Sbrian timer_Stop(&p->link.throughput.Timer); 56946686Sbrian physical_ChangedPid(p, newpid); 57046686Sbrian } 57146686Sbrian 57246686Sbrian if (*niov >= maxiov) { 57346686Sbrian log_Printf(LogERROR, "physical2iov: No room for physical !\n"); 57446686Sbrian if (p) 57546686Sbrian free(p); 57646686Sbrian return -1; 57746686Sbrian } 57846686Sbrian 57946686Sbrian iov[*niov].iov_base = p ? p : malloc(sizeof *p); 58046686Sbrian iov[*niov].iov_len = sizeof *p; 58146686Sbrian (*niov)++; 58246686Sbrian 58346686Sbrian return p ? p->fd : 0; 58446686Sbrian} 58546686Sbrian 58646686Sbrianvoid 58746686Sbrianphysical_ChangedPid(struct physical *p, pid_t newpid) 58846686Sbrian{ 58946686Sbrian if (p->fd >= 0 && p->type != PHYS_DIRECT) { 59046686Sbrian int res; 59146686Sbrian 59246686Sbrian if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK) 59346686Sbrian log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res)); 59446686Sbrian } 59546686Sbrian} 59646686Sbrian 59746686Sbrianint 59846686Sbrianphysical_IsSync(struct physical *p) 59946686Sbrian{ 60046686Sbrian return p->cfg.speed == 0; 60146686Sbrian} 60246686Sbrian 60346686Sbrianconst char *physical_GetDevice(struct physical *p) 60446686Sbrian{ 60546686Sbrian return p->name.full; 60646686Sbrian} 60746686Sbrian 60846686Sbrianvoid 60936285Sbrianphysical_SetDeviceList(struct physical *p, int argc, const char *const *argv) 61036285Sbrian{ 61136285Sbrian int f, pos; 61236285Sbrian 61336285Sbrian p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0'; 61436285Sbrian for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) { 61536285Sbrian if (pos) 61646102Sbrian p->cfg.devlist[pos++] = '\0'; 61736285Sbrian strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1); 61836285Sbrian pos += strlen(p->cfg.devlist + pos); 61936285Sbrian } 62046102Sbrian p->cfg.ndev = f; 62136285Sbrian} 62236285Sbrian 62336285Sbrianvoid 62446686Sbrianphysical_SetSync(struct physical *p) 62546686Sbrian{ 62646686Sbrian p->cfg.speed = 0; 62736285Sbrian} 62836285Sbrian 62936285Sbrianint 63046686Sbrianphysical_SetRtsCts(struct physical *p, int enable) 63146686Sbrian{ 63246686Sbrian p->cfg.rts_cts = enable ? 1 : 0; 63336285Sbrian return 1; 63436285Sbrian} 63536285Sbrian 63636285Sbrian/* Encapsulation for a read on the FD. Avoids some exposure, and 63736285Sbrian concentrates control. */ 63836285Sbrianssize_t 63946686Sbrianphysical_Read(struct physical *p, void *buf, size_t nbytes) 64046686Sbrian{ 64146686Sbrian return read(p->fd, buf, nbytes); 64236285Sbrian} 64336285Sbrian 64436285Sbrianssize_t 64546686Sbrianphysical_Write(struct physical *p, const void *buf, size_t nbytes) 64646686Sbrian{ 64746686Sbrian return write(p->fd, buf, nbytes); 64836285Sbrian} 64936285Sbrian 65036285Sbrianint 65146686Sbrianphysical_doUpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 65246686Sbrian int *n, int force) 65336285Sbrian{ 65436285Sbrian struct physical *p = descriptor2physical(d); 65536285Sbrian int sets; 65636285Sbrian 65736285Sbrian sets = 0; 65836285Sbrian if (p->fd >= 0) { 65936285Sbrian if (r) { 66036285Sbrian FD_SET(p->fd, r); 66136285Sbrian log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd); 66236285Sbrian sets++; 66336285Sbrian } 66436285Sbrian if (e) { 66536285Sbrian FD_SET(p->fd, e); 66636285Sbrian log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd); 66736285Sbrian sets++; 66836285Sbrian } 66936314Sbrian if (w && (force || link_QueueLen(&p->link) || p->out)) { 67036285Sbrian FD_SET(p->fd, w); 67136285Sbrian log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd); 67236285Sbrian sets++; 67336285Sbrian } 67436285Sbrian if (sets && *n < p->fd + 1) 67536285Sbrian *n = p->fd + 1; 67636285Sbrian } 67736285Sbrian 67836285Sbrian return sets; 67936285Sbrian} 68036285Sbrian 68136285Sbrianint 68236285Sbrianphysical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e) 68336285Sbrian{ 68436285Sbrian int sets; 68536285Sbrian 68636285Sbrian sets = 0; 68736285Sbrian if (p->fd >= 0) { 68836285Sbrian if (r && FD_ISSET(p->fd, r)) { 68936285Sbrian FD_CLR(p->fd, r); 69036285Sbrian log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd); 69136285Sbrian sets++; 69236285Sbrian } 69336285Sbrian if (e && FD_ISSET(p->fd, e)) { 69436285Sbrian FD_CLR(p->fd, e); 69536285Sbrian log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd); 69636285Sbrian sets++; 69736285Sbrian } 69836285Sbrian if (w && FD_ISSET(p->fd, w)) { 69936285Sbrian FD_CLR(p->fd, w); 70036285Sbrian log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd); 70136285Sbrian sets++; 70236285Sbrian } 70336285Sbrian } 70436285Sbrian 70536285Sbrian return sets; 70636285Sbrian} 70736285Sbrian 70836285Sbrianint 70936285Sbrianphysical_IsSet(struct descriptor *d, const fd_set *fdset) 71036285Sbrian{ 71136285Sbrian struct physical *p = descriptor2physical(d); 71236285Sbrian return p->fd >= 0 && FD_ISSET(p->fd, fdset); 71336285Sbrian} 71436285Sbrian 71536285Sbrianvoid 71646686Sbrianphysical_Login(struct physical *p, const char *name) 71736285Sbrian{ 71846686Sbrian if (p->type == PHYS_DIRECT && !p->Utmp) { 71946686Sbrian struct utmp ut; 72046686Sbrian const char *connstr; 72136285Sbrian 72246686Sbrian memset(&ut, 0, sizeof ut); 72346686Sbrian time(&ut.ut_time); 72446686Sbrian strncpy(ut.ut_name, name, sizeof ut.ut_name); 72546686Sbrian strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line); 72646686Sbrian if ((connstr = getenv("CONNECT"))) 72746686Sbrian /* mgetty sets this to the connection speed */ 72846686Sbrian strncpy(ut.ut_host, connstr, sizeof ut.ut_host); 72946686Sbrian ID0login(&ut); 73046686Sbrian p->Utmp = 1; 73136285Sbrian } 73236285Sbrian} 73336285Sbrian 73436285Sbrianint 73536285Sbrianphysical_SetMode(struct physical *p, int mode) 73636285Sbrian{ 73738174Sbrian if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) || 73838174Sbrian mode & (PHYS_DIRECT|PHYS_DEDICATED)) && 73938174Sbrian (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) { 74036285Sbrian log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name, 74136285Sbrian mode2Nam(p->type), mode2Nam(mode)); 74236285Sbrian return 0; 74336285Sbrian } 74436285Sbrian p->type = mode; 74536285Sbrian return 1; 74636285Sbrian} 74738544Sbrian 74838544Sbrianvoid 74938544Sbrianphysical_DeleteQueue(struct physical *p) 75038544Sbrian{ 75138544Sbrian if (p->out) { 75238544Sbrian mbuf_Free(p->out); 75338544Sbrian p->out = NULL; 75438544Sbrian } 75538544Sbrian link_DeleteQueue(&p->link); 75638544Sbrian} 75746686Sbrian 75846686Sbrianvoid 75946686Sbrianphysical_SetDevice(struct physical *p, const char *name) 76046686Sbrian{ 76146686Sbrian int len = strlen(_PATH_DEV); 76246686Sbrian 76346686Sbrian strncpy(p->name.full, name, sizeof p->name.full - 1); 76446686Sbrian p->name.full[sizeof p->name.full - 1] = '\0'; 76546686Sbrian p->name.base = *p->name.full == '!' ? p->name.full + 1 : 76646686Sbrian strncmp(p->name.full, _PATH_DEV, len) ? 76746686Sbrian p->name.full : p->name.full + len; 76846686Sbrian} 76946686Sbrian 77046686Sbrianstatic void 77146686Sbrianphysical_Found(struct physical *p) 77246686Sbrian{ 77346686Sbrian throughput_start(&p->link.throughput, "physical throughput", 77446686Sbrian Enabled(p->dl->bundle, OPT_THROUGHPUT)); 77546686Sbrian p->connect_count++; 77646686Sbrian p->input.sz = 0; 77746686Sbrian 77846686Sbrian log_Printf(LogPHASE, "%s: Connected!\n", p->link.name); 77946686Sbrian} 78046686Sbrian 78146686Sbrianint 78246686Sbrianphysical_Open(struct physical *p, struct bundle *bundle) 78346686Sbrian{ 78446686Sbrian int devno, h; 78546686Sbrian char *dev; 78646686Sbrian 78746686Sbrian if (p->fd >= 0) 78846686Sbrian log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name); 78946686Sbrian /* We're going back into "term" mode */ 79046686Sbrian else if (p->type == PHYS_DIRECT) { 79146686Sbrian if (tty_OpenStdin(p)) { 79246686Sbrian physical_Found(p); 79346686Sbrian p->handler = &ttydevice; 79446686Sbrian } else { 79546686Sbrian log_Printf(LogDEBUG, "%s: physical_Open: stdin is not a tty\n", 79646686Sbrian p->link.name); 79746686Sbrian physical_SetDevice(p, ""); 79846686Sbrian physical_SetupStack(p, 0); 79946686Sbrian physical_Found(p); 80046686Sbrian return p->fd = STDIN_FILENO; 80146686Sbrian } 80246686Sbrian } else { 80346686Sbrian dev = p->cfg.devlist; 80446686Sbrian devno = 0; 80546686Sbrian while (devno < p->cfg.ndev && p->fd < 0) { 80646686Sbrian physical_SetDevice(p, dev); 80746686Sbrian 80846686Sbrian for (h = 0; h < NHANDLERS; h++) 80946686Sbrian if (handlers[h]->open && (*handlers[h]->open)(p)) { 81046686Sbrian p->handler = handlers[h]; 81146686Sbrian physical_Found(p); 81246686Sbrian } 81346686Sbrian 81446686Sbrian if (p->fd < 0) 81546686Sbrian log_Printf(LogWARN, "%s: Device (%s) must begin with a '/'," 81646686Sbrian " a '!' or be a host:port pair\n", p->link.name, 81746686Sbrian p->name.full); 81846686Sbrian dev += strlen(dev) + 1; 81946686Sbrian devno++; 82046686Sbrian } 82146686Sbrian } 82246686Sbrian 82346686Sbrian return p->fd; 82446686Sbrian} 82546686Sbrian 82646686Sbrianvoid 82746686Sbrianphysical_SetupStack(struct physical *p, int forceasync) 82846686Sbrian{ 82946686Sbrian link_EmptyStack(&p->link); 83046686Sbrian if (!forceasync && physical_IsSync(p)) 83146686Sbrian link_Stack(&p->link, &synclayer); 83246686Sbrian else { 83346686Sbrian link_Stack(&p->link, &asynclayer); 83446686Sbrian link_Stack(&p->link, &hdlclayer); 83546686Sbrian } 83646686Sbrian link_Stack(&p->link, &acflayer); 83746686Sbrian link_Stack(&p->link, &protolayer); 83846686Sbrian link_Stack(&p->link, &lqrlayer); 83946686Sbrian link_Stack(&p->link, &ccplayer); 84046686Sbrian link_Stack(&p->link, &vjlayer); 84146686Sbrian#ifndef NOALIAS 84246686Sbrian link_Stack(&p->link, &aliaslayer); 84346686Sbrian#endif 84446686Sbrian if (forceasync && physical_IsSync(p)) 84546686Sbrian log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", 84646686Sbrian p->handler ? p->handler->name : "unknown"); 84746686Sbrian} 848