physical.c revision 53830
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 *
1950479Speter * $FreeBSD: head/usr.sbin/ppp/physical.c 53830 1999-11-28 15:50:08Z brian $
2036285Sbrian *
2136285Sbrian */
2236285Sbrian
2346686Sbrian#include <sys/param.h>
2446686Sbrian#include <netinet/in.h>
2546686Sbrian#include <netinet/in_systm.h>
2646686Sbrian#include <netinet/ip.h>
2746686Sbrian#include <sys/un.h>
2846686Sbrian
2946686Sbrian#include <errno.h>
3046686Sbrian#include <fcntl.h>
3146686Sbrian#include <paths.h>
3236285Sbrian#include <stdio.h>
3336285Sbrian#include <stdlib.h>
3436285Sbrian#include <string.h>
3546686Sbrian#include <sys/tty.h>	/* TIOCOUTQ */
3646686Sbrian#include <sys/uio.h>
3736285Sbrian#include <time.h>
3836285Sbrian#include <unistd.h>
3936285Sbrian#include <utmp.h>
4046686Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__)
4146686Sbrian#include <sys/ioctl.h>
4246686Sbrian#include <util.h>
4346686Sbrian#else
4446686Sbrian#include <libutil.h>
4546686Sbrian#endif
4636285Sbrian
4746686Sbrian#include "layer.h"
4850059Sbrian#ifndef NONAT
4951075Sbrian#include "nat_cmd.h"
5046686Sbrian#endif
5146686Sbrian#include "proto.h"
5246686Sbrian#include "acf.h"
5346686Sbrian#include "vjcomp.h"
5436285Sbrian#include "defs.h"
5546686Sbrian#include "command.h"
5636285Sbrian#include "mbuf.h"
5746686Sbrian#include "log.h"
5846686Sbrian#include "id.h"
5936285Sbrian#include "timer.h"
6046686Sbrian#include "fsm.h"
6136285Sbrian#include "lqr.h"
6236285Sbrian#include "hdlc.h"
6346686Sbrian#include "lcp.h"
6436285Sbrian#include "throughput.h"
6546686Sbrian#include "sync.h"
6636285Sbrian#include "async.h"
6746686Sbrian#include "iplist.h"
6846686Sbrian#include "slcompress.h"
6946686Sbrian#include "ipcp.h"
7046686Sbrian#include "filter.h"
7146686Sbrian#include "descriptor.h"
7236285Sbrian#include "ccp.h"
7336285Sbrian#include "link.h"
7436285Sbrian#include "physical.h"
7546686Sbrian#include "mp.h"
7646686Sbrian#ifndef NORADIUS
7746686Sbrian#include "radius.h"
7846686Sbrian#endif
7946686Sbrian#include "bundle.h"
8046686Sbrian#include "prompt.h"
8146686Sbrian#include "chat.h"
8246686Sbrian#include "auth.h"
8346686Sbrian#include "chap.h"
8446686Sbrian#include "cbcp.h"
8546686Sbrian#include "datalink.h"
8646686Sbrian#include "tcp.h"
8747061Sbrian#include "udp.h"
8846686Sbrian#include "exec.h"
8946686Sbrian#include "tty.h"
9049472Sbrian#ifndef NOI4B
9149472Sbrian#include "i4b.h"
9249472Sbrian#endif
9352942Sbrian#ifndef NONETGRAPH
9452942Sbrian#include "ether.h"
9552942Sbrian#endif
9636285Sbrian
9736285Sbrian
9852429Sbrian#define PPPOTCPLINE "ppp"
9952429Sbrian
10046686Sbrianstatic int physical_DescriptorWrite(struct descriptor *, struct bundle *,
10146686Sbrian                                    const fd_set *);
10236285Sbrian
10347769Sbrianstatic int
10447769Sbrianphysical_DeviceSize(void)
10547769Sbrian{
10647769Sbrian  return sizeof(struct device);
10747769Sbrian}
10847769Sbrian
10947061Sbrianstruct {
11047061Sbrian  struct device *(*create)(struct physical *);
11152942Sbrian  struct device *(*iov2device)(int, struct physical *, struct iovec *,
11252942Sbrian                               int *, int, int *, int *);
11347769Sbrian  int (*DeviceSize)(void);
11447061Sbrian} devices[] = {
11549472Sbrian#ifndef NOI4B
11649472Sbrian  { i4b_Create, i4b_iov2device, i4b_DeviceSize },
11749472Sbrian#endif
11847769Sbrian  { tty_Create, tty_iov2device, tty_DeviceSize },
11952942Sbrian#ifndef NONETGRAPH
12052942Sbrian  /* This must come before ``udp'' & ``tcp'' */
12152942Sbrian  { ether_Create, ether_iov2device, ether_DeviceSize },
12252942Sbrian#endif
12347769Sbrian  { tcp_Create, tcp_iov2device, tcp_DeviceSize },
12447769Sbrian  { udp_Create, udp_iov2device, udp_DeviceSize },
12547769Sbrian  { exec_Create, exec_iov2device, exec_DeviceSize }
12646686Sbrian};
12746686Sbrian
12847061Sbrian#define NDEVICES (sizeof devices / sizeof devices[0])
12946686Sbrian
13046686Sbrianstatic int
13146686Sbrianphysical_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
13246686Sbrian                   int *n)
13346686Sbrian{
13446686Sbrian  return physical_doUpdateSet(d, r, w, e, n, 0);
13546686Sbrian}
13646686Sbrian
13752942Sbrianvoid
13852942Sbrianphysical_SetDescriptor(struct physical *p)
13952942Sbrian{
14052942Sbrian  p->desc.type = PHYSICAL_DESCRIPTOR;
14152942Sbrian  p->desc.UpdateSet = physical_UpdateSet;
14252942Sbrian  p->desc.IsSet = physical_IsSet;
14352942Sbrian  p->desc.Read = physical_DescriptorRead;
14452942Sbrian  p->desc.Write = physical_DescriptorWrite;
14552942Sbrian}
14652942Sbrian
14746686Sbrianstruct physical *
14846686Sbrianphysical_Create(struct datalink *dl, int type)
14946686Sbrian{
15046686Sbrian  struct physical *p;
15146686Sbrian
15246686Sbrian  p = (struct physical *)malloc(sizeof(struct physical));
15346686Sbrian  if (!p)
15446686Sbrian    return NULL;
15546686Sbrian
15646686Sbrian  p->link.type = PHYSICAL_LINK;
15746686Sbrian  p->link.name = dl->name;
15846686Sbrian  p->link.len = sizeof *p;
15946686Sbrian
16049434Sbrian  /* The sample period is fixed - see physical2iov() & iov2physical() */
16149434Sbrian  throughput_init(&p->link.throughput, SAMPLE_PERIOD);
16249434Sbrian
16346686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
16446686Sbrian  memset(p->link.proto_in, '\0', sizeof p->link.proto_in);
16546686Sbrian  memset(p->link.proto_out, '\0', sizeof p->link.proto_out);
16646686Sbrian  link_EmptyStack(&p->link);
16746686Sbrian
16846686Sbrian  p->handler = NULL;
16952942Sbrian  physical_SetDescriptor(p);
17046686Sbrian  p->type = type;
17146686Sbrian
17246686Sbrian  hdlc_Init(&p->hdlc, &p->link.lcp);
17346686Sbrian  async_Init(&p->async);
17446686Sbrian
17546686Sbrian  p->fd = -1;
17646686Sbrian  p->out = NULL;
17746686Sbrian  p->connect_count = 0;
17846686Sbrian  p->dl = dl;
17946686Sbrian  p->input.sz = 0;
18046686Sbrian  *p->name.full = '\0';
18146686Sbrian  p->name.base = p->name.full;
18246686Sbrian
18346686Sbrian  p->Utmp = 0;
18446686Sbrian  p->session_owner = (pid_t)-1;
18546686Sbrian
18646686Sbrian  p->cfg.rts_cts = MODEM_CTSRTS;
18746686Sbrian  p->cfg.speed = MODEM_SPEED;
18846686Sbrian  p->cfg.parity = CS8;
18946686Sbrian  memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST);
19046686Sbrian  p->cfg.ndev = NMODEMS;
19153733Sbrian  p->cfg.cd.necessity = CD_DEFAULT;
19253733Sbrian  p->cfg.cd.delay = 0;		/* reconfigured or device specific default */
19346686Sbrian
19446686Sbrian  lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp);
19546686Sbrian  ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp);
19646686Sbrian
19746686Sbrian  return p;
19846686Sbrian}
19946686Sbrian
20046686Sbrianstatic const struct parity {
20146686Sbrian  const char *name;
20246686Sbrian  const char *name1;
20346686Sbrian  int set;
20446686Sbrian} validparity[] = {
20546686Sbrian  { "even", "P_EVEN", CS7 | PARENB },
20646686Sbrian  { "odd", "P_ODD", CS7 | PARENB | PARODD },
20746686Sbrian  { "none", "P_ZERO", CS8 },
20846686Sbrian  { NULL, 0 },
20946686Sbrian};
21046686Sbrian
21146686Sbrianstatic int
21246686SbrianGetParityValue(const char *str)
21346686Sbrian{
21446686Sbrian  const struct parity *pp;
21546686Sbrian
21646686Sbrian  for (pp = validparity; pp->name; pp++) {
21746686Sbrian    if (strcasecmp(pp->name, str) == 0 ||
21846686Sbrian	strcasecmp(pp->name1, str) == 0) {
21946686Sbrian      return pp->set;
22046686Sbrian    }
22146686Sbrian  }
22246686Sbrian  return (-1);
22346686Sbrian}
22446686Sbrian
22536285Sbrianint
22646686Sbrianphysical_SetParity(struct physical *p, const char *str)
22746686Sbrian{
22846686Sbrian  struct termios rstio;
22946686Sbrian  int val;
23046686Sbrian
23146686Sbrian  val = GetParityValue(str);
23246686Sbrian  if (val > 0) {
23346686Sbrian    p->cfg.parity = val;
23446686Sbrian    if (p->fd >= 0) {
23546686Sbrian      tcgetattr(p->fd, &rstio);
23646686Sbrian      rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
23746686Sbrian      rstio.c_cflag |= val;
23846686Sbrian      tcsetattr(p->fd, TCSADRAIN, &rstio);
23946686Sbrian    }
24046686Sbrian    return 0;
24146686Sbrian  }
24246686Sbrian  log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str);
24346686Sbrian  return -1;
24436285Sbrian}
24536285Sbrian
24636285Sbrianint
24746686Sbrianphysical_GetSpeed(struct physical *p)
24846686Sbrian{
24946686Sbrian  if (p->handler && p->handler->speed)
25046686Sbrian    return (*p->handler->speed)(p);
25146686Sbrian
25249434Sbrian  return 0;
25336285Sbrian}
25436285Sbrian
25546686Sbrianint
25646686Sbrianphysical_SetSpeed(struct physical *p, int speed)
25736285Sbrian{
25846686Sbrian  if (IntToSpeed(speed) != B0) {
25946686Sbrian      p->cfg.speed = speed;
26046686Sbrian      return 1;
26146686Sbrian  }
26246686Sbrian
26346686Sbrian  return 0;
26436285Sbrian}
26536285Sbrian
26646686Sbrianint
26746686Sbrianphysical_Raw(struct physical *p)
26846686Sbrian{
26946686Sbrian  if (p->handler && p->handler->raw)
27046686Sbrian    return (*p->handler->raw)(p);
27146686Sbrian
27246686Sbrian  return 1;
27346686Sbrian}
27446686Sbrian
27536285Sbrianvoid
27646686Sbrianphysical_Offline(struct physical *p)
27746686Sbrian{
27846686Sbrian  if (p->handler && p->handler->offline)
27946686Sbrian    (*p->handler->offline)(p);
28046686Sbrian  log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name);
28146686Sbrian}
28246686Sbrian
28347286Sbrianstatic int
28447286Sbrianphysical_Lock(struct physical *p)
28546686Sbrian{
28647286Sbrian  int res;
28746686Sbrian
28847286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
28947286Sbrian      (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
29047286Sbrian    if (res == UU_LOCK_INUSE)
29147286Sbrian      log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
29247286Sbrian    else
29347286Sbrian      log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
29447286Sbrian                 p->link.name, p->name.full, uu_lockerr(res));
29547286Sbrian    return 0;
29646686Sbrian  }
29747286Sbrian
29847286Sbrian  return 1;
29946686Sbrian}
30046686Sbrian
30147286Sbrianstatic void
30247286Sbrianphysical_Unlock(struct physical *p)
30347286Sbrian{
30447286Sbrian  char fn[MAXPATHLEN];
30547286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
30647286Sbrian      ID0uu_unlock(p->name.base) == -1)
30747286Sbrian    log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name, fn);
30847286Sbrian}
30947286Sbrian
31046686Sbrianvoid
31146686Sbrianphysical_Close(struct physical *p)
31246686Sbrian{
31347286Sbrian  int newsid;
31447286Sbrian  char fn[MAXPATHLEN];
31547286Sbrian
31646686Sbrian  if (p->fd < 0)
31746686Sbrian    return;
31846686Sbrian
31946686Sbrian  log_Printf(LogDEBUG, "%s: Close\n", p->link.name);
32046686Sbrian
32146686Sbrian  if (p->handler && p->handler->cooked)
32246686Sbrian    (*p->handler->cooked)(p);
32346686Sbrian
32447286Sbrian  physical_StopDeviceTimer(p);
32547286Sbrian  if (p->Utmp) {
32652429Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
32752487Sbrian                       p->handler->type == UDP_DEVICE))
32852487Sbrian      /* Careful - we logged in on line ``ppp'' with IP as our host */
32952487Sbrian      ID0logout(PPPOTCPLINE, 1);
33052487Sbrian    else
33152487Sbrian      ID0logout(p->name.base, 0);
33247286Sbrian    p->Utmp = 0;
33347286Sbrian  }
33447286Sbrian  newsid = tcgetpgrp(p->fd) == getpgrp();
33547286Sbrian  close(p->fd);
33647286Sbrian  p->fd = -1;
33747286Sbrian  log_SetTtyCommandMode(p->dl);
33847286Sbrian
33947286Sbrian  throughput_stop(&p->link.throughput);
34047286Sbrian  throughput_log(&p->link.throughput, LogPHASE, p->link.name);
34147286Sbrian
34247286Sbrian  if (p->session_owner != (pid_t)-1) {
34347286Sbrian    ID0kill(p->session_owner, SIGHUP);
34447286Sbrian    p->session_owner = (pid_t)-1;
34547286Sbrian  }
34647286Sbrian
34747286Sbrian  if (newsid)
34847286Sbrian    bundle_setsid(p->dl->bundle, 0);
34947286Sbrian
35047286Sbrian  if (*p->name.full == '/') {
35147286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
35247286Sbrian#ifndef RELEASE_CRUNCH
35347286Sbrian    if (ID0unlink(fn) == -1)
35447286Sbrian      log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
35547286Sbrian                 p->link.name, fn, strerror(errno));
35647286Sbrian#else
35747286Sbrian    ID0unlink(fn);
35847286Sbrian#endif
35947286Sbrian  }
36047286Sbrian  physical_Unlock(p);
36147286Sbrian  if (p->handler && p->handler->destroy)
36247286Sbrian    (*p->handler->destroy)(p);
36347286Sbrian  p->handler = NULL;
36447286Sbrian  p->name.base = p->name.full;
36547286Sbrian  *p->name.full = '\0';
36646686Sbrian}
36746686Sbrian
36846686Sbrianvoid
36946686Sbrianphysical_Destroy(struct physical *p)
37046686Sbrian{
37146686Sbrian  physical_Close(p);
37249434Sbrian  throughput_destroy(&p->link.throughput);
37346686Sbrian  free(p);
37446686Sbrian}
37546686Sbrian
37646686Sbrianstatic int
37746686Sbrianphysical_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
37846686Sbrian                         const fd_set *fdset)
37946686Sbrian{
38046686Sbrian  struct physical *p = descriptor2physical(d);
38146686Sbrian  int nw, result = 0;
38246686Sbrian
38346686Sbrian  if (p->out == NULL)
38446686Sbrian    p->out = link_Dequeue(&p->link);
38546686Sbrian
38646686Sbrian  if (p->out) {
38746686Sbrian    nw = physical_Write(p, MBUF_CTOP(p->out), p->out->cnt);
38846686Sbrian    log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%d) to %d\n",
38946686Sbrian               p->link.name, nw, p->out->cnt, p->fd);
39046686Sbrian    if (nw > 0) {
39146686Sbrian      p->out->cnt -= nw;
39246686Sbrian      p->out->offset += nw;
39346686Sbrian      if (p->out->cnt == 0)
39446686Sbrian	p->out = mbuf_FreeSeg(p->out);
39546686Sbrian      result = 1;
39646686Sbrian    } else if (nw < 0) {
39746686Sbrian      if (errno != EAGAIN) {
39846686Sbrian	log_Printf(LogPHASE, "%s: write (%d): %s\n", p->link.name,
39946686Sbrian                   p->fd, strerror(errno));
40046686Sbrian        datalink_Down(p->dl, CLOSE_NORMAL);
40146686Sbrian      }
40246686Sbrian      result = 1;
40346686Sbrian    }
40446686Sbrian    /* else we shouldn't really have been called !  select() is broken ! */
40546686Sbrian  }
40646686Sbrian
40746686Sbrian  return result;
40846686Sbrian}
40946686Sbrian
41046686Sbrianint
41146686Sbrianphysical_ShowStatus(struct cmdargs const *arg)
41246686Sbrian{
41346686Sbrian  struct physical *p = arg->cx->physical;
41453733Sbrian  struct cd *cd;
41546686Sbrian  const char *dev;
41646686Sbrian  int n;
41746686Sbrian
41846686Sbrian  prompt_Printf(arg->prompt, "Name: %s\n", p->link.name);
41946686Sbrian  prompt_Printf(arg->prompt, " State:           ");
42046686Sbrian  if (p->fd < 0)
42146686Sbrian    prompt_Printf(arg->prompt, "closed\n");
42246686Sbrian  else if (p->handler && p->handler->openinfo)
42346686Sbrian    prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
42446686Sbrian  else
42546686Sbrian    prompt_Printf(arg->prompt, "open\n");
42646686Sbrian
42746686Sbrian  prompt_Printf(arg->prompt, " Device:          %s",
42846686Sbrian                *p->name.full ?  p->name.full :
42946686Sbrian                p->type == PHYS_DIRECT ? "unknown" : "N/A");
43046686Sbrian  if (p->session_owner != (pid_t)-1)
43146686Sbrian    prompt_Printf(arg->prompt, " (session owner: %d)", (int)p->session_owner);
43246686Sbrian
43346686Sbrian  prompt_Printf(arg->prompt, "\n Link Type:       %s\n", mode2Nam(p->type));
43446686Sbrian  prompt_Printf(arg->prompt, " Connect Count:   %d\n", p->connect_count);
43546686Sbrian#ifdef TIOCOUTQ
43646686Sbrian  if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
43746686Sbrian      prompt_Printf(arg->prompt, " Physical outq:   %d\n", n);
43846686Sbrian#endif
43946686Sbrian
44046686Sbrian  prompt_Printf(arg->prompt, " Queued Packets:  %d\n",
44146686Sbrian                link_QueueLen(&p->link));
44246686Sbrian  prompt_Printf(arg->prompt, " Phone Number:    %s\n", arg->cx->phone.chosen);
44346686Sbrian
44446686Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
44546686Sbrian
44646686Sbrian  prompt_Printf(arg->prompt, " Device List:     ");
44746686Sbrian  dev = p->cfg.devlist;
44846686Sbrian  for (n = 0; n < p->cfg.ndev; n++) {
44946686Sbrian    if (n)
45046686Sbrian      prompt_Printf(arg->prompt, ", ");
45146686Sbrian    prompt_Printf(arg->prompt, "\"%s\"", dev);
45246686Sbrian    dev += strlen(dev) + 1;
45346686Sbrian  }
45446686Sbrian
45546686Sbrian  prompt_Printf(arg->prompt, "\n Characteristics: ");
45646686Sbrian  if (physical_IsSync(arg->cx->physical))
45746686Sbrian    prompt_Printf(arg->prompt, "sync");
45846686Sbrian  else
45946686Sbrian    prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
46046686Sbrian
46146686Sbrian  switch (p->cfg.parity & CSIZE) {
46246686Sbrian  case CS7:
46346686Sbrian    prompt_Printf(arg->prompt, ", cs7");
46446686Sbrian    break;
46546686Sbrian  case CS8:
46646686Sbrian    prompt_Printf(arg->prompt, ", cs8");
46746686Sbrian    break;
46846686Sbrian  }
46946686Sbrian  if (p->cfg.parity & PARENB) {
47046686Sbrian    if (p->cfg.parity & PARODD)
47146686Sbrian      prompt_Printf(arg->prompt, ", odd parity");
47246686Sbrian    else
47346686Sbrian      prompt_Printf(arg->prompt, ", even parity");
47446686Sbrian  } else
47546686Sbrian    prompt_Printf(arg->prompt, ", no parity");
47646686Sbrian
47746686Sbrian  prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
47846686Sbrian
47951699Sbrian  prompt_Printf(arg->prompt, " CD check delay:  ");
48053733Sbrian  cd = p->handler ? &p->handler->cd : &p->cfg.cd;
48153733Sbrian  if (cd->necessity == CD_NOTREQUIRED)
48251699Sbrian    prompt_Printf(arg->prompt, "no cd");
48353733Sbrian  else if (p->cfg.cd.necessity == CD_DEFAULT) {
48453733Sbrian    prompt_Printf(arg->prompt, "device specific");
48553733Sbrian  } else {
48651699Sbrian    prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay,
48751699Sbrian                  p->cfg.cd.delay == 1 ? "" : "s");
48851699Sbrian    if (p->cfg.cd.necessity == CD_REQUIRED)
48951699Sbrian      prompt_Printf(arg->prompt, " (required!)");
49051699Sbrian  }
49151699Sbrian  prompt_Printf(arg->prompt, "\n\n");
49246686Sbrian
49346686Sbrian  throughput_disp(&p->link.throughput, arg->prompt);
49446686Sbrian
49546686Sbrian  return 0;
49646686Sbrian}
49746686Sbrian
49852942Sbrianvoid
49946686Sbrianphysical_DescriptorRead(struct descriptor *d, struct bundle *bundle,
50046686Sbrian                     const fd_set *fdset)
50146686Sbrian{
50246686Sbrian  struct physical *p = descriptor2physical(d);
50346686Sbrian  u_char *rbuff;
50446686Sbrian  int n, found;
50546686Sbrian
50646686Sbrian  rbuff = p->input.buf + p->input.sz;
50746686Sbrian
50846686Sbrian  /* something to read */
50946686Sbrian  n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
51046686Sbrian  log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
51146686Sbrian             p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
51246686Sbrian  if (n <= 0) {
51346686Sbrian    if (n < 0)
51446686Sbrian      log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
51546686Sbrian                 strerror(errno));
51646686Sbrian    else
51746686Sbrian      log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
51846686Sbrian                 p->link.name, p->fd);
51946686Sbrian    datalink_Down(p->dl, CLOSE_NORMAL);
52046686Sbrian    return;
52146686Sbrian  }
52246686Sbrian
52346686Sbrian  rbuff -= p->input.sz;
52446686Sbrian  n += p->input.sz;
52546686Sbrian
52646686Sbrian  if (p->link.lcp.fsm.state <= ST_CLOSED) {
52746686Sbrian    if (p->type != PHYS_DEDICATED) {
52846686Sbrian      found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
52946686Sbrian      if (rbuff != p->input.buf)
53046686Sbrian        log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
53146686Sbrian                         p->input.buf);
53246686Sbrian      p->input.sz = n - (rbuff - p->input.buf);
53346686Sbrian
53446686Sbrian      if (found) {
53546686Sbrian        /* LCP packet is detected. Turn ourselves into packet mode */
53646686Sbrian        log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
53746686Sbrian                   p->link.name);
53846686Sbrian        log_SetTtyCommandMode(p->dl);
53946686Sbrian        datalink_Up(p->dl, 0, 1);
54046686Sbrian        link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
54146686Sbrian        p->input.sz = 0;
54246686Sbrian      } else
54346686Sbrian        bcopy(rbuff, p->input.buf, p->input.sz);
54446686Sbrian    } else
54546686Sbrian      /* In -dedicated mode, we just discard input until LCP is started */
54646686Sbrian      p->input.sz = 0;
54746686Sbrian  } else if (n > 0)
54846686Sbrian    link_PullPacket(&p->link, rbuff, n, bundle);
54946686Sbrian}
55046686Sbrian
55146686Sbrianstruct physical *
55246686Sbrianiov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
55352942Sbrian             int fd, int *auxfd, int *nauxfd)
55446686Sbrian{
55546686Sbrian  struct physical *p;
55647061Sbrian  int len, h, type;
55746686Sbrian
55846686Sbrian  p = (struct physical *)iov[(*niov)++].iov_base;
55946686Sbrian  p->link.name = dl->name;
56046686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
56146686Sbrian
56246686Sbrian  p->desc.UpdateSet = physical_UpdateSet;
56346686Sbrian  p->desc.IsSet = physical_IsSet;
56446686Sbrian  p->desc.Read = physical_DescriptorRead;
56546686Sbrian  p->desc.Write = physical_DescriptorWrite;
56646686Sbrian  p->type = PHYS_DIRECT;
56746686Sbrian  p->dl = dl;
56846686Sbrian  len = strlen(_PATH_DEV);
56946686Sbrian  p->out = NULL;
57046686Sbrian  p->connect_count = 1;
57146686Sbrian
57247682Sbrian  physical_SetDevice(p, p->name.full);
57347682Sbrian
57446686Sbrian  p->link.lcp.fsm.bundle = dl->bundle;
57546686Sbrian  p->link.lcp.fsm.link = &p->link;
57646686Sbrian  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
57746686Sbrian  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
57846686Sbrian  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
57946686Sbrian         sizeof p->link.lcp.fsm.StoppedTimer);
58046686Sbrian  p->link.lcp.fsm.parent = &dl->fsmp;
58146686Sbrian  lcp_SetupCallbacks(&p->link.lcp);
58246686Sbrian
58346686Sbrian  p->link.ccp.fsm.bundle = dl->bundle;
58446686Sbrian  p->link.ccp.fsm.link = &p->link;
58546686Sbrian  /* Our in.state & out.state are NULL (no link-level ccp yet) */
58646686Sbrian  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
58746686Sbrian  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
58846686Sbrian  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
58946686Sbrian         sizeof p->link.ccp.fsm.StoppedTimer);
59046686Sbrian  p->link.ccp.fsm.parent = &dl->fsmp;
59146686Sbrian  ccp_SetupCallbacks(&p->link.ccp);
59246686Sbrian
59346686Sbrian  p->hdlc.lqm.owner = &p->link.lcp;
59446686Sbrian  p->hdlc.ReportTimer.state = TIMER_STOPPED;
59546686Sbrian  p->hdlc.lqm.timer.state = TIMER_STOPPED;
59646686Sbrian
59746686Sbrian  p->fd = fd;
59849434Sbrian  p->link.throughput.SampleOctets = (long long *)iov[(*niov)++].iov_base;
59946686Sbrian
60047769Sbrian  type = (long)p->handler;
60147769Sbrian  p->handler = NULL;
60247769Sbrian  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
60352942Sbrian    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
60452942Sbrian                                          auxfd, nauxfd);
60547769Sbrian  if (p->handler == NULL) {
60652942Sbrian    log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
60747769Sbrian    free(iov[(*niov)++].iov_base);
60847769Sbrian    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
60947769Sbrian  } else
61047769Sbrian    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
61147769Sbrian               p->link.name, p->name.full, p->handler->name);
61247769Sbrian
61346686Sbrian  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
61446686Sbrian    lqr_reStart(&p->link.lcp);
61546686Sbrian  hdlc_StartTimer(&p->hdlc);
61646686Sbrian
61749434Sbrian  throughput_restart(&p->link.throughput, "physical throughput",
61849434Sbrian                     Enabled(dl->bundle, OPT_THROUGHPUT));
61946686Sbrian
62047769Sbrian  return p;
62147769Sbrian}
62247061Sbrian
62347769Sbrianint
62447769Sbrianphysical_MaxDeviceSize()
62547769Sbrian{
62647769Sbrian  int biggest, sz, n;
62747061Sbrian
62847769Sbrian  biggest = sizeof(struct device);
62947769Sbrian  for (sz = n = 0; n < NDEVICES; n++)
63047769Sbrian    if (devices[n].DeviceSize) {
63147769Sbrian      sz = (*devices[n].DeviceSize)();
63247769Sbrian      if (biggest < sz)
63347769Sbrian        biggest = sz;
63447769Sbrian    }
63547769Sbrian
63647769Sbrian  return biggest;
63746686Sbrian}
63846686Sbrian
63946686Sbrianint
64046686Sbrianphysical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
64153684Sbrian             int *auxfd, int *nauxfd)
64246686Sbrian{
64347769Sbrian  struct device *h;
64447769Sbrian  int sz;
64547769Sbrian
64647769Sbrian  h = NULL;
64746686Sbrian  if (p) {
64846686Sbrian    hdlc_StopTimer(&p->hdlc);
64946686Sbrian    lqr_StopTimer(p);
65046686Sbrian    timer_Stop(&p->link.lcp.fsm.FsmTimer);
65146686Sbrian    timer_Stop(&p->link.ccp.fsm.FsmTimer);
65246686Sbrian    timer_Stop(&p->link.lcp.fsm.OpenTimer);
65346686Sbrian    timer_Stop(&p->link.ccp.fsm.OpenTimer);
65446686Sbrian    timer_Stop(&p->link.lcp.fsm.StoppedTimer);
65546686Sbrian    timer_Stop(&p->link.ccp.fsm.StoppedTimer);
65647061Sbrian    if (p->handler) {
65753684Sbrian      h = p->handler;
65847061Sbrian      p->handler = (struct device *)(long)p->handler->type;
65946686Sbrian    }
66047061Sbrian
66147689Sbrian    if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
66247689Sbrian        tcgetpgrp(p->fd) == getpgrp())
66346686Sbrian      p->session_owner = getpid();      /* So I'll eventually get HUP'd */
66447689Sbrian    else
66547689Sbrian      p->session_owner = (pid_t)-1;
66646686Sbrian    timer_Stop(&p->link.throughput.Timer);
66746686Sbrian  }
66846686Sbrian
66949434Sbrian  if (*niov + 2 >= maxiov) {
67049434Sbrian    log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
67149434Sbrian               " + device !\n");
67246686Sbrian    if (p)
67346686Sbrian      free(p);
67446686Sbrian    return -1;
67546686Sbrian  }
67646686Sbrian
67753684Sbrian  iov[*niov].iov_base = (void *)p;
67846686Sbrian  iov[*niov].iov_len = sizeof *p;
67946686Sbrian  (*niov)++;
68046686Sbrian
68153684Sbrian  iov[*niov].iov_base = p ? (void *)p->link.throughput.SampleOctets : NULL;
68249434Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
68349434Sbrian  (*niov)++;
68449434Sbrian
68547769Sbrian  sz = physical_MaxDeviceSize();
68647769Sbrian  if (p) {
68753684Sbrian    if (h && h->device2iov)
68853684Sbrian      (*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd);
68947769Sbrian    else {
69047769Sbrian      iov[*niov].iov_base = malloc(sz);
69153684Sbrian      if (h)
69253684Sbrian        memcpy(iov[*niov].iov_base, h, sizeof *h);
69347769Sbrian      iov[*niov].iov_len = sz;
69447769Sbrian      (*niov)++;
69547769Sbrian    }
69647769Sbrian  } else {
69753684Sbrian    iov[*niov].iov_base = NULL;
69847769Sbrian    iov[*niov].iov_len = sz;
69947769Sbrian    (*niov)++;
70047769Sbrian  }
70147769Sbrian
70246686Sbrian  return p ? p->fd : 0;
70346686Sbrian}
70446686Sbrian
70553684Sbrianconst char *
70653684Sbrianphysical_LockedDevice(struct physical *p)
70753684Sbrian{
70853684Sbrian  if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT)
70953684Sbrian    return p->name.base;
71053684Sbrian
71153684Sbrian  return NULL;
71253684Sbrian}
71353684Sbrian
71446686Sbrianvoid
71546686Sbrianphysical_ChangedPid(struct physical *p, pid_t newpid)
71646686Sbrian{
71753684Sbrian  if (physical_LockedDevice(p)) {
71846686Sbrian    int res;
71946686Sbrian
72046686Sbrian    if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
72146686Sbrian      log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
72246686Sbrian  }
72346686Sbrian}
72446686Sbrian
72546686Sbrianint
72646686Sbrianphysical_IsSync(struct physical *p)
72746686Sbrian{
72846686Sbrian   return p->cfg.speed == 0;
72946686Sbrian}
73046686Sbrian
73146686Sbrianconst char *physical_GetDevice(struct physical *p)
73246686Sbrian{
73346686Sbrian   return p->name.full;
73446686Sbrian}
73546686Sbrian
73646686Sbrianvoid
73736285Sbrianphysical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
73836285Sbrian{
73936285Sbrian  int f, pos;
74036285Sbrian
74136285Sbrian  p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
74236285Sbrian  for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
74336285Sbrian    if (pos)
74446102Sbrian      p->cfg.devlist[pos++] = '\0';
74536285Sbrian    strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
74636285Sbrian    pos += strlen(p->cfg.devlist + pos);
74736285Sbrian  }
74846102Sbrian  p->cfg.ndev = f;
74936285Sbrian}
75036285Sbrian
75136285Sbrianvoid
75246686Sbrianphysical_SetSync(struct physical *p)
75346686Sbrian{
75446686Sbrian   p->cfg.speed = 0;
75536285Sbrian}
75636285Sbrian
75736285Sbrianint
75846686Sbrianphysical_SetRtsCts(struct physical *p, int enable)
75946686Sbrian{
76046686Sbrian   p->cfg.rts_cts = enable ? 1 : 0;
76136285Sbrian   return 1;
76236285Sbrian}
76336285Sbrian
76436285Sbrianssize_t
76546686Sbrianphysical_Read(struct physical *p, void *buf, size_t nbytes)
76646686Sbrian{
76747061Sbrian  ssize_t ret;
76847061Sbrian
76947061Sbrian  if (p->handler && p->handler->read)
77047061Sbrian    ret = (*p->handler->read)(p, buf, nbytes);
77147061Sbrian  else
77247061Sbrian    ret = read(p->fd, buf, nbytes);
77347061Sbrian
77447061Sbrian  log_DumpBuff(LogPHYSICAL, "read", buf, ret);
77547061Sbrian
77647061Sbrian  return ret;
77736285Sbrian}
77836285Sbrian
77936285Sbrianssize_t
78046686Sbrianphysical_Write(struct physical *p, const void *buf, size_t nbytes)
78146686Sbrian{
78247061Sbrian  log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
78347061Sbrian
78447061Sbrian  if (p->handler && p->handler->write)
78547061Sbrian    return (*p->handler->write)(p, buf, nbytes);
78647061Sbrian
78747061Sbrian  return write(p->fd, buf, nbytes);
78836285Sbrian}
78936285Sbrian
79036285Sbrianint
79146686Sbrianphysical_doUpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
79246686Sbrian                     int *n, int force)
79336285Sbrian{
79436285Sbrian  struct physical *p = descriptor2physical(d);
79536285Sbrian  int sets;
79636285Sbrian
79736285Sbrian  sets = 0;
79836285Sbrian  if (p->fd >= 0) {
79936285Sbrian    if (r) {
80036285Sbrian      FD_SET(p->fd, r);
80136285Sbrian      log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
80236285Sbrian      sets++;
80336285Sbrian    }
80436285Sbrian    if (e) {
80536285Sbrian      FD_SET(p->fd, e);
80636285Sbrian      log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
80736285Sbrian      sets++;
80836285Sbrian    }
80936314Sbrian    if (w && (force || link_QueueLen(&p->link) || p->out)) {
81036285Sbrian      FD_SET(p->fd, w);
81136285Sbrian      log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
81236285Sbrian      sets++;
81336285Sbrian    }
81436285Sbrian    if (sets && *n < p->fd + 1)
81536285Sbrian      *n = p->fd + 1;
81636285Sbrian  }
81736285Sbrian
81836285Sbrian  return sets;
81936285Sbrian}
82036285Sbrian
82136285Sbrianint
82236285Sbrianphysical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
82336285Sbrian{
82452942Sbrian  if (p->handler && p->handler->removefromset)
82552942Sbrian    return (*p->handler->removefromset)(p, r, w, e);
82652942Sbrian  else {
82752942Sbrian    int sets;
82836285Sbrian
82952942Sbrian    sets = 0;
83052942Sbrian    if (p->fd >= 0) {
83152942Sbrian      if (r && FD_ISSET(p->fd, r)) {
83252942Sbrian        FD_CLR(p->fd, r);
83352942Sbrian        log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
83452942Sbrian        sets++;
83552942Sbrian      }
83652942Sbrian      if (e && FD_ISSET(p->fd, e)) {
83752942Sbrian        FD_CLR(p->fd, e);
83852942Sbrian        log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
83952942Sbrian        sets++;
84052942Sbrian      }
84152942Sbrian      if (w && FD_ISSET(p->fd, w)) {
84252942Sbrian        FD_CLR(p->fd, w);
84352942Sbrian        log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
84452942Sbrian        sets++;
84552942Sbrian      }
84636285Sbrian    }
84752942Sbrian
84852942Sbrian    return sets;
84936285Sbrian  }
85036285Sbrian}
85136285Sbrian
85236285Sbrianint
85336285Sbrianphysical_IsSet(struct descriptor *d, const fd_set *fdset)
85436285Sbrian{
85536285Sbrian  struct physical *p = descriptor2physical(d);
85636285Sbrian  return p->fd >= 0 && FD_ISSET(p->fd, fdset);
85736285Sbrian}
85836285Sbrian
85936285Sbrianvoid
86046686Sbrianphysical_Login(struct physical *p, const char *name)
86136285Sbrian{
86246830Sbrian  if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
86346686Sbrian    struct utmp ut;
86446686Sbrian    const char *connstr;
86552413Sbrian    char *colon;
86636285Sbrian
86746686Sbrian    memset(&ut, 0, sizeof ut);
86846686Sbrian    time(&ut.ut_time);
86946686Sbrian    strncpy(ut.ut_name, name, sizeof ut.ut_name);
87052413Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
87152413Sbrian                       p->handler->type == UDP_DEVICE)) {
87252429Sbrian      strncpy(ut.ut_line, PPPOTCPLINE, sizeof ut.ut_line);
87352413Sbrian      strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host);
87452413Sbrian      colon = memchr(ut.ut_host, ':', sizeof ut.ut_host);
87552413Sbrian      if (colon)
87652413Sbrian        *colon = '\0';
87752413Sbrian    } else
87852413Sbrian      strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
87946686Sbrian    if ((connstr = getenv("CONNECT")))
88046686Sbrian      /* mgetty sets this to the connection speed */
88146686Sbrian      strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
88246686Sbrian    ID0login(&ut);
88352429Sbrian    p->Utmp = ut.ut_time;
88436285Sbrian  }
88536285Sbrian}
88636285Sbrian
88736285Sbrianint
88836285Sbrianphysical_SetMode(struct physical *p, int mode)
88936285Sbrian{
89038174Sbrian  if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
89138174Sbrian       mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
89238174Sbrian      (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
89353830Sbrian    /* Note:  The -direct -> -background is for callback ! */
89436285Sbrian    log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
89536285Sbrian               mode2Nam(p->type), mode2Nam(mode));
89636285Sbrian    return 0;
89736285Sbrian  }
89836285Sbrian  p->type = mode;
89936285Sbrian  return 1;
90036285Sbrian}
90138544Sbrian
90238544Sbrianvoid
90338544Sbrianphysical_DeleteQueue(struct physical *p)
90438544Sbrian{
90538544Sbrian  if (p->out) {
90638544Sbrian    mbuf_Free(p->out);
90738544Sbrian    p->out = NULL;
90838544Sbrian  }
90938544Sbrian  link_DeleteQueue(&p->link);
91038544Sbrian}
91146686Sbrian
91246686Sbrianvoid
91346686Sbrianphysical_SetDevice(struct physical *p, const char *name)
91446686Sbrian{
91546686Sbrian  int len = strlen(_PATH_DEV);
91646686Sbrian
91747682Sbrian  if (name != p->name.full) {
91847682Sbrian    strncpy(p->name.full, name, sizeof p->name.full - 1);
91947682Sbrian    p->name.full[sizeof p->name.full - 1] = '\0';
92047682Sbrian  }
92146686Sbrian  p->name.base = *p->name.full == '!' ?  p->name.full + 1 :
92246686Sbrian                 strncmp(p->name.full, _PATH_DEV, len) ?
92346686Sbrian                 p->name.full : p->name.full + len;
92446686Sbrian}
92546686Sbrian
92646686Sbrianstatic void
92746686Sbrianphysical_Found(struct physical *p)
92846686Sbrian{
92947286Sbrian  FILE *lockfile;
93047286Sbrian  char fn[MAXPATHLEN];
93147286Sbrian
93247286Sbrian  if (*p->name.full == '/') {
93347286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
93447286Sbrian    lockfile = ID0fopen(fn, "w");
93547286Sbrian    if (lockfile != NULL) {
93647286Sbrian      fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
93747286Sbrian      fclose(lockfile);
93847286Sbrian    }
93947286Sbrian#ifndef RELEASE_CRUNCH
94047286Sbrian    else
94147286Sbrian      log_Printf(LogALERT, "%s: Can't create %s: %s\n",
94247286Sbrian                 p->link.name, fn, strerror(errno));
94347286Sbrian#endif
94447286Sbrian  }
94547286Sbrian
94646686Sbrian  throughput_start(&p->link.throughput, "physical throughput",
94746686Sbrian                   Enabled(p->dl->bundle, OPT_THROUGHPUT));
94846686Sbrian  p->connect_count++;
94946686Sbrian  p->input.sz = 0;
95046686Sbrian
95146686Sbrian  log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
95246686Sbrian}
95346686Sbrian
95446686Sbrianint
95546686Sbrianphysical_Open(struct physical *p, struct bundle *bundle)
95646686Sbrian{
95752942Sbrian  int devno, h, wasfd, err;
95846686Sbrian  char *dev;
95946686Sbrian
96046686Sbrian  if (p->fd >= 0)
96146686Sbrian    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
96246686Sbrian    /* We're going back into "term" mode */
96346686Sbrian  else if (p->type == PHYS_DIRECT) {
96447061Sbrian    physical_SetDevice(p, "");
96547061Sbrian    p->fd = STDIN_FILENO;
96647061Sbrian    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
96752942Sbrian      p->handler = (*devices[h].create)(p);
96847061Sbrian    if (p->fd >= 0) {
96947124Sbrian      if (p->handler == NULL) {
97047461Sbrian        physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
97147124Sbrian        log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
97247124Sbrian      }
97346686Sbrian      physical_Found(p);
97446686Sbrian    }
97546686Sbrian  } else {
97646686Sbrian    dev = p->cfg.devlist;
97746686Sbrian    devno = 0;
97846686Sbrian    while (devno < p->cfg.ndev && p->fd < 0) {
97946686Sbrian      physical_SetDevice(p, dev);
98047286Sbrian      if (physical_Lock(p)) {
98147878Sbrian        err = 0;
98247878Sbrian
98347878Sbrian        if (*p->name.full == '/') {
98447286Sbrian          p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
98547878Sbrian          if (p->fd < 0)
98647878Sbrian            err = errno;
98747878Sbrian        }
98846686Sbrian
98952942Sbrian        wasfd = p->fd;
99047286Sbrian        for (h = 0; h < NDEVICES && p->handler == NULL; h++)
99152942Sbrian          if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd)
99247286Sbrian            break;
99346686Sbrian
99447286Sbrian        if (p->fd < 0) {
99547878Sbrian          if (h == NDEVICES) {
99647878Sbrian            if (err)
99747878Sbrian	      log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
99847878Sbrian                         strerror(errno));
99947878Sbrian            else
100047878Sbrian	      log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
100152942Sbrian                         " a '!' or contain at least one ':'\n", p->link.name,
100247878Sbrian                         p->name.full);
100347878Sbrian          }
100447286Sbrian          physical_Unlock(p);
100547286Sbrian        } else
100647286Sbrian          physical_Found(p);
100747286Sbrian      }
100846686Sbrian      dev += strlen(dev) + 1;
100946686Sbrian      devno++;
101046686Sbrian    }
101146686Sbrian  }
101246686Sbrian
101346686Sbrian  return p->fd;
101446686Sbrian}
101546686Sbrian
101646686Sbrianvoid
101747461Sbrianphysical_SetupStack(struct physical *p, const char *who, int how)
101846686Sbrian{
101946686Sbrian  link_EmptyStack(&p->link);
102052942Sbrian  if (how == PHYSICAL_FORCE_SYNC || how == PHYSICAL_FORCE_SYNCNOACF ||
102147061Sbrian      (how == PHYSICAL_NOFORCE && physical_IsSync(p)))
102246686Sbrian    link_Stack(&p->link, &synclayer);
102346686Sbrian  else {
102446686Sbrian    link_Stack(&p->link, &asynclayer);
102546686Sbrian    link_Stack(&p->link, &hdlclayer);
102646686Sbrian  }
102752942Sbrian  if (how != PHYSICAL_FORCE_SYNCNOACF)
102852942Sbrian    link_Stack(&p->link, &acflayer);
102946686Sbrian  link_Stack(&p->link, &protolayer);
103046686Sbrian  link_Stack(&p->link, &lqrlayer);
103146686Sbrian  link_Stack(&p->link, &ccplayer);
103246686Sbrian  link_Stack(&p->link, &vjlayer);
103350059Sbrian#ifndef NONAT
103450059Sbrian  link_Stack(&p->link, &natlayer);
103546686Sbrian#endif
103647061Sbrian  if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) {
103747461Sbrian    log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who);
103847061Sbrian    p->cfg.speed = MODEM_SPEED;
103947061Sbrian  } else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) {
104047061Sbrian    log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n",
104147461Sbrian               who);
104247061Sbrian    physical_SetSync(p);
104347061Sbrian  }
104446686Sbrian}
104547061Sbrian
104647061Sbrianvoid
104747061Sbrianphysical_StopDeviceTimer(struct physical *p)
104847061Sbrian{
104947061Sbrian  if (p->handler && p->handler->stoptimer)
105047061Sbrian    (*p->handler->stoptimer)(p);
105147061Sbrian}
105249472Sbrian
105349472Sbrianint
105449472Sbrianphysical_AwaitCarrier(struct physical *p)
105549472Sbrian{
105649472Sbrian  if (p->handler && p->handler->awaitcarrier)
105749472Sbrian    return (*p->handler->awaitcarrier)(p);
105849472Sbrian
105949472Sbrian  return CARRIER_OK;
106049472Sbrian}
1061