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