physical.c revision 78410
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 78410 2001-06-18 14:59:36Z 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>
3264802Sbrian#ifdef NOSUID
3364802Sbrian#include <signal.h>
3464802Sbrian#endif
3536285Sbrian#include <stdio.h>
3636285Sbrian#include <stdlib.h>
3736285Sbrian#include <string.h>
3846686Sbrian#include <sys/tty.h>	/* TIOCOUTQ */
3946686Sbrian#include <sys/uio.h>
4036285Sbrian#include <time.h>
4136285Sbrian#include <unistd.h>
4236285Sbrian#include <utmp.h>
4346686Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__)
4446686Sbrian#include <sys/ioctl.h>
4546686Sbrian#include <util.h>
4646686Sbrian#else
4746686Sbrian#include <libutil.h>
4846686Sbrian#endif
4936285Sbrian
5046686Sbrian#include "layer.h"
5150059Sbrian#ifndef NONAT
5251075Sbrian#include "nat_cmd.h"
5346686Sbrian#endif
5446686Sbrian#include "proto.h"
5546686Sbrian#include "acf.h"
5646686Sbrian#include "vjcomp.h"
5736285Sbrian#include "defs.h"
5846686Sbrian#include "command.h"
5936285Sbrian#include "mbuf.h"
6046686Sbrian#include "log.h"
6146686Sbrian#include "id.h"
6236285Sbrian#include "timer.h"
6346686Sbrian#include "fsm.h"
6436285Sbrian#include "lqr.h"
6536285Sbrian#include "hdlc.h"
6646686Sbrian#include "lcp.h"
6736285Sbrian#include "throughput.h"
6846686Sbrian#include "sync.h"
6936285Sbrian#include "async.h"
7046686Sbrian#include "iplist.h"
7146686Sbrian#include "slcompress.h"
7246686Sbrian#include "ipcp.h"
7346686Sbrian#include "filter.h"
7446686Sbrian#include "descriptor.h"
7536285Sbrian#include "ccp.h"
7636285Sbrian#include "link.h"
7736285Sbrian#include "physical.h"
7846686Sbrian#include "mp.h"
7946686Sbrian#ifndef NORADIUS
8046686Sbrian#include "radius.h"
8146686Sbrian#endif
8246686Sbrian#include "bundle.h"
8346686Sbrian#include "prompt.h"
8446686Sbrian#include "chat.h"
8546686Sbrian#include "auth.h"
8646686Sbrian#include "chap.h"
8746686Sbrian#include "cbcp.h"
8846686Sbrian#include "datalink.h"
8946686Sbrian#include "tcp.h"
9047061Sbrian#include "udp.h"
9146686Sbrian#include "exec.h"
9246686Sbrian#include "tty.h"
9349472Sbrian#ifndef NOI4B
9449472Sbrian#include "i4b.h"
9549472Sbrian#endif
9652942Sbrian#ifndef NONETGRAPH
9752942Sbrian#include "ether.h"
9852942Sbrian#endif
9965862Sbrian#ifndef NOATM
10065862Sbrian#include "atm.h"
10165862Sbrian#endif
10269303Sbrian#include "tcpmss.h"
10336285Sbrian
10452429Sbrian#define PPPOTCPLINE "ppp"
10552429Sbrian
10658028Sbrianstatic int physical_DescriptorWrite(struct fdescriptor *, struct bundle *,
10746686Sbrian                                    const fd_set *);
10836285Sbrian
10947769Sbrianstatic int
11047769Sbrianphysical_DeviceSize(void)
11147769Sbrian{
11247769Sbrian  return sizeof(struct device);
11347769Sbrian}
11447769Sbrian
11547061Sbrianstruct {
11647061Sbrian  struct device *(*create)(struct physical *);
11752942Sbrian  struct device *(*iov2device)(int, struct physical *, struct iovec *,
11852942Sbrian                               int *, int, int *, int *);
11947769Sbrian  int (*DeviceSize)(void);
12047061Sbrian} devices[] = {
12149472Sbrian#ifndef NOI4B
12271006Sbrian  /*
12371006Sbrian   * This must come before ``tty'' so that the probe routine is
12471006Sbrian   * able to identify it as a more specific type of terminal device.
12571006Sbrian   */
12649472Sbrian  { i4b_Create, i4b_iov2device, i4b_DeviceSize },
12749472Sbrian#endif
12847769Sbrian  { tty_Create, tty_iov2device, tty_DeviceSize },
12952942Sbrian#ifndef NONETGRAPH
13071006Sbrian  /*
13171006Sbrian   * This must come before ``udp'' so that the probe routine is
13271006Sbrian   * able to identify it as a more specific type of SOCK_DGRAM.
13371006Sbrian   */
13452942Sbrian  { ether_Create, ether_iov2device, ether_DeviceSize },
13552942Sbrian#endif
13665862Sbrian#ifndef NOATM
13771006Sbrian  /* Ditto for ATM devices */
13865862Sbrian  { atm_Create, atm_iov2device, atm_DeviceSize },
13965862Sbrian#endif
14047769Sbrian  { tcp_Create, tcp_iov2device, tcp_DeviceSize },
14147769Sbrian  { udp_Create, udp_iov2device, udp_DeviceSize },
14247769Sbrian  { exec_Create, exec_iov2device, exec_DeviceSize }
14346686Sbrian};
14446686Sbrian
14547061Sbrian#define NDEVICES (sizeof devices / sizeof devices[0])
14646686Sbrian
14746686Sbrianstatic int
14858028Sbrianphysical_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
14946686Sbrian                   int *n)
15046686Sbrian{
15146686Sbrian  return physical_doUpdateSet(d, r, w, e, n, 0);
15246686Sbrian}
15346686Sbrian
15452942Sbrianvoid
15552942Sbrianphysical_SetDescriptor(struct physical *p)
15652942Sbrian{
15752942Sbrian  p->desc.type = PHYSICAL_DESCRIPTOR;
15852942Sbrian  p->desc.UpdateSet = physical_UpdateSet;
15952942Sbrian  p->desc.IsSet = physical_IsSet;
16052942Sbrian  p->desc.Read = physical_DescriptorRead;
16152942Sbrian  p->desc.Write = physical_DescriptorWrite;
16252942Sbrian}
16352942Sbrian
16446686Sbrianstruct physical *
16546686Sbrianphysical_Create(struct datalink *dl, int type)
16646686Sbrian{
16746686Sbrian  struct physical *p;
16846686Sbrian
16946686Sbrian  p = (struct physical *)malloc(sizeof(struct physical));
17046686Sbrian  if (!p)
17146686Sbrian    return NULL;
17246686Sbrian
17346686Sbrian  p->link.type = PHYSICAL_LINK;
17446686Sbrian  p->link.name = dl->name;
17546686Sbrian  p->link.len = sizeof *p;
17646686Sbrian
17749434Sbrian  /* The sample period is fixed - see physical2iov() & iov2physical() */
17864652Sbrian  throughput_init(&p->link.stats.total, SAMPLE_PERIOD);
17964652Sbrian  p->link.stats.parent = dl->bundle->ncp.mp.active ?
18064652Sbrian    &dl->bundle->ncp.mp.link.stats.total : NULL;
18164652Sbrian  p->link.stats.gather = 1;
18249434Sbrian
18346686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
18446686Sbrian  memset(p->link.proto_in, '\0', sizeof p->link.proto_in);
18546686Sbrian  memset(p->link.proto_out, '\0', sizeof p->link.proto_out);
18646686Sbrian  link_EmptyStack(&p->link);
18746686Sbrian
18846686Sbrian  p->handler = NULL;
18952942Sbrian  physical_SetDescriptor(p);
19046686Sbrian  p->type = type;
19146686Sbrian
19246686Sbrian  hdlc_Init(&p->hdlc, &p->link.lcp);
19346686Sbrian  async_Init(&p->async);
19446686Sbrian
19546686Sbrian  p->fd = -1;
19646686Sbrian  p->out = NULL;
19746686Sbrian  p->connect_count = 0;
19846686Sbrian  p->dl = dl;
19946686Sbrian  p->input.sz = 0;
20046686Sbrian  *p->name.full = '\0';
20146686Sbrian  p->name.base = p->name.full;
20246686Sbrian
20346686Sbrian  p->Utmp = 0;
20446686Sbrian  p->session_owner = (pid_t)-1;
20546686Sbrian
20646686Sbrian  p->cfg.rts_cts = MODEM_CTSRTS;
20746686Sbrian  p->cfg.speed = MODEM_SPEED;
20846686Sbrian  p->cfg.parity = CS8;
20946686Sbrian  memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST);
21046686Sbrian  p->cfg.ndev = NMODEMS;
21153733Sbrian  p->cfg.cd.necessity = CD_DEFAULT;
21253733Sbrian  p->cfg.cd.delay = 0;		/* reconfigured or device specific default */
21346686Sbrian
21446686Sbrian  lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp);
21546686Sbrian  ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp);
21646686Sbrian
21746686Sbrian  return p;
21846686Sbrian}
21946686Sbrian
22046686Sbrianstatic const struct parity {
22146686Sbrian  const char *name;
22246686Sbrian  const char *name1;
22346686Sbrian  int set;
22446686Sbrian} validparity[] = {
22546686Sbrian  { "even", "P_EVEN", CS7 | PARENB },
22646686Sbrian  { "odd", "P_ODD", CS7 | PARENB | PARODD },
22746686Sbrian  { "none", "P_ZERO", CS8 },
22846686Sbrian  { NULL, 0 },
22946686Sbrian};
23046686Sbrian
23146686Sbrianstatic int
23246686SbrianGetParityValue(const char *str)
23346686Sbrian{
23446686Sbrian  const struct parity *pp;
23546686Sbrian
23646686Sbrian  for (pp = validparity; pp->name; pp++) {
23746686Sbrian    if (strcasecmp(pp->name, str) == 0 ||
23846686Sbrian	strcasecmp(pp->name1, str) == 0) {
23946686Sbrian      return pp->set;
24046686Sbrian    }
24146686Sbrian  }
24246686Sbrian  return (-1);
24346686Sbrian}
24446686Sbrian
24536285Sbrianint
24646686Sbrianphysical_SetParity(struct physical *p, const char *str)
24746686Sbrian{
24846686Sbrian  struct termios rstio;
24946686Sbrian  int val;
25046686Sbrian
25146686Sbrian  val = GetParityValue(str);
25246686Sbrian  if (val > 0) {
25346686Sbrian    p->cfg.parity = val;
25446686Sbrian    if (p->fd >= 0) {
25546686Sbrian      tcgetattr(p->fd, &rstio);
25646686Sbrian      rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
25746686Sbrian      rstio.c_cflag |= val;
25846686Sbrian      tcsetattr(p->fd, TCSADRAIN, &rstio);
25946686Sbrian    }
26046686Sbrian    return 0;
26146686Sbrian  }
26246686Sbrian  log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str);
26346686Sbrian  return -1;
26436285Sbrian}
26536285Sbrian
26636285Sbrianint
26746686Sbrianphysical_GetSpeed(struct physical *p)
26846686Sbrian{
26946686Sbrian  if (p->handler && p->handler->speed)
27046686Sbrian    return (*p->handler->speed)(p);
27146686Sbrian
27249434Sbrian  return 0;
27336285Sbrian}
27436285Sbrian
27546686Sbrianint
27646686Sbrianphysical_SetSpeed(struct physical *p, int speed)
27736285Sbrian{
27846686Sbrian  if (IntToSpeed(speed) != B0) {
27946686Sbrian      p->cfg.speed = speed;
28046686Sbrian      return 1;
28146686Sbrian  }
28246686Sbrian
28346686Sbrian  return 0;
28436285Sbrian}
28536285Sbrian
28646686Sbrianint
28746686Sbrianphysical_Raw(struct physical *p)
28846686Sbrian{
28946686Sbrian  if (p->handler && p->handler->raw)
29046686Sbrian    return (*p->handler->raw)(p);
29146686Sbrian
29246686Sbrian  return 1;
29346686Sbrian}
29446686Sbrian
29536285Sbrianvoid
29646686Sbrianphysical_Offline(struct physical *p)
29746686Sbrian{
29846686Sbrian  if (p->handler && p->handler->offline)
29946686Sbrian    (*p->handler->offline)(p);
30046686Sbrian  log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name);
30146686Sbrian}
30246686Sbrian
30347286Sbrianstatic int
30447286Sbrianphysical_Lock(struct physical *p)
30546686Sbrian{
30647286Sbrian  int res;
30746686Sbrian
30847286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
30947286Sbrian      (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
31047286Sbrian    if (res == UU_LOCK_INUSE)
31147286Sbrian      log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
31247286Sbrian    else
31347286Sbrian      log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
31447286Sbrian                 p->link.name, p->name.full, uu_lockerr(res));
31547286Sbrian    return 0;
31646686Sbrian  }
31747286Sbrian
31847286Sbrian  return 1;
31946686Sbrian}
32046686Sbrian
32147286Sbrianstatic void
32247286Sbrianphysical_Unlock(struct physical *p)
32347286Sbrian{
32447286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
32547286Sbrian      ID0uu_unlock(p->name.base) == -1)
32674001Sbrian    log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name,
32774001Sbrian               p->name.base);
32847286Sbrian}
32947286Sbrian
33046686Sbrianvoid
33146686Sbrianphysical_Close(struct physical *p)
33246686Sbrian{
33347286Sbrian  int newsid;
33474001Sbrian  char fn[PATH_MAX];
33547286Sbrian
33646686Sbrian  if (p->fd < 0)
33746686Sbrian    return;
33846686Sbrian
33946686Sbrian  log_Printf(LogDEBUG, "%s: Close\n", p->link.name);
34046686Sbrian
34146686Sbrian  if (p->handler && p->handler->cooked)
34246686Sbrian    (*p->handler->cooked)(p);
34346686Sbrian
34447286Sbrian  physical_StopDeviceTimer(p);
34547286Sbrian  if (p->Utmp) {
34652429Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
34752487Sbrian                       p->handler->type == UDP_DEVICE))
34852487Sbrian      /* Careful - we logged in on line ``ppp'' with IP as our host */
34952487Sbrian      ID0logout(PPPOTCPLINE, 1);
35052487Sbrian    else
35152487Sbrian      ID0logout(p->name.base, 0);
35247286Sbrian    p->Utmp = 0;
35347286Sbrian  }
35447286Sbrian  newsid = tcgetpgrp(p->fd) == getpgrp();
35547286Sbrian  close(p->fd);
35647286Sbrian  p->fd = -1;
35747286Sbrian  log_SetTtyCommandMode(p->dl);
35847286Sbrian
35964652Sbrian  throughput_stop(&p->link.stats.total);
36064652Sbrian  throughput_log(&p->link.stats.total, LogPHASE, p->link.name);
36147286Sbrian
36247286Sbrian  if (p->session_owner != (pid_t)-1) {
36360863Sbrian    log_Printf(LogPHASE, "%s: HUPing %d\n", p->link.name,
36460863Sbrian               (int)p->session_owner);
36547286Sbrian    ID0kill(p->session_owner, SIGHUP);
36647286Sbrian    p->session_owner = (pid_t)-1;
36747286Sbrian  }
36847286Sbrian
36947286Sbrian  if (newsid)
37047286Sbrian    bundle_setsid(p->dl->bundle, 0);
37147286Sbrian
37247286Sbrian  if (*p->name.full == '/') {
37347286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
37447286Sbrian#ifndef RELEASE_CRUNCH
37547286Sbrian    if (ID0unlink(fn) == -1)
37647286Sbrian      log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
37747286Sbrian                 p->link.name, fn, strerror(errno));
37847286Sbrian#else
37947286Sbrian    ID0unlink(fn);
38047286Sbrian#endif
38147286Sbrian  }
38247286Sbrian  physical_Unlock(p);
38347286Sbrian  if (p->handler && p->handler->destroy)
38447286Sbrian    (*p->handler->destroy)(p);
38547286Sbrian  p->handler = NULL;
38647286Sbrian  p->name.base = p->name.full;
38747286Sbrian  *p->name.full = '\0';
38846686Sbrian}
38946686Sbrian
39046686Sbrianvoid
39146686Sbrianphysical_Destroy(struct physical *p)
39246686Sbrian{
39346686Sbrian  physical_Close(p);
39464652Sbrian  throughput_destroy(&p->link.stats.total);
39546686Sbrian  free(p);
39646686Sbrian}
39746686Sbrian
39846686Sbrianstatic int
39958028Sbrianphysical_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle,
40046686Sbrian                         const fd_set *fdset)
40146686Sbrian{
40246686Sbrian  struct physical *p = descriptor2physical(d);
40346686Sbrian  int nw, result = 0;
40446686Sbrian
40546686Sbrian  if (p->out == NULL)
40646686Sbrian    p->out = link_Dequeue(&p->link);
40746686Sbrian
40846686Sbrian  if (p->out) {
40954912Sbrian    nw = physical_Write(p, MBUF_CTOP(p->out), p->out->m_len);
41058042Sbrian    log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%lu) to %d\n",
41158042Sbrian               p->link.name, nw, (unsigned long)p->out->m_len, p->fd);
41246686Sbrian    if (nw > 0) {
41354912Sbrian      p->out->m_len -= nw;
41454912Sbrian      p->out->m_offset += nw;
41554912Sbrian      if (p->out->m_len == 0)
41654912Sbrian	p->out = m_free(p->out);
41746686Sbrian      result = 1;
41846686Sbrian    } else if (nw < 0) {
41966900Sbrian      if (errno == EAGAIN)
42066900Sbrian        result = 1;
42166900Sbrian      else if (errno != ENOBUFS) {
42246686Sbrian	log_Printf(LogPHASE, "%s: write (%d): %s\n", p->link.name,
42346686Sbrian                   p->fd, strerror(errno));
42446686Sbrian        datalink_Down(p->dl, CLOSE_NORMAL);
42546686Sbrian      }
42646686Sbrian    }
42746686Sbrian    /* else we shouldn't really have been called !  select() is broken ! */
42846686Sbrian  }
42946686Sbrian
43046686Sbrian  return result;
43146686Sbrian}
43246686Sbrian
43346686Sbrianint
43446686Sbrianphysical_ShowStatus(struct cmdargs const *arg)
43546686Sbrian{
43646686Sbrian  struct physical *p = arg->cx->physical;
43753733Sbrian  struct cd *cd;
43846686Sbrian  const char *dev;
43946686Sbrian  int n;
44046686Sbrian
44146686Sbrian  prompt_Printf(arg->prompt, "Name: %s\n", p->link.name);
44246686Sbrian  prompt_Printf(arg->prompt, " State:           ");
44346686Sbrian  if (p->fd < 0)
44446686Sbrian    prompt_Printf(arg->prompt, "closed\n");
44546686Sbrian  else if (p->handler && p->handler->openinfo)
44646686Sbrian    prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
44746686Sbrian  else
44846686Sbrian    prompt_Printf(arg->prompt, "open\n");
44946686Sbrian
45046686Sbrian  prompt_Printf(arg->prompt, " Device:          %s",
45146686Sbrian                *p->name.full ?  p->name.full :
45246686Sbrian                p->type == PHYS_DIRECT ? "unknown" : "N/A");
45346686Sbrian  if (p->session_owner != (pid_t)-1)
45446686Sbrian    prompt_Printf(arg->prompt, " (session owner: %d)", (int)p->session_owner);
45546686Sbrian
45646686Sbrian  prompt_Printf(arg->prompt, "\n Link Type:       %s\n", mode2Nam(p->type));
45746686Sbrian  prompt_Printf(arg->prompt, " Connect Count:   %d\n", p->connect_count);
45846686Sbrian#ifdef TIOCOUTQ
45946686Sbrian  if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
46046686Sbrian      prompt_Printf(arg->prompt, " Physical outq:   %d\n", n);
46146686Sbrian#endif
46246686Sbrian
46354912Sbrian  prompt_Printf(arg->prompt, " Queued Packets:  %lu\n",
46454912Sbrian                (u_long)link_QueueLen(&p->link));
46546686Sbrian  prompt_Printf(arg->prompt, " Phone Number:    %s\n", arg->cx->phone.chosen);
46646686Sbrian
46746686Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
46846686Sbrian
46946686Sbrian  prompt_Printf(arg->prompt, " Device List:     ");
47046686Sbrian  dev = p->cfg.devlist;
47146686Sbrian  for (n = 0; n < p->cfg.ndev; n++) {
47246686Sbrian    if (n)
47346686Sbrian      prompt_Printf(arg->prompt, ", ");
47446686Sbrian    prompt_Printf(arg->prompt, "\"%s\"", dev);
47546686Sbrian    dev += strlen(dev) + 1;
47646686Sbrian  }
47746686Sbrian
47846686Sbrian  prompt_Printf(arg->prompt, "\n Characteristics: ");
47946686Sbrian  if (physical_IsSync(arg->cx->physical))
48046686Sbrian    prompt_Printf(arg->prompt, "sync");
48146686Sbrian  else
48246686Sbrian    prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
48346686Sbrian
48446686Sbrian  switch (p->cfg.parity & CSIZE) {
48546686Sbrian  case CS7:
48646686Sbrian    prompt_Printf(arg->prompt, ", cs7");
48746686Sbrian    break;
48846686Sbrian  case CS8:
48946686Sbrian    prompt_Printf(arg->prompt, ", cs8");
49046686Sbrian    break;
49146686Sbrian  }
49246686Sbrian  if (p->cfg.parity & PARENB) {
49346686Sbrian    if (p->cfg.parity & PARODD)
49446686Sbrian      prompt_Printf(arg->prompt, ", odd parity");
49546686Sbrian    else
49646686Sbrian      prompt_Printf(arg->prompt, ", even parity");
49746686Sbrian  } else
49846686Sbrian    prompt_Printf(arg->prompt, ", no parity");
49946686Sbrian
50046686Sbrian  prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
50146686Sbrian
50251699Sbrian  prompt_Printf(arg->prompt, " CD check delay:  ");
50353733Sbrian  cd = p->handler ? &p->handler->cd : &p->cfg.cd;
50453733Sbrian  if (cd->necessity == CD_NOTREQUIRED)
50551699Sbrian    prompt_Printf(arg->prompt, "no cd");
50653733Sbrian  else if (p->cfg.cd.necessity == CD_DEFAULT) {
50753733Sbrian    prompt_Printf(arg->prompt, "device specific");
50853733Sbrian  } else {
50951699Sbrian    prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay,
51051699Sbrian                  p->cfg.cd.delay == 1 ? "" : "s");
51151699Sbrian    if (p->cfg.cd.necessity == CD_REQUIRED)
51251699Sbrian      prompt_Printf(arg->prompt, " (required!)");
51351699Sbrian  }
51451699Sbrian  prompt_Printf(arg->prompt, "\n\n");
51546686Sbrian
51664652Sbrian  throughput_disp(&p->link.stats.total, arg->prompt);
51746686Sbrian
51846686Sbrian  return 0;
51946686Sbrian}
52046686Sbrian
52152942Sbrianvoid
52258028Sbrianphysical_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
52346686Sbrian                     const fd_set *fdset)
52446686Sbrian{
52546686Sbrian  struct physical *p = descriptor2physical(d);
52646686Sbrian  u_char *rbuff;
52746686Sbrian  int n, found;
52846686Sbrian
52946686Sbrian  rbuff = p->input.buf + p->input.sz;
53046686Sbrian
53146686Sbrian  /* something to read */
53246686Sbrian  n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
53346686Sbrian  log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
53446686Sbrian             p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
53546686Sbrian  if (n <= 0) {
53646686Sbrian    if (n < 0)
53746686Sbrian      log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
53846686Sbrian                 strerror(errno));
53946686Sbrian    else
54046686Sbrian      log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
54146686Sbrian                 p->link.name, p->fd);
54246686Sbrian    datalink_Down(p->dl, CLOSE_NORMAL);
54346686Sbrian    return;
54446686Sbrian  }
54546686Sbrian
54646686Sbrian  rbuff -= p->input.sz;
54746686Sbrian  n += p->input.sz;
54846686Sbrian
54946686Sbrian  if (p->link.lcp.fsm.state <= ST_CLOSED) {
55046686Sbrian    if (p->type != PHYS_DEDICATED) {
55146686Sbrian      found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
55246686Sbrian      if (rbuff != p->input.buf)
55346686Sbrian        log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
55446686Sbrian                         p->input.buf);
55546686Sbrian      p->input.sz = n - (rbuff - p->input.buf);
55646686Sbrian
55746686Sbrian      if (found) {
55846686Sbrian        /* LCP packet is detected. Turn ourselves into packet mode */
55946686Sbrian        log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
56046686Sbrian                   p->link.name);
56146686Sbrian        log_SetTtyCommandMode(p->dl);
56246686Sbrian        datalink_Up(p->dl, 0, 1);
56346686Sbrian        link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
56446686Sbrian        p->input.sz = 0;
56546686Sbrian      } else
56646686Sbrian        bcopy(rbuff, p->input.buf, p->input.sz);
56746686Sbrian    } else
56846686Sbrian      /* In -dedicated mode, we just discard input until LCP is started */
56946686Sbrian      p->input.sz = 0;
57046686Sbrian  } else if (n > 0)
57146686Sbrian    link_PullPacket(&p->link, rbuff, n, bundle);
57246686Sbrian}
57346686Sbrian
57446686Sbrianstruct physical *
57546686Sbrianiov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
57652942Sbrian             int fd, int *auxfd, int *nauxfd)
57746686Sbrian{
57846686Sbrian  struct physical *p;
57947061Sbrian  int len, h, type;
58046686Sbrian
58146686Sbrian  p = (struct physical *)iov[(*niov)++].iov_base;
58246686Sbrian  p->link.name = dl->name;
58346686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
58446686Sbrian
58546686Sbrian  p->desc.UpdateSet = physical_UpdateSet;
58646686Sbrian  p->desc.IsSet = physical_IsSet;
58746686Sbrian  p->desc.Read = physical_DescriptorRead;
58846686Sbrian  p->desc.Write = physical_DescriptorWrite;
58946686Sbrian  p->type = PHYS_DIRECT;
59046686Sbrian  p->dl = dl;
59146686Sbrian  len = strlen(_PATH_DEV);
59246686Sbrian  p->out = NULL;
59346686Sbrian  p->connect_count = 1;
59446686Sbrian
59547682Sbrian  physical_SetDevice(p, p->name.full);
59647682Sbrian
59746686Sbrian  p->link.lcp.fsm.bundle = dl->bundle;
59846686Sbrian  p->link.lcp.fsm.link = &p->link;
59946686Sbrian  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
60046686Sbrian  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
60146686Sbrian  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
60246686Sbrian         sizeof p->link.lcp.fsm.StoppedTimer);
60346686Sbrian  p->link.lcp.fsm.parent = &dl->fsmp;
60446686Sbrian  lcp_SetupCallbacks(&p->link.lcp);
60546686Sbrian
60646686Sbrian  p->link.ccp.fsm.bundle = dl->bundle;
60746686Sbrian  p->link.ccp.fsm.link = &p->link;
60846686Sbrian  /* Our in.state & out.state are NULL (no link-level ccp yet) */
60946686Sbrian  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
61046686Sbrian  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
61146686Sbrian  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
61246686Sbrian         sizeof p->link.ccp.fsm.StoppedTimer);
61346686Sbrian  p->link.ccp.fsm.parent = &dl->fsmp;
61446686Sbrian  ccp_SetupCallbacks(&p->link.ccp);
61546686Sbrian
61646686Sbrian  p->hdlc.lqm.owner = &p->link.lcp;
61746686Sbrian  p->hdlc.ReportTimer.state = TIMER_STOPPED;
61846686Sbrian  p->hdlc.lqm.timer.state = TIMER_STOPPED;
61946686Sbrian
62046686Sbrian  p->fd = fd;
62164670Sbrian  p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base;
62264670Sbrian  p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base;
62364652Sbrian  p->link.stats.parent = dl->bundle->ncp.mp.active ?
62464652Sbrian    &dl->bundle->ncp.mp.link.stats.total : NULL;
62564652Sbrian  p->link.stats.gather = 1;
62646686Sbrian
62747769Sbrian  type = (long)p->handler;
62847769Sbrian  p->handler = NULL;
62947769Sbrian  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
63052942Sbrian    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
63152942Sbrian                                          auxfd, nauxfd);
63247769Sbrian  if (p->handler == NULL) {
63352942Sbrian    log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
63447769Sbrian    free(iov[(*niov)++].iov_base);
63547769Sbrian    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
63647769Sbrian  } else
63747769Sbrian    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
63847769Sbrian               p->link.name, p->name.full, p->handler->name);
63947769Sbrian
64046686Sbrian  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
64146686Sbrian    lqr_reStart(&p->link.lcp);
64246686Sbrian  hdlc_StartTimer(&p->hdlc);
64346686Sbrian
64464652Sbrian  throughput_restart(&p->link.stats.total, "physical throughput",
64549434Sbrian                     Enabled(dl->bundle, OPT_THROUGHPUT));
64646686Sbrian
64747769Sbrian  return p;
64847769Sbrian}
64947061Sbrian
65047769Sbrianint
65147769Sbrianphysical_MaxDeviceSize()
65247769Sbrian{
65347769Sbrian  int biggest, sz, n;
65447061Sbrian
65547769Sbrian  biggest = sizeof(struct device);
65647769Sbrian  for (sz = n = 0; n < NDEVICES; n++)
65747769Sbrian    if (devices[n].DeviceSize) {
65847769Sbrian      sz = (*devices[n].DeviceSize)();
65947769Sbrian      if (biggest < sz)
66047769Sbrian        biggest = sz;
66147769Sbrian    }
66247769Sbrian
66347769Sbrian  return biggest;
66446686Sbrian}
66546686Sbrian
66646686Sbrianint
66746686Sbrianphysical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
66853684Sbrian             int *auxfd, int *nauxfd)
66946686Sbrian{
67047769Sbrian  struct device *h;
67147769Sbrian  int sz;
67247769Sbrian
67347769Sbrian  h = NULL;
67446686Sbrian  if (p) {
67546686Sbrian    hdlc_StopTimer(&p->hdlc);
67646686Sbrian    lqr_StopTimer(p);
67746686Sbrian    timer_Stop(&p->link.lcp.fsm.FsmTimer);
67846686Sbrian    timer_Stop(&p->link.ccp.fsm.FsmTimer);
67946686Sbrian    timer_Stop(&p->link.lcp.fsm.OpenTimer);
68046686Sbrian    timer_Stop(&p->link.ccp.fsm.OpenTimer);
68146686Sbrian    timer_Stop(&p->link.lcp.fsm.StoppedTimer);
68246686Sbrian    timer_Stop(&p->link.ccp.fsm.StoppedTimer);
68347061Sbrian    if (p->handler) {
68453684Sbrian      h = p->handler;
68547061Sbrian      p->handler = (struct device *)(long)p->handler->type;
68646686Sbrian    }
68747061Sbrian
68847689Sbrian    if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
68947689Sbrian        tcgetpgrp(p->fd) == getpgrp())
69046686Sbrian      p->session_owner = getpid();      /* So I'll eventually get HUP'd */
69147689Sbrian    else
69247689Sbrian      p->session_owner = (pid_t)-1;
69364652Sbrian    timer_Stop(&p->link.stats.total.Timer);
69446686Sbrian  }
69546686Sbrian
69649434Sbrian  if (*niov + 2 >= maxiov) {
69749434Sbrian    log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
69849434Sbrian               " + device !\n");
69946686Sbrian    if (p)
70046686Sbrian      free(p);
70146686Sbrian    return -1;
70246686Sbrian  }
70346686Sbrian
70453684Sbrian  iov[*niov].iov_base = (void *)p;
70546686Sbrian  iov[*niov].iov_len = sizeof *p;
70646686Sbrian  (*niov)++;
70746686Sbrian
70864670Sbrian  iov[*niov].iov_base = p ? (void *)p->link.stats.total.in.SampleOctets : NULL;
70949434Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
71049434Sbrian  (*niov)++;
71164670Sbrian  iov[*niov].iov_base = p ? (void *)p->link.stats.total.out.SampleOctets : NULL;
71264670Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
71364670Sbrian  (*niov)++;
71449434Sbrian
71547769Sbrian  sz = physical_MaxDeviceSize();
71647769Sbrian  if (p) {
71753684Sbrian    if (h && h->device2iov)
71853684Sbrian      (*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd);
71947769Sbrian    else {
72047769Sbrian      iov[*niov].iov_base = malloc(sz);
72153684Sbrian      if (h)
72253684Sbrian        memcpy(iov[*niov].iov_base, h, sizeof *h);
72347769Sbrian      iov[*niov].iov_len = sz;
72447769Sbrian      (*niov)++;
72547769Sbrian    }
72647769Sbrian  } else {
72753684Sbrian    iov[*niov].iov_base = NULL;
72847769Sbrian    iov[*niov].iov_len = sz;
72947769Sbrian    (*niov)++;
73047769Sbrian  }
73147769Sbrian
73246686Sbrian  return p ? p->fd : 0;
73346686Sbrian}
73446686Sbrian
73553684Sbrianconst char *
73653684Sbrianphysical_LockedDevice(struct physical *p)
73753684Sbrian{
73853684Sbrian  if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT)
73953684Sbrian    return p->name.base;
74053684Sbrian
74153684Sbrian  return NULL;
74253684Sbrian}
74353684Sbrian
74446686Sbrianvoid
74546686Sbrianphysical_ChangedPid(struct physical *p, pid_t newpid)
74646686Sbrian{
74753684Sbrian  if (physical_LockedDevice(p)) {
74846686Sbrian    int res;
74946686Sbrian
75046686Sbrian    if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
75146686Sbrian      log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
75246686Sbrian  }
75346686Sbrian}
75446686Sbrian
75546686Sbrianint
75646686Sbrianphysical_IsSync(struct physical *p)
75746686Sbrian{
75846686Sbrian   return p->cfg.speed == 0;
75946686Sbrian}
76046686Sbrian
76178410Sbrianu_short
76278410Sbrianphysical_DeviceMTU(struct physical *p)
76378410Sbrian{
76478410Sbrian  return p->handler ? p->handler->mtu : 0;
76578410Sbrian}
76678410Sbrian
76746686Sbrianconst char *physical_GetDevice(struct physical *p)
76846686Sbrian{
76946686Sbrian   return p->name.full;
77046686Sbrian}
77146686Sbrian
77246686Sbrianvoid
77336285Sbrianphysical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
77436285Sbrian{
77536285Sbrian  int f, pos;
77636285Sbrian
77736285Sbrian  p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
77836285Sbrian  for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
77936285Sbrian    if (pos)
78046102Sbrian      p->cfg.devlist[pos++] = '\0';
78136285Sbrian    strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
78236285Sbrian    pos += strlen(p->cfg.devlist + pos);
78336285Sbrian  }
78446102Sbrian  p->cfg.ndev = f;
78536285Sbrian}
78636285Sbrian
78736285Sbrianvoid
78846686Sbrianphysical_SetSync(struct physical *p)
78946686Sbrian{
79046686Sbrian   p->cfg.speed = 0;
79136285Sbrian}
79236285Sbrian
79336285Sbrianint
79446686Sbrianphysical_SetRtsCts(struct physical *p, int enable)
79546686Sbrian{
79646686Sbrian   p->cfg.rts_cts = enable ? 1 : 0;
79736285Sbrian   return 1;
79836285Sbrian}
79936285Sbrian
80036285Sbrianssize_t
80146686Sbrianphysical_Read(struct physical *p, void *buf, size_t nbytes)
80246686Sbrian{
80347061Sbrian  ssize_t ret;
80447061Sbrian
80547061Sbrian  if (p->handler && p->handler->read)
80647061Sbrian    ret = (*p->handler->read)(p, buf, nbytes);
80747061Sbrian  else
80847061Sbrian    ret = read(p->fd, buf, nbytes);
80947061Sbrian
81047061Sbrian  log_DumpBuff(LogPHYSICAL, "read", buf, ret);
81147061Sbrian
81247061Sbrian  return ret;
81336285Sbrian}
81436285Sbrian
81536285Sbrianssize_t
81646686Sbrianphysical_Write(struct physical *p, const void *buf, size_t nbytes)
81746686Sbrian{
81847061Sbrian  log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
81947061Sbrian
82047061Sbrian  if (p->handler && p->handler->write)
82147061Sbrian    return (*p->handler->write)(p, buf, nbytes);
82247061Sbrian
82347061Sbrian  return write(p->fd, buf, nbytes);
82436285Sbrian}
82536285Sbrian
82636285Sbrianint
82758028Sbrianphysical_doUpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
82846686Sbrian                     int *n, int force)
82936285Sbrian{
83036285Sbrian  struct physical *p = descriptor2physical(d);
83136285Sbrian  int sets;
83236285Sbrian
83336285Sbrian  sets = 0;
83436285Sbrian  if (p->fd >= 0) {
83536285Sbrian    if (r) {
83636285Sbrian      FD_SET(p->fd, r);
83736285Sbrian      log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
83836285Sbrian      sets++;
83936285Sbrian    }
84036285Sbrian    if (e) {
84136285Sbrian      FD_SET(p->fd, e);
84236285Sbrian      log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
84336285Sbrian      sets++;
84436285Sbrian    }
84536314Sbrian    if (w && (force || link_QueueLen(&p->link) || p->out)) {
84636285Sbrian      FD_SET(p->fd, w);
84736285Sbrian      log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
84836285Sbrian      sets++;
84936285Sbrian    }
85036285Sbrian    if (sets && *n < p->fd + 1)
85136285Sbrian      *n = p->fd + 1;
85236285Sbrian  }
85336285Sbrian
85436285Sbrian  return sets;
85536285Sbrian}
85636285Sbrian
85736285Sbrianint
85836285Sbrianphysical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
85936285Sbrian{
86052942Sbrian  if (p->handler && p->handler->removefromset)
86152942Sbrian    return (*p->handler->removefromset)(p, r, w, e);
86252942Sbrian  else {
86352942Sbrian    int sets;
86436285Sbrian
86552942Sbrian    sets = 0;
86652942Sbrian    if (p->fd >= 0) {
86752942Sbrian      if (r && FD_ISSET(p->fd, r)) {
86852942Sbrian        FD_CLR(p->fd, r);
86952942Sbrian        log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
87052942Sbrian        sets++;
87152942Sbrian      }
87252942Sbrian      if (e && FD_ISSET(p->fd, e)) {
87352942Sbrian        FD_CLR(p->fd, e);
87452942Sbrian        log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
87552942Sbrian        sets++;
87652942Sbrian      }
87752942Sbrian      if (w && FD_ISSET(p->fd, w)) {
87852942Sbrian        FD_CLR(p->fd, w);
87952942Sbrian        log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
88052942Sbrian        sets++;
88152942Sbrian      }
88236285Sbrian    }
88352942Sbrian
88452942Sbrian    return sets;
88536285Sbrian  }
88636285Sbrian}
88736285Sbrian
88836285Sbrianint
88958028Sbrianphysical_IsSet(struct fdescriptor *d, const fd_set *fdset)
89036285Sbrian{
89136285Sbrian  struct physical *p = descriptor2physical(d);
89236285Sbrian  return p->fd >= 0 && FD_ISSET(p->fd, fdset);
89336285Sbrian}
89436285Sbrian
89536285Sbrianvoid
89646686Sbrianphysical_Login(struct physical *p, const char *name)
89736285Sbrian{
89846830Sbrian  if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
89946686Sbrian    struct utmp ut;
90046686Sbrian    const char *connstr;
90152413Sbrian    char *colon;
90236285Sbrian
90346686Sbrian    memset(&ut, 0, sizeof ut);
90446686Sbrian    time(&ut.ut_time);
90546686Sbrian    strncpy(ut.ut_name, name, sizeof ut.ut_name);
90652413Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
90752413Sbrian                       p->handler->type == UDP_DEVICE)) {
90852429Sbrian      strncpy(ut.ut_line, PPPOTCPLINE, sizeof ut.ut_line);
90952413Sbrian      strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host);
91052413Sbrian      colon = memchr(ut.ut_host, ':', sizeof ut.ut_host);
91152413Sbrian      if (colon)
91252413Sbrian        *colon = '\0';
91352413Sbrian    } else
91452413Sbrian      strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
91546686Sbrian    if ((connstr = getenv("CONNECT")))
91646686Sbrian      /* mgetty sets this to the connection speed */
91746686Sbrian      strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
91846686Sbrian    ID0login(&ut);
91952429Sbrian    p->Utmp = ut.ut_time;
92036285Sbrian  }
92136285Sbrian}
92236285Sbrian
92336285Sbrianint
92436285Sbrianphysical_SetMode(struct physical *p, int mode)
92536285Sbrian{
92638174Sbrian  if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
92738174Sbrian       mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
92838174Sbrian      (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
92953830Sbrian    /* Note:  The -direct -> -background is for callback ! */
93036285Sbrian    log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
93136285Sbrian               mode2Nam(p->type), mode2Nam(mode));
93236285Sbrian    return 0;
93336285Sbrian  }
93436285Sbrian  p->type = mode;
93536285Sbrian  return 1;
93636285Sbrian}
93738544Sbrian
93838544Sbrianvoid
93938544Sbrianphysical_DeleteQueue(struct physical *p)
94038544Sbrian{
94138544Sbrian  if (p->out) {
94254912Sbrian    m_freem(p->out);
94338544Sbrian    p->out = NULL;
94438544Sbrian  }
94538544Sbrian  link_DeleteQueue(&p->link);
94638544Sbrian}
94746686Sbrian
94846686Sbrianvoid
94946686Sbrianphysical_SetDevice(struct physical *p, const char *name)
95046686Sbrian{
95146686Sbrian  int len = strlen(_PATH_DEV);
95246686Sbrian
95347682Sbrian  if (name != p->name.full) {
95447682Sbrian    strncpy(p->name.full, name, sizeof p->name.full - 1);
95547682Sbrian    p->name.full[sizeof p->name.full - 1] = '\0';
95647682Sbrian  }
95746686Sbrian  p->name.base = *p->name.full == '!' ?  p->name.full + 1 :
95846686Sbrian                 strncmp(p->name.full, _PATH_DEV, len) ?
95946686Sbrian                 p->name.full : p->name.full + len;
96046686Sbrian}
96146686Sbrian
96246686Sbrianstatic void
96346686Sbrianphysical_Found(struct physical *p)
96446686Sbrian{
96547286Sbrian  FILE *lockfile;
96674001Sbrian  char fn[PATH_MAX];
96747286Sbrian
96847286Sbrian  if (*p->name.full == '/') {
96947286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
97047286Sbrian    lockfile = ID0fopen(fn, "w");
97147286Sbrian    if (lockfile != NULL) {
97247286Sbrian      fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
97347286Sbrian      fclose(lockfile);
97447286Sbrian    }
97547286Sbrian#ifndef RELEASE_CRUNCH
97647286Sbrian    else
97747286Sbrian      log_Printf(LogALERT, "%s: Can't create %s: %s\n",
97847286Sbrian                 p->link.name, fn, strerror(errno));
97947286Sbrian#endif
98047286Sbrian  }
98147286Sbrian
98264652Sbrian  throughput_start(&p->link.stats.total, "physical throughput",
98346686Sbrian                   Enabled(p->dl->bundle, OPT_THROUGHPUT));
98446686Sbrian  p->connect_count++;
98546686Sbrian  p->input.sz = 0;
98646686Sbrian
98746686Sbrian  log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
98846686Sbrian}
98946686Sbrian
99046686Sbrianint
99146686Sbrianphysical_Open(struct physical *p, struct bundle *bundle)
99246686Sbrian{
99352942Sbrian  int devno, h, wasfd, err;
99446686Sbrian  char *dev;
99546686Sbrian
99646686Sbrian  if (p->fd >= 0)
99746686Sbrian    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
99846686Sbrian    /* We're going back into "term" mode */
99946686Sbrian  else if (p->type == PHYS_DIRECT) {
100047061Sbrian    physical_SetDevice(p, "");
100147061Sbrian    p->fd = STDIN_FILENO;
100247061Sbrian    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
100352942Sbrian      p->handler = (*devices[h].create)(p);
100447061Sbrian    if (p->fd >= 0) {
100547124Sbrian      if (p->handler == NULL) {
100647461Sbrian        physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
100747124Sbrian        log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
100847124Sbrian      }
100946686Sbrian      physical_Found(p);
101046686Sbrian    }
101146686Sbrian  } else {
101246686Sbrian    dev = p->cfg.devlist;
101346686Sbrian    devno = 0;
101446686Sbrian    while (devno < p->cfg.ndev && p->fd < 0) {
101546686Sbrian      physical_SetDevice(p, dev);
101647286Sbrian      if (physical_Lock(p)) {
101747878Sbrian        err = 0;
101847878Sbrian
101947878Sbrian        if (*p->name.full == '/') {
102047286Sbrian          p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
102147878Sbrian          if (p->fd < 0)
102247878Sbrian            err = errno;
102347878Sbrian        }
102446686Sbrian
102552942Sbrian        wasfd = p->fd;
102647286Sbrian        for (h = 0; h < NDEVICES && p->handler == NULL; h++)
102752942Sbrian          if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd)
102847286Sbrian            break;
102946686Sbrian
103047286Sbrian        if (p->fd < 0) {
103147878Sbrian          if (h == NDEVICES) {
103247878Sbrian            if (err)
103347878Sbrian	      log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
103447878Sbrian                         strerror(errno));
103547878Sbrian            else
103647878Sbrian	      log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
103752942Sbrian                         " a '!' or contain at least one ':'\n", p->link.name,
103847878Sbrian                         p->name.full);
103947878Sbrian          }
104047286Sbrian          physical_Unlock(p);
104147286Sbrian        } else
104247286Sbrian          physical_Found(p);
104347286Sbrian      }
104446686Sbrian      dev += strlen(dev) + 1;
104546686Sbrian      devno++;
104646686Sbrian    }
104746686Sbrian  }
104846686Sbrian
104946686Sbrian  return p->fd;
105046686Sbrian}
105146686Sbrian
105246686Sbrianvoid
105347461Sbrianphysical_SetupStack(struct physical *p, const char *who, int how)
105446686Sbrian{
105546686Sbrian  link_EmptyStack(&p->link);
105652942Sbrian  if (how == PHYSICAL_FORCE_SYNC || how == PHYSICAL_FORCE_SYNCNOACF ||
105747061Sbrian      (how == PHYSICAL_NOFORCE && physical_IsSync(p)))
105846686Sbrian    link_Stack(&p->link, &synclayer);
105946686Sbrian  else {
106046686Sbrian    link_Stack(&p->link, &asynclayer);
106146686Sbrian    link_Stack(&p->link, &hdlclayer);
106246686Sbrian  }
106352942Sbrian  if (how != PHYSICAL_FORCE_SYNCNOACF)
106452942Sbrian    link_Stack(&p->link, &acflayer);
106546686Sbrian  link_Stack(&p->link, &protolayer);
106646686Sbrian  link_Stack(&p->link, &lqrlayer);
106746686Sbrian  link_Stack(&p->link, &ccplayer);
106846686Sbrian  link_Stack(&p->link, &vjlayer);
106969303Sbrian  link_Stack(&p->link, &tcpmsslayer);
107050059Sbrian#ifndef NONAT
107150059Sbrian  link_Stack(&p->link, &natlayer);
107246686Sbrian#endif
107347061Sbrian  if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) {
107447461Sbrian    log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who);
107547061Sbrian    p->cfg.speed = MODEM_SPEED;
107647061Sbrian  } else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) {
107747061Sbrian    log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n",
107847461Sbrian               who);
107947061Sbrian    physical_SetSync(p);
108047061Sbrian  }
108146686Sbrian}
108247061Sbrian
108347061Sbrianvoid
108447061Sbrianphysical_StopDeviceTimer(struct physical *p)
108547061Sbrian{
108647061Sbrian  if (p->handler && p->handler->stoptimer)
108747061Sbrian    (*p->handler->stoptimer)(p);
108847061Sbrian}
108949472Sbrian
109049472Sbrianint
109149472Sbrianphysical_AwaitCarrier(struct physical *p)
109249472Sbrian{
109349472Sbrian  if (p->handler && p->handler->awaitcarrier)
109449472Sbrian    return (*p->handler->awaitcarrier)(p);
109549472Sbrian
109649472Sbrian  return CARRIER_OK;
109749472Sbrian}
1098