physical.c revision 50479
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 50479 1999-08-28 01:35:59Z peter $
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
4946686Sbrian#include "alias_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
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
10047769Sbrianstatic int
10147769Sbrianphysical_DeviceSize(void)
10247769Sbrian{
10347769Sbrian  return sizeof(struct device);
10447769Sbrian}
10547769Sbrian
10647061Sbrianstruct {
10747061Sbrian  struct device *(*create)(struct physical *);
10847061Sbrian  struct device *(*iov2device)(int, struct physical *, struct iovec *iov,
10947061Sbrian                               int *niov, int maxiov);
11047769Sbrian  int (*DeviceSize)(void);
11147061Sbrian} devices[] = {
11249472Sbrian#ifndef NOI4B
11349472Sbrian  { i4b_Create, i4b_iov2device, i4b_DeviceSize },
11449472Sbrian#endif
11547769Sbrian  { tty_Create, tty_iov2device, tty_DeviceSize },
11647769Sbrian  { tcp_Create, tcp_iov2device, tcp_DeviceSize },
11747769Sbrian  { udp_Create, udp_iov2device, udp_DeviceSize },
11847769Sbrian  { exec_Create, exec_iov2device, exec_DeviceSize }
11946686Sbrian};
12046686Sbrian
12147061Sbrian#define NDEVICES (sizeof devices / sizeof devices[0])
12246686Sbrian
12346686Sbrianstatic int
12446686Sbrianphysical_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
12546686Sbrian                   int *n)
12646686Sbrian{
12746686Sbrian  return physical_doUpdateSet(d, r, w, e, n, 0);
12846686Sbrian}
12946686Sbrian
13046686Sbrianstruct physical *
13146686Sbrianphysical_Create(struct datalink *dl, int type)
13246686Sbrian{
13346686Sbrian  struct physical *p;
13446686Sbrian
13546686Sbrian  p = (struct physical *)malloc(sizeof(struct physical));
13646686Sbrian  if (!p)
13746686Sbrian    return NULL;
13846686Sbrian
13946686Sbrian  p->link.type = PHYSICAL_LINK;
14046686Sbrian  p->link.name = dl->name;
14146686Sbrian  p->link.len = sizeof *p;
14246686Sbrian
14349434Sbrian  /* The sample period is fixed - see physical2iov() & iov2physical() */
14449434Sbrian  throughput_init(&p->link.throughput, SAMPLE_PERIOD);
14549434Sbrian
14646686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
14746686Sbrian  memset(p->link.proto_in, '\0', sizeof p->link.proto_in);
14846686Sbrian  memset(p->link.proto_out, '\0', sizeof p->link.proto_out);
14946686Sbrian  link_EmptyStack(&p->link);
15046686Sbrian
15146686Sbrian  p->handler = NULL;
15246686Sbrian  p->desc.type = PHYSICAL_DESCRIPTOR;
15346686Sbrian  p->desc.UpdateSet = physical_UpdateSet;
15446686Sbrian  p->desc.IsSet = physical_IsSet;
15546686Sbrian  p->desc.Read = physical_DescriptorRead;
15646686Sbrian  p->desc.Write = physical_DescriptorWrite;
15746686Sbrian  p->type = type;
15846686Sbrian
15946686Sbrian  hdlc_Init(&p->hdlc, &p->link.lcp);
16046686Sbrian  async_Init(&p->async);
16146686Sbrian
16246686Sbrian  p->fd = -1;
16346686Sbrian  p->out = NULL;
16446686Sbrian  p->connect_count = 0;
16546686Sbrian  p->dl = dl;
16646686Sbrian  p->input.sz = 0;
16746686Sbrian  *p->name.full = '\0';
16846686Sbrian  p->name.base = p->name.full;
16946686Sbrian
17046686Sbrian  p->Utmp = 0;
17146686Sbrian  p->session_owner = (pid_t)-1;
17246686Sbrian
17346686Sbrian  p->cfg.rts_cts = MODEM_CTSRTS;
17446686Sbrian  p->cfg.speed = MODEM_SPEED;
17546686Sbrian  p->cfg.parity = CS8;
17646686Sbrian  memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST);
17746686Sbrian  p->cfg.ndev = NMODEMS;
17846686Sbrian  p->cfg.cd.required = 0;
17946686Sbrian  p->cfg.cd.delay = DEF_CDDELAY;
18046686Sbrian
18146686Sbrian  lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp);
18246686Sbrian  ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp);
18346686Sbrian
18446686Sbrian  return p;
18546686Sbrian}
18646686Sbrian
18746686Sbrianstatic const struct parity {
18846686Sbrian  const char *name;
18946686Sbrian  const char *name1;
19046686Sbrian  int set;
19146686Sbrian} validparity[] = {
19246686Sbrian  { "even", "P_EVEN", CS7 | PARENB },
19346686Sbrian  { "odd", "P_ODD", CS7 | PARENB | PARODD },
19446686Sbrian  { "none", "P_ZERO", CS8 },
19546686Sbrian  { NULL, 0 },
19646686Sbrian};
19746686Sbrian
19846686Sbrianstatic int
19946686SbrianGetParityValue(const char *str)
20046686Sbrian{
20146686Sbrian  const struct parity *pp;
20246686Sbrian
20346686Sbrian  for (pp = validparity; pp->name; pp++) {
20446686Sbrian    if (strcasecmp(pp->name, str) == 0 ||
20546686Sbrian	strcasecmp(pp->name1, str) == 0) {
20646686Sbrian      return pp->set;
20746686Sbrian    }
20846686Sbrian  }
20946686Sbrian  return (-1);
21046686Sbrian}
21146686Sbrian
21236285Sbrianint
21346686Sbrianphysical_SetParity(struct physical *p, const char *str)
21446686Sbrian{
21546686Sbrian  struct termios rstio;
21646686Sbrian  int val;
21746686Sbrian
21846686Sbrian  val = GetParityValue(str);
21946686Sbrian  if (val > 0) {
22046686Sbrian    p->cfg.parity = val;
22146686Sbrian    if (p->fd >= 0) {
22246686Sbrian      tcgetattr(p->fd, &rstio);
22346686Sbrian      rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
22446686Sbrian      rstio.c_cflag |= val;
22546686Sbrian      tcsetattr(p->fd, TCSADRAIN, &rstio);
22646686Sbrian    }
22746686Sbrian    return 0;
22846686Sbrian  }
22946686Sbrian  log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str);
23046686Sbrian  return -1;
23136285Sbrian}
23236285Sbrian
23336285Sbrianint
23446686Sbrianphysical_GetSpeed(struct physical *p)
23546686Sbrian{
23646686Sbrian  if (p->handler && p->handler->speed)
23746686Sbrian    return (*p->handler->speed)(p);
23846686Sbrian
23949434Sbrian  return 0;
24036285Sbrian}
24136285Sbrian
24246686Sbrianint
24346686Sbrianphysical_SetSpeed(struct physical *p, int speed)
24436285Sbrian{
24546686Sbrian  if (IntToSpeed(speed) != B0) {
24646686Sbrian      p->cfg.speed = speed;
24746686Sbrian      return 1;
24846686Sbrian  }
24946686Sbrian
25046686Sbrian  return 0;
25136285Sbrian}
25236285Sbrian
25346686Sbrianint
25446686Sbrianphysical_Raw(struct physical *p)
25546686Sbrian{
25646686Sbrian  if (p->handler && p->handler->raw)
25746686Sbrian    return (*p->handler->raw)(p);
25846686Sbrian
25946686Sbrian  return 1;
26046686Sbrian}
26146686Sbrian
26236285Sbrianvoid
26346686Sbrianphysical_Offline(struct physical *p)
26446686Sbrian{
26546686Sbrian  if (p->handler && p->handler->offline)
26646686Sbrian    (*p->handler->offline)(p);
26746686Sbrian  log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name);
26846686Sbrian}
26946686Sbrian
27047286Sbrianstatic int
27147286Sbrianphysical_Lock(struct physical *p)
27246686Sbrian{
27347286Sbrian  int res;
27446686Sbrian
27547286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
27647286Sbrian      (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
27747286Sbrian    if (res == UU_LOCK_INUSE)
27847286Sbrian      log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
27947286Sbrian    else
28047286Sbrian      log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
28147286Sbrian                 p->link.name, p->name.full, uu_lockerr(res));
28247286Sbrian    return 0;
28346686Sbrian  }
28447286Sbrian
28547286Sbrian  return 1;
28646686Sbrian}
28746686Sbrian
28847286Sbrianstatic void
28947286Sbrianphysical_Unlock(struct physical *p)
29047286Sbrian{
29147286Sbrian  char fn[MAXPATHLEN];
29247286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
29347286Sbrian      ID0uu_unlock(p->name.base) == -1)
29447286Sbrian    log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name, fn);
29547286Sbrian}
29647286Sbrian
29746686Sbrianvoid
29846686Sbrianphysical_Close(struct physical *p)
29946686Sbrian{
30047286Sbrian  int newsid;
30147286Sbrian  char fn[MAXPATHLEN];
30247286Sbrian
30346686Sbrian  if (p->fd < 0)
30446686Sbrian    return;
30546686Sbrian
30646686Sbrian  log_Printf(LogDEBUG, "%s: Close\n", p->link.name);
30746686Sbrian
30846686Sbrian  if (p->handler && p->handler->cooked)
30946686Sbrian    (*p->handler->cooked)(p);
31046686Sbrian
31147286Sbrian  physical_StopDeviceTimer(p);
31247286Sbrian  if (p->Utmp) {
31347286Sbrian    ID0logout(p->name.base);
31447286Sbrian    p->Utmp = 0;
31547286Sbrian  }
31647286Sbrian  newsid = tcgetpgrp(p->fd) == getpgrp();
31747286Sbrian  close(p->fd);
31847286Sbrian  p->fd = -1;
31947286Sbrian  log_SetTtyCommandMode(p->dl);
32047286Sbrian
32147286Sbrian  throughput_stop(&p->link.throughput);
32247286Sbrian  throughput_log(&p->link.throughput, LogPHASE, p->link.name);
32347286Sbrian
32447286Sbrian  if (p->session_owner != (pid_t)-1) {
32547286Sbrian    ID0kill(p->session_owner, SIGHUP);
32647286Sbrian    p->session_owner = (pid_t)-1;
32747286Sbrian  }
32847286Sbrian
32947286Sbrian  if (newsid)
33047286Sbrian    bundle_setsid(p->dl->bundle, 0);
33147286Sbrian
33247286Sbrian  if (*p->name.full == '/') {
33347286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
33447286Sbrian#ifndef RELEASE_CRUNCH
33547286Sbrian    if (ID0unlink(fn) == -1)
33647286Sbrian      log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
33747286Sbrian                 p->link.name, fn, strerror(errno));
33847286Sbrian#else
33947286Sbrian    ID0unlink(fn);
34047286Sbrian#endif
34147286Sbrian  }
34247286Sbrian  physical_Unlock(p);
34347286Sbrian  if (p->handler && p->handler->destroy)
34447286Sbrian    (*p->handler->destroy)(p);
34547286Sbrian  p->handler = NULL;
34647286Sbrian  p->name.base = p->name.full;
34747286Sbrian  *p->name.full = '\0';
34846686Sbrian}
34946686Sbrian
35046686Sbrianvoid
35146686Sbrianphysical_Destroy(struct physical *p)
35246686Sbrian{
35346686Sbrian  physical_Close(p);
35449434Sbrian  throughput_destroy(&p->link.throughput);
35546686Sbrian  free(p);
35646686Sbrian}
35746686Sbrian
35846686Sbrianstatic int
35946686Sbrianphysical_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
36046686Sbrian                         const fd_set *fdset)
36146686Sbrian{
36246686Sbrian  struct physical *p = descriptor2physical(d);
36346686Sbrian  int nw, result = 0;
36446686Sbrian
36546686Sbrian  if (p->out == NULL)
36646686Sbrian    p->out = link_Dequeue(&p->link);
36746686Sbrian
36846686Sbrian  if (p->out) {
36946686Sbrian    nw = physical_Write(p, MBUF_CTOP(p->out), p->out->cnt);
37046686Sbrian    log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%d) to %d\n",
37146686Sbrian               p->link.name, nw, p->out->cnt, p->fd);
37246686Sbrian    if (nw > 0) {
37346686Sbrian      p->out->cnt -= nw;
37446686Sbrian      p->out->offset += nw;
37546686Sbrian      if (p->out->cnt == 0)
37646686Sbrian	p->out = mbuf_FreeSeg(p->out);
37746686Sbrian      result = 1;
37846686Sbrian    } else if (nw < 0) {
37946686Sbrian      if (errno != EAGAIN) {
38046686Sbrian	log_Printf(LogPHASE, "%s: write (%d): %s\n", p->link.name,
38146686Sbrian                   p->fd, strerror(errno));
38246686Sbrian        datalink_Down(p->dl, CLOSE_NORMAL);
38346686Sbrian      }
38446686Sbrian      result = 1;
38546686Sbrian    }
38646686Sbrian    /* else we shouldn't really have been called !  select() is broken ! */
38746686Sbrian  }
38846686Sbrian
38946686Sbrian  return result;
39046686Sbrian}
39146686Sbrian
39246686Sbrianint
39346686Sbrianphysical_ShowStatus(struct cmdargs const *arg)
39446686Sbrian{
39546686Sbrian  struct physical *p = arg->cx->physical;
39646686Sbrian  const char *dev;
39746686Sbrian  int n;
39846686Sbrian
39946686Sbrian  prompt_Printf(arg->prompt, "Name: %s\n", p->link.name);
40046686Sbrian  prompt_Printf(arg->prompt, " State:           ");
40146686Sbrian  if (p->fd < 0)
40246686Sbrian    prompt_Printf(arg->prompt, "closed\n");
40346686Sbrian  else if (p->handler && p->handler->openinfo)
40446686Sbrian    prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
40546686Sbrian  else
40646686Sbrian    prompt_Printf(arg->prompt, "open\n");
40746686Sbrian
40846686Sbrian  prompt_Printf(arg->prompt, " Device:          %s",
40946686Sbrian                *p->name.full ?  p->name.full :
41046686Sbrian                p->type == PHYS_DIRECT ? "unknown" : "N/A");
41146686Sbrian  if (p->session_owner != (pid_t)-1)
41246686Sbrian    prompt_Printf(arg->prompt, " (session owner: %d)", (int)p->session_owner);
41346686Sbrian
41446686Sbrian  prompt_Printf(arg->prompt, "\n Link Type:       %s\n", mode2Nam(p->type));
41546686Sbrian  prompt_Printf(arg->prompt, " Connect Count:   %d\n", p->connect_count);
41646686Sbrian#ifdef TIOCOUTQ
41746686Sbrian  if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
41846686Sbrian      prompt_Printf(arg->prompt, " Physical outq:   %d\n", n);
41946686Sbrian#endif
42046686Sbrian
42146686Sbrian  prompt_Printf(arg->prompt, " Queued Packets:  %d\n",
42246686Sbrian                link_QueueLen(&p->link));
42346686Sbrian  prompt_Printf(arg->prompt, " Phone Number:    %s\n", arg->cx->phone.chosen);
42446686Sbrian
42546686Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
42646686Sbrian
42746686Sbrian  prompt_Printf(arg->prompt, " Device List:     ");
42846686Sbrian  dev = p->cfg.devlist;
42946686Sbrian  for (n = 0; n < p->cfg.ndev; n++) {
43046686Sbrian    if (n)
43146686Sbrian      prompt_Printf(arg->prompt, ", ");
43246686Sbrian    prompt_Printf(arg->prompt, "\"%s\"", dev);
43346686Sbrian    dev += strlen(dev) + 1;
43446686Sbrian  }
43546686Sbrian
43646686Sbrian  prompt_Printf(arg->prompt, "\n Characteristics: ");
43746686Sbrian  if (physical_IsSync(arg->cx->physical))
43846686Sbrian    prompt_Printf(arg->prompt, "sync");
43946686Sbrian  else
44046686Sbrian    prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
44146686Sbrian
44246686Sbrian  switch (p->cfg.parity & CSIZE) {
44346686Sbrian  case CS7:
44446686Sbrian    prompt_Printf(arg->prompt, ", cs7");
44546686Sbrian    break;
44646686Sbrian  case CS8:
44746686Sbrian    prompt_Printf(arg->prompt, ", cs8");
44846686Sbrian    break;
44946686Sbrian  }
45046686Sbrian  if (p->cfg.parity & PARENB) {
45146686Sbrian    if (p->cfg.parity & PARODD)
45246686Sbrian      prompt_Printf(arg->prompt, ", odd parity");
45346686Sbrian    else
45446686Sbrian      prompt_Printf(arg->prompt, ", even parity");
45546686Sbrian  } else
45646686Sbrian    prompt_Printf(arg->prompt, ", no parity");
45746686Sbrian
45846686Sbrian  prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
45946686Sbrian
46046686Sbrian  prompt_Printf(arg->prompt, " CD check delay:  %d second%s",
46146686Sbrian                p->cfg.cd.delay, p->cfg.cd.delay == 1 ? "" : "s");
46246686Sbrian  if (p->cfg.cd.required)
46346686Sbrian    prompt_Printf(arg->prompt, " (required!)\n\n");
46446686Sbrian  else
46546686Sbrian    prompt_Printf(arg->prompt, "\n\n");
46646686Sbrian
46746686Sbrian  throughput_disp(&p->link.throughput, arg->prompt);
46846686Sbrian
46946686Sbrian  return 0;
47046686Sbrian}
47146686Sbrian
47246686Sbrianstatic void
47346686Sbrianphysical_DescriptorRead(struct descriptor *d, struct bundle *bundle,
47446686Sbrian                     const fd_set *fdset)
47546686Sbrian{
47646686Sbrian  struct physical *p = descriptor2physical(d);
47746686Sbrian  u_char *rbuff;
47846686Sbrian  int n, found;
47946686Sbrian
48046686Sbrian  rbuff = p->input.buf + p->input.sz;
48146686Sbrian
48246686Sbrian  /* something to read */
48346686Sbrian  n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
48446686Sbrian  log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
48546686Sbrian             p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
48646686Sbrian  if (n <= 0) {
48746686Sbrian    if (n < 0)
48846686Sbrian      log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
48946686Sbrian                 strerror(errno));
49046686Sbrian    else
49146686Sbrian      log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
49246686Sbrian                 p->link.name, p->fd);
49346686Sbrian    datalink_Down(p->dl, CLOSE_NORMAL);
49446686Sbrian    return;
49546686Sbrian  }
49646686Sbrian
49746686Sbrian  rbuff -= p->input.sz;
49846686Sbrian  n += p->input.sz;
49946686Sbrian
50046686Sbrian  if (p->link.lcp.fsm.state <= ST_CLOSED) {
50146686Sbrian    if (p->type != PHYS_DEDICATED) {
50246686Sbrian      found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
50346686Sbrian      if (rbuff != p->input.buf)
50446686Sbrian        log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
50546686Sbrian                         p->input.buf);
50646686Sbrian      p->input.sz = n - (rbuff - p->input.buf);
50746686Sbrian
50846686Sbrian      if (found) {
50946686Sbrian        /* LCP packet is detected. Turn ourselves into packet mode */
51046686Sbrian        log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
51146686Sbrian                   p->link.name);
51246686Sbrian        log_SetTtyCommandMode(p->dl);
51346686Sbrian        datalink_Up(p->dl, 0, 1);
51446686Sbrian        link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
51546686Sbrian        p->input.sz = 0;
51646686Sbrian      } else
51746686Sbrian        bcopy(rbuff, p->input.buf, p->input.sz);
51846686Sbrian    } else
51946686Sbrian      /* In -dedicated mode, we just discard input until LCP is started */
52046686Sbrian      p->input.sz = 0;
52146686Sbrian  } else if (n > 0)
52246686Sbrian    link_PullPacket(&p->link, rbuff, n, bundle);
52346686Sbrian}
52446686Sbrian
52546686Sbrianstruct physical *
52646686Sbrianiov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
52746686Sbrian             int fd)
52846686Sbrian{
52946686Sbrian  struct physical *p;
53047061Sbrian  int len, h, type;
53146686Sbrian
53246686Sbrian  p = (struct physical *)iov[(*niov)++].iov_base;
53346686Sbrian  p->link.name = dl->name;
53446686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
53546686Sbrian
53646686Sbrian  p->desc.UpdateSet = physical_UpdateSet;
53746686Sbrian  p->desc.IsSet = physical_IsSet;
53846686Sbrian  p->desc.Read = physical_DescriptorRead;
53946686Sbrian  p->desc.Write = physical_DescriptorWrite;
54046686Sbrian  p->type = PHYS_DIRECT;
54146686Sbrian  p->dl = dl;
54246686Sbrian  len = strlen(_PATH_DEV);
54346686Sbrian  p->out = NULL;
54446686Sbrian  p->connect_count = 1;
54546686Sbrian
54647682Sbrian  physical_SetDevice(p, p->name.full);
54747682Sbrian
54846686Sbrian  p->link.lcp.fsm.bundle = dl->bundle;
54946686Sbrian  p->link.lcp.fsm.link = &p->link;
55046686Sbrian  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
55146686Sbrian  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
55246686Sbrian  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
55346686Sbrian         sizeof p->link.lcp.fsm.StoppedTimer);
55446686Sbrian  p->link.lcp.fsm.parent = &dl->fsmp;
55546686Sbrian  lcp_SetupCallbacks(&p->link.lcp);
55646686Sbrian
55746686Sbrian  p->link.ccp.fsm.bundle = dl->bundle;
55846686Sbrian  p->link.ccp.fsm.link = &p->link;
55946686Sbrian  /* Our in.state & out.state are NULL (no link-level ccp yet) */
56046686Sbrian  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
56146686Sbrian  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
56246686Sbrian  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
56346686Sbrian         sizeof p->link.ccp.fsm.StoppedTimer);
56446686Sbrian  p->link.ccp.fsm.parent = &dl->fsmp;
56546686Sbrian  ccp_SetupCallbacks(&p->link.ccp);
56646686Sbrian
56746686Sbrian  p->hdlc.lqm.owner = &p->link.lcp;
56846686Sbrian  p->hdlc.ReportTimer.state = TIMER_STOPPED;
56946686Sbrian  p->hdlc.lqm.timer.state = TIMER_STOPPED;
57046686Sbrian
57146686Sbrian  p->fd = fd;
57249434Sbrian  p->link.throughput.SampleOctets = (long long *)iov[(*niov)++].iov_base;
57346686Sbrian
57447769Sbrian  type = (long)p->handler;
57547769Sbrian  p->handler = NULL;
57647769Sbrian  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
57747769Sbrian    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov);
57847769Sbrian
57947769Sbrian  if (p->handler == NULL) {
58047769Sbrian    log_Printf(LogPHASE, "%s: Device %s, unknown link type\n",
58147769Sbrian               p->link.name, p->name.full);
58247769Sbrian    free(iov[(*niov)++].iov_base);
58347769Sbrian    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
58447769Sbrian  } else
58547769Sbrian    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
58647769Sbrian               p->link.name, p->name.full, p->handler->name);
58747769Sbrian
58846686Sbrian  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
58946686Sbrian    lqr_reStart(&p->link.lcp);
59046686Sbrian  hdlc_StartTimer(&p->hdlc);
59146686Sbrian
59249434Sbrian  throughput_restart(&p->link.throughput, "physical throughput",
59349434Sbrian                     Enabled(dl->bundle, OPT_THROUGHPUT));
59446686Sbrian
59547769Sbrian  return p;
59647769Sbrian}
59747061Sbrian
59847769Sbrianint
59947769Sbrianphysical_MaxDeviceSize()
60047769Sbrian{
60147769Sbrian  int biggest, sz, n;
60247061Sbrian
60347769Sbrian  biggest = sizeof(struct device);
60447769Sbrian  for (sz = n = 0; n < NDEVICES; n++)
60547769Sbrian    if (devices[n].DeviceSize) {
60647769Sbrian      sz = (*devices[n].DeviceSize)();
60747769Sbrian      if (biggest < sz)
60847769Sbrian        biggest = sz;
60947769Sbrian    }
61047769Sbrian
61147769Sbrian  return biggest;
61246686Sbrian}
61346686Sbrian
61446686Sbrianint
61546686Sbrianphysical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
61646686Sbrian             pid_t newpid)
61746686Sbrian{
61847769Sbrian  struct device *h;
61947769Sbrian  int sz;
62047769Sbrian
62147769Sbrian  h = NULL;
62246686Sbrian  if (p) {
62346686Sbrian    hdlc_StopTimer(&p->hdlc);
62446686Sbrian    lqr_StopTimer(p);
62546686Sbrian    timer_Stop(&p->link.lcp.fsm.FsmTimer);
62646686Sbrian    timer_Stop(&p->link.ccp.fsm.FsmTimer);
62746686Sbrian    timer_Stop(&p->link.lcp.fsm.OpenTimer);
62846686Sbrian    timer_Stop(&p->link.ccp.fsm.OpenTimer);
62946686Sbrian    timer_Stop(&p->link.lcp.fsm.StoppedTimer);
63046686Sbrian    timer_Stop(&p->link.ccp.fsm.StoppedTimer);
63147061Sbrian    if (p->handler) {
63247061Sbrian      if (p->handler->device2iov)
63347769Sbrian        h = p->handler;
63447061Sbrian      p->handler = (struct device *)(long)p->handler->type;
63546686Sbrian    }
63647061Sbrian
63747689Sbrian    if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
63847689Sbrian        tcgetpgrp(p->fd) == getpgrp())
63946686Sbrian      p->session_owner = getpid();      /* So I'll eventually get HUP'd */
64047689Sbrian    else
64147689Sbrian      p->session_owner = (pid_t)-1;
64246686Sbrian    timer_Stop(&p->link.throughput.Timer);
64346686Sbrian    physical_ChangedPid(p, newpid);
64446686Sbrian  }
64546686Sbrian
64649434Sbrian  if (*niov + 2 >= maxiov) {
64749434Sbrian    log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
64849434Sbrian               " + device !\n");
64946686Sbrian    if (p)
65046686Sbrian      free(p);
65146686Sbrian    return -1;
65246686Sbrian  }
65346686Sbrian
65447769Sbrian  iov[*niov].iov_base = p ? (void *)p : malloc(sizeof *p);
65546686Sbrian  iov[*niov].iov_len = sizeof *p;
65646686Sbrian  (*niov)++;
65746686Sbrian
65849434Sbrian  iov[*niov].iov_base = p ? (void *)p->link.throughput.SampleOctets :
65949434Sbrian                            malloc(SAMPLE_PERIOD * sizeof(long long));
66049434Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
66149434Sbrian  (*niov)++;
66249434Sbrian
66347769Sbrian  sz = physical_MaxDeviceSize();
66447769Sbrian  if (p) {
66547769Sbrian    if (h)
66647769Sbrian      (*h->device2iov)(h, iov, niov, maxiov, newpid);
66747769Sbrian    else {
66847769Sbrian      iov[*niov].iov_base = malloc(sz);
66947769Sbrian      if (p->handler)
67047769Sbrian        memcpy(iov[*niov].iov_base, p->handler, sizeof *p->handler);
67147769Sbrian      iov[*niov].iov_len = sz;
67247769Sbrian      (*niov)++;
67347769Sbrian    }
67447769Sbrian  } else {
67547769Sbrian    iov[*niov].iov_base = malloc(sz);
67647769Sbrian    iov[*niov].iov_len = sz;
67747769Sbrian    (*niov)++;
67847769Sbrian  }
67947769Sbrian
68046686Sbrian  return p ? p->fd : 0;
68146686Sbrian}
68246686Sbrian
68346686Sbrianvoid
68446686Sbrianphysical_ChangedPid(struct physical *p, pid_t newpid)
68546686Sbrian{
68647689Sbrian  if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT) {
68746686Sbrian    int res;
68846686Sbrian
68946686Sbrian    if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
69046686Sbrian      log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
69146686Sbrian  }
69246686Sbrian}
69346686Sbrian
69446686Sbrianint
69546686Sbrianphysical_IsSync(struct physical *p)
69646686Sbrian{
69746686Sbrian   return p->cfg.speed == 0;
69846686Sbrian}
69946686Sbrian
70046686Sbrianconst char *physical_GetDevice(struct physical *p)
70146686Sbrian{
70246686Sbrian   return p->name.full;
70346686Sbrian}
70446686Sbrian
70546686Sbrianvoid
70636285Sbrianphysical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
70736285Sbrian{
70836285Sbrian  int f, pos;
70936285Sbrian
71036285Sbrian  p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
71136285Sbrian  for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
71236285Sbrian    if (pos)
71346102Sbrian      p->cfg.devlist[pos++] = '\0';
71436285Sbrian    strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
71536285Sbrian    pos += strlen(p->cfg.devlist + pos);
71636285Sbrian  }
71746102Sbrian  p->cfg.ndev = f;
71836285Sbrian}
71936285Sbrian
72036285Sbrianvoid
72146686Sbrianphysical_SetSync(struct physical *p)
72246686Sbrian{
72346686Sbrian   p->cfg.speed = 0;
72436285Sbrian}
72536285Sbrian
72636285Sbrianint
72746686Sbrianphysical_SetRtsCts(struct physical *p, int enable)
72846686Sbrian{
72946686Sbrian   p->cfg.rts_cts = enable ? 1 : 0;
73036285Sbrian   return 1;
73136285Sbrian}
73236285Sbrian
73336285Sbrianssize_t
73446686Sbrianphysical_Read(struct physical *p, void *buf, size_t nbytes)
73546686Sbrian{
73647061Sbrian  ssize_t ret;
73747061Sbrian
73847061Sbrian  if (p->handler && p->handler->read)
73947061Sbrian    ret = (*p->handler->read)(p, buf, nbytes);
74047061Sbrian  else
74147061Sbrian    ret = read(p->fd, buf, nbytes);
74247061Sbrian
74347061Sbrian  log_DumpBuff(LogPHYSICAL, "read", buf, ret);
74447061Sbrian
74547061Sbrian  return ret;
74636285Sbrian}
74736285Sbrian
74836285Sbrianssize_t
74946686Sbrianphysical_Write(struct physical *p, const void *buf, size_t nbytes)
75046686Sbrian{
75147061Sbrian  log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
75247061Sbrian
75347061Sbrian  if (p->handler && p->handler->write)
75447061Sbrian    return (*p->handler->write)(p, buf, nbytes);
75547061Sbrian
75647061Sbrian  return write(p->fd, buf, nbytes);
75736285Sbrian}
75836285Sbrian
75936285Sbrianint
76046686Sbrianphysical_doUpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
76146686Sbrian                     int *n, int force)
76236285Sbrian{
76336285Sbrian  struct physical *p = descriptor2physical(d);
76436285Sbrian  int sets;
76536285Sbrian
76636285Sbrian  sets = 0;
76736285Sbrian  if (p->fd >= 0) {
76836285Sbrian    if (r) {
76936285Sbrian      FD_SET(p->fd, r);
77036285Sbrian      log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
77136285Sbrian      sets++;
77236285Sbrian    }
77336285Sbrian    if (e) {
77436285Sbrian      FD_SET(p->fd, e);
77536285Sbrian      log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
77636285Sbrian      sets++;
77736285Sbrian    }
77836314Sbrian    if (w && (force || link_QueueLen(&p->link) || p->out)) {
77936285Sbrian      FD_SET(p->fd, w);
78036285Sbrian      log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
78136285Sbrian      sets++;
78236285Sbrian    }
78336285Sbrian    if (sets && *n < p->fd + 1)
78436285Sbrian      *n = p->fd + 1;
78536285Sbrian  }
78636285Sbrian
78736285Sbrian  return sets;
78836285Sbrian}
78936285Sbrian
79036285Sbrianint
79136285Sbrianphysical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
79236285Sbrian{
79336285Sbrian  int sets;
79436285Sbrian
79536285Sbrian  sets = 0;
79636285Sbrian  if (p->fd >= 0) {
79736285Sbrian    if (r && FD_ISSET(p->fd, r)) {
79836285Sbrian      FD_CLR(p->fd, r);
79936285Sbrian      log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
80036285Sbrian      sets++;
80136285Sbrian    }
80236285Sbrian    if (e && FD_ISSET(p->fd, e)) {
80336285Sbrian      FD_CLR(p->fd, e);
80436285Sbrian      log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
80536285Sbrian      sets++;
80636285Sbrian    }
80736285Sbrian    if (w && FD_ISSET(p->fd, w)) {
80836285Sbrian      FD_CLR(p->fd, w);
80936285Sbrian      log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
81036285Sbrian      sets++;
81136285Sbrian    }
81236285Sbrian  }
81336285Sbrian
81436285Sbrian  return sets;
81536285Sbrian}
81636285Sbrian
81736285Sbrianint
81836285Sbrianphysical_IsSet(struct descriptor *d, const fd_set *fdset)
81936285Sbrian{
82036285Sbrian  struct physical *p = descriptor2physical(d);
82136285Sbrian  return p->fd >= 0 && FD_ISSET(p->fd, fdset);
82236285Sbrian}
82336285Sbrian
82436285Sbrianvoid
82546686Sbrianphysical_Login(struct physical *p, const char *name)
82636285Sbrian{
82746830Sbrian  if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
82846686Sbrian    struct utmp ut;
82946686Sbrian    const char *connstr;
83036285Sbrian
83146686Sbrian    memset(&ut, 0, sizeof ut);
83246686Sbrian    time(&ut.ut_time);
83346686Sbrian    strncpy(ut.ut_name, name, sizeof ut.ut_name);
83446686Sbrian    strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
83546686Sbrian    if ((connstr = getenv("CONNECT")))
83646686Sbrian      /* mgetty sets this to the connection speed */
83746686Sbrian      strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
83846686Sbrian    ID0login(&ut);
83946686Sbrian    p->Utmp = 1;
84036285Sbrian  }
84136285Sbrian}
84236285Sbrian
84336285Sbrianint
84436285Sbrianphysical_SetMode(struct physical *p, int mode)
84536285Sbrian{
84638174Sbrian  if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
84738174Sbrian       mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
84838174Sbrian      (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
84936285Sbrian    log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
85036285Sbrian               mode2Nam(p->type), mode2Nam(mode));
85136285Sbrian    return 0;
85236285Sbrian  }
85336285Sbrian  p->type = mode;
85436285Sbrian  return 1;
85536285Sbrian}
85638544Sbrian
85738544Sbrianvoid
85838544Sbrianphysical_DeleteQueue(struct physical *p)
85938544Sbrian{
86038544Sbrian  if (p->out) {
86138544Sbrian    mbuf_Free(p->out);
86238544Sbrian    p->out = NULL;
86338544Sbrian  }
86438544Sbrian  link_DeleteQueue(&p->link);
86538544Sbrian}
86646686Sbrian
86746686Sbrianvoid
86846686Sbrianphysical_SetDevice(struct physical *p, const char *name)
86946686Sbrian{
87046686Sbrian  int len = strlen(_PATH_DEV);
87146686Sbrian
87247682Sbrian  if (name != p->name.full) {
87347682Sbrian    strncpy(p->name.full, name, sizeof p->name.full - 1);
87447682Sbrian    p->name.full[sizeof p->name.full - 1] = '\0';
87547682Sbrian  }
87646686Sbrian  p->name.base = *p->name.full == '!' ?  p->name.full + 1 :
87746686Sbrian                 strncmp(p->name.full, _PATH_DEV, len) ?
87846686Sbrian                 p->name.full : p->name.full + len;
87946686Sbrian}
88046686Sbrian
88146686Sbrianstatic void
88246686Sbrianphysical_Found(struct physical *p)
88346686Sbrian{
88447286Sbrian  FILE *lockfile;
88547286Sbrian  char fn[MAXPATHLEN];
88647286Sbrian
88747286Sbrian  if (*p->name.full == '/') {
88847286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
88947286Sbrian    lockfile = ID0fopen(fn, "w");
89047286Sbrian    if (lockfile != NULL) {
89147286Sbrian      fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
89247286Sbrian      fclose(lockfile);
89347286Sbrian    }
89447286Sbrian#ifndef RELEASE_CRUNCH
89547286Sbrian    else
89647286Sbrian      log_Printf(LogALERT, "%s: Can't create %s: %s\n",
89747286Sbrian                 p->link.name, fn, strerror(errno));
89847286Sbrian#endif
89947286Sbrian  }
90047286Sbrian
90146686Sbrian  throughput_start(&p->link.throughput, "physical throughput",
90246686Sbrian                   Enabled(p->dl->bundle, OPT_THROUGHPUT));
90346686Sbrian  p->connect_count++;
90446686Sbrian  p->input.sz = 0;
90546686Sbrian
90646686Sbrian  log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
90746686Sbrian}
90846686Sbrian
90946686Sbrianint
91046686Sbrianphysical_Open(struct physical *p, struct bundle *bundle)
91146686Sbrian{
91247878Sbrian  int devno, h, wasopen, err;
91346686Sbrian  char *dev;
91446686Sbrian
91546686Sbrian  if (p->fd >= 0)
91646686Sbrian    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
91746686Sbrian    /* We're going back into "term" mode */
91846686Sbrian  else if (p->type == PHYS_DIRECT) {
91947061Sbrian    physical_SetDevice(p, "");
92047061Sbrian    p->fd = STDIN_FILENO;
92147061Sbrian    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
92247061Sbrian        p->handler = (*devices[h].create)(p);
92347061Sbrian    if (p->fd >= 0) {
92447124Sbrian      if (p->handler == NULL) {
92547461Sbrian        physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
92647124Sbrian        log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
92747124Sbrian      }
92846686Sbrian      physical_Found(p);
92946686Sbrian    }
93046686Sbrian  } else {
93146686Sbrian    dev = p->cfg.devlist;
93246686Sbrian    devno = 0;
93346686Sbrian    while (devno < p->cfg.ndev && p->fd < 0) {
93446686Sbrian      physical_SetDevice(p, dev);
93547286Sbrian      if (physical_Lock(p)) {
93647878Sbrian        err = 0;
93747878Sbrian
93847878Sbrian        if (*p->name.full == '/') {
93947286Sbrian          p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
94047878Sbrian          if (p->fd < 0)
94147878Sbrian            err = errno;
94247878Sbrian        }
94346686Sbrian
94447286Sbrian        wasopen = p->fd >= 0;
94547286Sbrian        for (h = 0; h < NDEVICES && p->handler == NULL; h++)
94647286Sbrian          if ((p->handler = (*devices[h].create)(p)) == NULL &&
94747286Sbrian              wasopen && p->fd == -1)
94847286Sbrian            break;
94946686Sbrian
95047286Sbrian        if (p->fd < 0) {
95147878Sbrian          if (h == NDEVICES) {
95247878Sbrian            if (err)
95347878Sbrian	      log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
95447878Sbrian                         strerror(errno));
95547878Sbrian            else
95647878Sbrian	      log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
95747878Sbrian                         " a '!' or be a host:port pair\n", p->link.name,
95847878Sbrian                         p->name.full);
95947878Sbrian          }
96047286Sbrian          physical_Unlock(p);
96147286Sbrian        } else
96247286Sbrian          physical_Found(p);
96347286Sbrian      }
96446686Sbrian      dev += strlen(dev) + 1;
96546686Sbrian      devno++;
96646686Sbrian    }
96746686Sbrian  }
96846686Sbrian
96946686Sbrian  return p->fd;
97046686Sbrian}
97146686Sbrian
97246686Sbrianvoid
97347461Sbrianphysical_SetupStack(struct physical *p, const char *who, int how)
97446686Sbrian{
97546686Sbrian  link_EmptyStack(&p->link);
97647061Sbrian  if (how == PHYSICAL_FORCE_SYNC ||
97747061Sbrian      (how == PHYSICAL_NOFORCE && physical_IsSync(p)))
97846686Sbrian    link_Stack(&p->link, &synclayer);
97946686Sbrian  else {
98046686Sbrian    link_Stack(&p->link, &asynclayer);
98146686Sbrian    link_Stack(&p->link, &hdlclayer);
98246686Sbrian  }
98346686Sbrian  link_Stack(&p->link, &acflayer);
98446686Sbrian  link_Stack(&p->link, &protolayer);
98546686Sbrian  link_Stack(&p->link, &lqrlayer);
98646686Sbrian  link_Stack(&p->link, &ccplayer);
98746686Sbrian  link_Stack(&p->link, &vjlayer);
98850059Sbrian#ifndef NONAT
98950059Sbrian  link_Stack(&p->link, &natlayer);
99046686Sbrian#endif
99147061Sbrian  if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) {
99247461Sbrian    log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who);
99347061Sbrian    p->cfg.speed = MODEM_SPEED;
99447061Sbrian  } else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) {
99547061Sbrian    log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n",
99647461Sbrian               who);
99747061Sbrian    physical_SetSync(p);
99847061Sbrian  }
99946686Sbrian}
100047061Sbrian
100147061Sbrianvoid
100247061Sbrianphysical_StopDeviceTimer(struct physical *p)
100347061Sbrian{
100447061Sbrian  if (p->handler && p->handler->stoptimer)
100547061Sbrian    (*p->handler->stoptimer)(p);
100647061Sbrian}
100749472Sbrian
100849472Sbrianint
100949472Sbrianphysical_AwaitCarrier(struct physical *p)
101049472Sbrian{
101149472Sbrian  if (p->handler && p->handler->awaitcarrier)
101249472Sbrian    return (*p->handler->awaitcarrier)(p);
101349472Sbrian
101449472Sbrian  return CARRIER_OK;
101549472Sbrian}
1016