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$
2036285Sbrian *
2136285Sbrian */
2236285Sbrian
2346686Sbrian#include <sys/param.h>
2446686Sbrian#include <netinet/in.h>
2546686Sbrian#include <netinet/in_systm.h>
2646686Sbrian#include <netinet/ip.h>
2781634Sbrian#include <sys/socket.h>
28202192Sed#include <sys/time.h>
2946686Sbrian#include <sys/un.h>
3046686Sbrian
3146686Sbrian#include <errno.h>
3246686Sbrian#include <fcntl.h>
3346686Sbrian#include <paths.h>
34134789Sbrian#ifdef NOSUID
35134789Sbrian#include <signal.h>
36134789Sbrian#endif
37102500Sbrian#include <stdarg.h>
3836285Sbrian#include <stdio.h>
3936285Sbrian#include <stdlib.h>
4036285Sbrian#include <string.h>
4146686Sbrian#include <sys/uio.h>
42136375Sbrian#include <sysexits.h>
43179568Sed#include <termios.h>
4436285Sbrian#include <time.h>
4536285Sbrian#include <unistd.h>
46202192Sed#include <utmpx.h>
4746686Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__)
4846686Sbrian#include <sys/ioctl.h>
4946686Sbrian#include <util.h>
5046686Sbrian#else
5146686Sbrian#include <libutil.h>
5246686Sbrian#endif
5336285Sbrian
5446686Sbrian#include "layer.h"
5550059Sbrian#ifndef NONAT
5651075Sbrian#include "nat_cmd.h"
5746686Sbrian#endif
5846686Sbrian#include "proto.h"
5946686Sbrian#include "acf.h"
6046686Sbrian#include "vjcomp.h"
6136285Sbrian#include "defs.h"
6246686Sbrian#include "command.h"
6336285Sbrian#include "mbuf.h"
6446686Sbrian#include "log.h"
6546686Sbrian#include "id.h"
6636285Sbrian#include "timer.h"
6746686Sbrian#include "fsm.h"
6836285Sbrian#include "lqr.h"
6936285Sbrian#include "hdlc.h"
7046686Sbrian#include "lcp.h"
7136285Sbrian#include "throughput.h"
7246686Sbrian#include "sync.h"
7336285Sbrian#include "async.h"
7446686Sbrian#include "iplist.h"
7546686Sbrian#include "slcompress.h"
7681634Sbrian#include "ncpaddr.h"
7746686Sbrian#include "ipcp.h"
7846686Sbrian#include "filter.h"
7946686Sbrian#include "descriptor.h"
8036285Sbrian#include "ccp.h"
8136285Sbrian#include "link.h"
8236285Sbrian#include "physical.h"
8346686Sbrian#include "mp.h"
8446686Sbrian#ifndef NORADIUS
8546686Sbrian#include "radius.h"
8646686Sbrian#endif
8781634Sbrian#include "ipv6cp.h"
8881634Sbrian#include "ncp.h"
8946686Sbrian#include "bundle.h"
9046686Sbrian#include "prompt.h"
9146686Sbrian#include "chat.h"
9246686Sbrian#include "auth.h"
93136375Sbrian#include "main.h"
9446686Sbrian#include "chap.h"
9546686Sbrian#include "cbcp.h"
9646686Sbrian#include "datalink.h"
9746686Sbrian#include "tcp.h"
9847061Sbrian#include "udp.h"
9946686Sbrian#include "exec.h"
10046686Sbrian#include "tty.h"
10152942Sbrian#ifndef NONETGRAPH
10252942Sbrian#include "ether.h"
10393418Sbrian#include "netgraph.h"
10452942Sbrian#endif
10565862Sbrian#ifndef NOATM
10665862Sbrian#include "atm.h"
10765862Sbrian#endif
10869303Sbrian#include "tcpmss.h"
10936285Sbrian
11058028Sbrianstatic int physical_DescriptorWrite(struct fdescriptor *, struct bundle *,
11146686Sbrian                                    const fd_set *);
11236285Sbrian
113134789Sbrianstatic unsigned
11447769Sbrianphysical_DeviceSize(void)
11547769Sbrian{
11647769Sbrian  return sizeof(struct device);
11747769Sbrian}
11847769Sbrian
11947061Sbrianstruct {
12047061Sbrian  struct device *(*create)(struct physical *);
12152942Sbrian  struct device *(*iov2device)(int, struct physical *, struct iovec *,
12252942Sbrian                               int *, int, int *, int *);
123134789Sbrian  unsigned (*DeviceSize)(void);
12447061Sbrian} devices[] = {
12547769Sbrian  { tty_Create, tty_iov2device, tty_DeviceSize },
12652942Sbrian#ifndef NONETGRAPH
12771006Sbrian  /*
12871006Sbrian   * This must come before ``udp'' so that the probe routine is
12971006Sbrian   * able to identify it as a more specific type of SOCK_DGRAM.
13071006Sbrian   */
13152942Sbrian  { ether_Create, ether_iov2device, ether_DeviceSize },
13293418Sbrian#ifdef EXPERIMENTAL_NETGRAPH
13393418Sbrian  { ng_Create, ng_iov2device, ng_DeviceSize },
13452942Sbrian#endif
13593418Sbrian#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 },
228134789Sbrian  { NULL, 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
266134789Sbrianunsigned
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
276134789Sbrianphysical_SetSpeed(struct physical *p, unsigned speed)
27736285Sbrian{
278134789Sbrian  if (UnsignedToSpeed(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];
335202192Sed  struct utmpx ut;
33647286Sbrian
33746686Sbrian  if (p->fd < 0)
33846686Sbrian    return;
33946686Sbrian
34046686Sbrian  log_Printf(LogDEBUG, "%s: Close\n", p->link.name);
34146686Sbrian
34246686Sbrian  if (p->handler && p->handler->cooked)
34346686Sbrian    (*p->handler->cooked)(p);
34446686Sbrian
34547286Sbrian  physical_StopDeviceTimer(p);
34647286Sbrian  if (p->Utmp) {
347202192Sed    memset(&ut, 0, sizeof ut);
348202192Sed    ut.ut_type = DEAD_PROCESS;
349202192Sed    gettimeofday(&ut.ut_tv, NULL);
350202192Sed    snprintf(ut.ut_id, sizeof ut.ut_id, "%xppp", (int)getpid());
351202192Sed    ID0logout(&ut);
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) {
36397360Sbrian    log_Printf(LogPHASE, "%s: HUPing %ld\n", p->link.name,
36497360Sbrian               (long)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
399134789Sbrianphysical_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle __unused,
400134789Sbrian                         const fd_set *fdset __unused)
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) {
422134833Smarcel	log_Printf(LogPHASE, "%s: write (fd %d, len %zd): %s\n", p->link.name,
423132423Sbrian                   p->fd, p->out->m_len, 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;
43999097Sbrian  int n, slot;
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");
44599097Sbrian  else {
44699097Sbrian    slot = physical_Slot(p);
44799097Sbrian    if (p->handler && p->handler->openinfo) {
44899097Sbrian      if (slot == -1)
44999097Sbrian        prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
45099097Sbrian      else
45199097Sbrian        prompt_Printf(arg->prompt, "open (%s, port %d)\n",
45299097Sbrian                      (*p->handler->openinfo)(p), slot);
45399097Sbrian    } else if (slot == -1)
45499097Sbrian      prompt_Printf(arg->prompt, "open\n");
45599097Sbrian    else
45699097Sbrian      prompt_Printf(arg->prompt, "open (port %d)\n", slot);
45799097Sbrian  }
45846686Sbrian
45946686Sbrian  prompt_Printf(arg->prompt, " Device:          %s",
46046686Sbrian                *p->name.full ?  p->name.full :
46146686Sbrian                p->type == PHYS_DIRECT ? "unknown" : "N/A");
46246686Sbrian  if (p->session_owner != (pid_t)-1)
46397360Sbrian    prompt_Printf(arg->prompt, " (session owner: %ld)", (long)p->session_owner);
46446686Sbrian
46546686Sbrian  prompt_Printf(arg->prompt, "\n Link Type:       %s\n", mode2Nam(p->type));
46646686Sbrian  prompt_Printf(arg->prompt, " Connect Count:   %d\n", p->connect_count);
46746686Sbrian#ifdef TIOCOUTQ
46846686Sbrian  if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
46946686Sbrian      prompt_Printf(arg->prompt, " Physical outq:   %d\n", n);
47046686Sbrian#endif
47146686Sbrian
47254912Sbrian  prompt_Printf(arg->prompt, " Queued Packets:  %lu\n",
47354912Sbrian                (u_long)link_QueueLen(&p->link));
47446686Sbrian  prompt_Printf(arg->prompt, " Phone Number:    %s\n", arg->cx->phone.chosen);
47546686Sbrian
47646686Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
47746686Sbrian
47846686Sbrian  prompt_Printf(arg->prompt, " Device List:     ");
47946686Sbrian  dev = p->cfg.devlist;
48046686Sbrian  for (n = 0; n < p->cfg.ndev; n++) {
48146686Sbrian    if (n)
48246686Sbrian      prompt_Printf(arg->prompt, ", ");
48346686Sbrian    prompt_Printf(arg->prompt, "\"%s\"", dev);
48446686Sbrian    dev += strlen(dev) + 1;
48546686Sbrian  }
48698243Sbrian
48746686Sbrian  prompt_Printf(arg->prompt, "\n Characteristics: ");
48846686Sbrian  if (physical_IsSync(arg->cx->physical))
48946686Sbrian    prompt_Printf(arg->prompt, "sync");
49046686Sbrian  else
49146686Sbrian    prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
49246686Sbrian
49346686Sbrian  switch (p->cfg.parity & CSIZE) {
49446686Sbrian  case CS7:
49546686Sbrian    prompt_Printf(arg->prompt, ", cs7");
49646686Sbrian    break;
49746686Sbrian  case CS8:
49846686Sbrian    prompt_Printf(arg->prompt, ", cs8");
49946686Sbrian    break;
50046686Sbrian  }
50146686Sbrian  if (p->cfg.parity & PARENB) {
50246686Sbrian    if (p->cfg.parity & PARODD)
50346686Sbrian      prompt_Printf(arg->prompt, ", odd parity");
50446686Sbrian    else
50546686Sbrian      prompt_Printf(arg->prompt, ", even parity");
50646686Sbrian  } else
50746686Sbrian    prompt_Printf(arg->prompt, ", no parity");
50846686Sbrian
50946686Sbrian  prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
51046686Sbrian
51151699Sbrian  prompt_Printf(arg->prompt, " CD check delay:  ");
51253733Sbrian  cd = p->handler ? &p->handler->cd : &p->cfg.cd;
51353733Sbrian  if (cd->necessity == CD_NOTREQUIRED)
51451699Sbrian    prompt_Printf(arg->prompt, "no cd");
51553733Sbrian  else if (p->cfg.cd.necessity == CD_DEFAULT) {
51653733Sbrian    prompt_Printf(arg->prompt, "device specific");
51753733Sbrian  } else {
51851699Sbrian    prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay,
51951699Sbrian                  p->cfg.cd.delay == 1 ? "" : "s");
52051699Sbrian    if (p->cfg.cd.necessity == CD_REQUIRED)
52151699Sbrian      prompt_Printf(arg->prompt, " (required!)");
52251699Sbrian  }
52351699Sbrian  prompt_Printf(arg->prompt, "\n\n");
52446686Sbrian
52564652Sbrian  throughput_disp(&p->link.stats.total, arg->prompt);
52646686Sbrian
52746686Sbrian  return 0;
52846686Sbrian}
52946686Sbrian
53052942Sbrianvoid
53158028Sbrianphysical_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
532134789Sbrian                     const fd_set *fdset __unused)
53346686Sbrian{
53446686Sbrian  struct physical *p = descriptor2physical(d);
53546686Sbrian  u_char *rbuff;
53646686Sbrian  int n, found;
53746686Sbrian
53846686Sbrian  rbuff = p->input.buf + p->input.sz;
53946686Sbrian
54046686Sbrian  /* something to read */
54146686Sbrian  n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
54246686Sbrian  log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
54346686Sbrian             p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
54446686Sbrian  if (n <= 0) {
54546686Sbrian    if (n < 0)
54646686Sbrian      log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
54746686Sbrian                 strerror(errno));
54846686Sbrian    else
54946686Sbrian      log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
55046686Sbrian                 p->link.name, p->fd);
55146686Sbrian    datalink_Down(p->dl, CLOSE_NORMAL);
55246686Sbrian    return;
55346686Sbrian  }
55446686Sbrian
55546686Sbrian  rbuff -= p->input.sz;
55646686Sbrian  n += p->input.sz;
55746686Sbrian
55846686Sbrian  if (p->link.lcp.fsm.state <= ST_CLOSED) {
55946686Sbrian    if (p->type != PHYS_DEDICATED) {
56046686Sbrian      found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
56146686Sbrian      if (rbuff != p->input.buf)
56246686Sbrian        log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
56346686Sbrian                         p->input.buf);
56446686Sbrian      p->input.sz = n - (rbuff - p->input.buf);
56546686Sbrian
56646686Sbrian      if (found) {
56746686Sbrian        /* LCP packet is detected. Turn ourselves into packet mode */
56846686Sbrian        log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
56946686Sbrian                   p->link.name);
57046686Sbrian        log_SetTtyCommandMode(p->dl);
57146686Sbrian        datalink_Up(p->dl, 0, 1);
57246686Sbrian        link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
57346686Sbrian        p->input.sz = 0;
57446686Sbrian      } else
57546686Sbrian        bcopy(rbuff, p->input.buf, p->input.sz);
57646686Sbrian    } else
57746686Sbrian      /* In -dedicated mode, we just discard input until LCP is started */
57846686Sbrian      p->input.sz = 0;
57946686Sbrian  } else if (n > 0)
58046686Sbrian    link_PullPacket(&p->link, rbuff, n, bundle);
58146686Sbrian}
58246686Sbrian
58346686Sbrianstruct physical *
58446686Sbrianiov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
58552942Sbrian             int fd, int *auxfd, int *nauxfd)
58646686Sbrian{
58746686Sbrian  struct physical *p;
588230349Seadler  int type;
589134789Sbrian  unsigned h;
59046686Sbrian
59146686Sbrian  p = (struct physical *)iov[(*niov)++].iov_base;
59246686Sbrian  p->link.name = dl->name;
59346686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
59446686Sbrian
59546686Sbrian  p->desc.UpdateSet = physical_UpdateSet;
59646686Sbrian  p->desc.IsSet = physical_IsSet;
59746686Sbrian  p->desc.Read = physical_DescriptorRead;
59846686Sbrian  p->desc.Write = physical_DescriptorWrite;
59946686Sbrian  p->type = PHYS_DIRECT;
60046686Sbrian  p->dl = dl;
60146686Sbrian  p->out = NULL;
60246686Sbrian  p->connect_count = 1;
60346686Sbrian
60447682Sbrian  physical_SetDevice(p, p->name.full);
60547682Sbrian
60646686Sbrian  p->link.lcp.fsm.bundle = dl->bundle;
60746686Sbrian  p->link.lcp.fsm.link = &p->link;
60846686Sbrian  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
60946686Sbrian  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
61046686Sbrian  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
61146686Sbrian         sizeof p->link.lcp.fsm.StoppedTimer);
61246686Sbrian  p->link.lcp.fsm.parent = &dl->fsmp;
61346686Sbrian  lcp_SetupCallbacks(&p->link.lcp);
61446686Sbrian
61546686Sbrian  p->link.ccp.fsm.bundle = dl->bundle;
61646686Sbrian  p->link.ccp.fsm.link = &p->link;
61746686Sbrian  /* Our in.state & out.state are NULL (no link-level ccp yet) */
61846686Sbrian  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
61946686Sbrian  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
62046686Sbrian  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
62146686Sbrian         sizeof p->link.ccp.fsm.StoppedTimer);
62246686Sbrian  p->link.ccp.fsm.parent = &dl->fsmp;
62346686Sbrian  ccp_SetupCallbacks(&p->link.ccp);
62446686Sbrian
62546686Sbrian  p->hdlc.lqm.owner = &p->link.lcp;
62646686Sbrian  p->hdlc.ReportTimer.state = TIMER_STOPPED;
62746686Sbrian  p->hdlc.lqm.timer.state = TIMER_STOPPED;
62846686Sbrian
62946686Sbrian  p->fd = fd;
63064670Sbrian  p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base;
63164670Sbrian  p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base;
63264652Sbrian  p->link.stats.parent = dl->bundle->ncp.mp.active ?
63364652Sbrian    &dl->bundle->ncp.mp.link.stats.total : NULL;
63464652Sbrian  p->link.stats.gather = 1;
63546686Sbrian
63647769Sbrian  type = (long)p->handler;
63747769Sbrian  p->handler = NULL;
63847769Sbrian  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
63952942Sbrian    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
64052942Sbrian                                          auxfd, nauxfd);
64147769Sbrian  if (p->handler == NULL) {
64252942Sbrian    log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
64347769Sbrian    free(iov[(*niov)++].iov_base);
64447769Sbrian    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
64547769Sbrian  } else
64647769Sbrian    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
64747769Sbrian               p->link.name, p->name.full, p->handler->name);
64847769Sbrian
64946686Sbrian  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
65046686Sbrian    lqr_reStart(&p->link.lcp);
65146686Sbrian  hdlc_StartTimer(&p->hdlc);
65246686Sbrian
65364652Sbrian  throughput_restart(&p->link.stats.total, "physical throughput",
65449434Sbrian                     Enabled(dl->bundle, OPT_THROUGHPUT));
65546686Sbrian
65647769Sbrian  return p;
65747769Sbrian}
65847061Sbrian
659134789Sbrianunsigned
66047769Sbrianphysical_MaxDeviceSize()
66147769Sbrian{
662134789Sbrian  unsigned biggest, sz, n;
66347061Sbrian
66447769Sbrian  biggest = sizeof(struct device);
665134789Sbrian  for (n = 0; n < NDEVICES; n++)
66647769Sbrian    if (devices[n].DeviceSize) {
66747769Sbrian      sz = (*devices[n].DeviceSize)();
66847769Sbrian      if (biggest < sz)
66947769Sbrian        biggest = sz;
67047769Sbrian    }
67147769Sbrian
67247769Sbrian  return biggest;
67346686Sbrian}
67446686Sbrian
67546686Sbrianint
67646686Sbrianphysical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
67753684Sbrian             int *auxfd, int *nauxfd)
67846686Sbrian{
67947769Sbrian  struct device *h;
68047769Sbrian  int sz;
68147769Sbrian
68247769Sbrian  h = NULL;
68346686Sbrian  if (p) {
68446686Sbrian    hdlc_StopTimer(&p->hdlc);
68546686Sbrian    lqr_StopTimer(p);
68646686Sbrian    timer_Stop(&p->link.lcp.fsm.FsmTimer);
68746686Sbrian    timer_Stop(&p->link.ccp.fsm.FsmTimer);
68846686Sbrian    timer_Stop(&p->link.lcp.fsm.OpenTimer);
68946686Sbrian    timer_Stop(&p->link.ccp.fsm.OpenTimer);
69046686Sbrian    timer_Stop(&p->link.lcp.fsm.StoppedTimer);
69146686Sbrian    timer_Stop(&p->link.ccp.fsm.StoppedTimer);
69247061Sbrian    if (p->handler) {
69353684Sbrian      h = p->handler;
69447061Sbrian      p->handler = (struct device *)(long)p->handler->type;
69546686Sbrian    }
69647061Sbrian
69747689Sbrian    if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
69847689Sbrian        tcgetpgrp(p->fd) == getpgrp())
69946686Sbrian      p->session_owner = getpid();      /* So I'll eventually get HUP'd */
70047689Sbrian    else
70147689Sbrian      p->session_owner = (pid_t)-1;
70264652Sbrian    timer_Stop(&p->link.stats.total.Timer);
70346686Sbrian  }
70446686Sbrian
70549434Sbrian  if (*niov + 2 >= maxiov) {
70649434Sbrian    log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
70749434Sbrian               " + device !\n");
70846686Sbrian    if (p)
70946686Sbrian      free(p);
71046686Sbrian    return -1;
71146686Sbrian  }
71246686Sbrian
71353684Sbrian  iov[*niov].iov_base = (void *)p;
71446686Sbrian  iov[*niov].iov_len = sizeof *p;
71546686Sbrian  (*niov)++;
71646686Sbrian
71764670Sbrian  iov[*niov].iov_base = p ? (void *)p->link.stats.total.in.SampleOctets : NULL;
71849434Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
71949434Sbrian  (*niov)++;
72064670Sbrian  iov[*niov].iov_base = p ? (void *)p->link.stats.total.out.SampleOctets : NULL;
72164670Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
72264670Sbrian  (*niov)++;
72349434Sbrian
72447769Sbrian  sz = physical_MaxDeviceSize();
72547769Sbrian  if (p) {
72653684Sbrian    if (h && h->device2iov)
72753684Sbrian      (*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd);
72847769Sbrian    else {
729136375Sbrian      if ((iov[*niov].iov_base = malloc(sz)) == NULL) {
730136375Sbrian	log_Printf(LogALERT, "physical2iov: Out of memory (%d bytes)\n", sz);
731136375Sbrian	AbortProgram(EX_OSERR);
732136375Sbrian      }
73353684Sbrian      if (h)
73453684Sbrian        memcpy(iov[*niov].iov_base, h, sizeof *h);
73547769Sbrian      iov[*niov].iov_len = sz;
73647769Sbrian      (*niov)++;
73747769Sbrian    }
73847769Sbrian  } else {
73953684Sbrian    iov[*niov].iov_base = NULL;
74047769Sbrian    iov[*niov].iov_len = sz;
74147769Sbrian    (*niov)++;
74247769Sbrian  }
74347769Sbrian
74446686Sbrian  return p ? p->fd : 0;
74546686Sbrian}
74646686Sbrian
74753684Sbrianconst char *
74853684Sbrianphysical_LockedDevice(struct physical *p)
74953684Sbrian{
75053684Sbrian  if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT)
75153684Sbrian    return p->name.base;
75253684Sbrian
75353684Sbrian  return NULL;
75453684Sbrian}
75553684Sbrian
75646686Sbrianvoid
75746686Sbrianphysical_ChangedPid(struct physical *p, pid_t newpid)
75846686Sbrian{
75953684Sbrian  if (physical_LockedDevice(p)) {
76046686Sbrian    int res;
76146686Sbrian
76246686Sbrian    if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
76346686Sbrian      log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
76446686Sbrian  }
76546686Sbrian}
76646686Sbrian
76746686Sbrianint
76846686Sbrianphysical_IsSync(struct physical *p)
76946686Sbrian{
77046686Sbrian   return p->cfg.speed == 0;
77146686Sbrian}
77246686Sbrian
77378410Sbrianu_short
77478410Sbrianphysical_DeviceMTU(struct physical *p)
77578410Sbrian{
77678410Sbrian  return p->handler ? p->handler->mtu : 0;
77778410Sbrian}
77878410Sbrian
77946686Sbrianconst char *physical_GetDevice(struct physical *p)
78046686Sbrian{
78146686Sbrian   return p->name.full;
78246686Sbrian}
78346686Sbrian
78446686Sbrianvoid
78536285Sbrianphysical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
78636285Sbrian{
787134789Sbrian  unsigned pos;
788134789Sbrian  int f;
78936285Sbrian
79036285Sbrian  p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
79136285Sbrian  for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
79236285Sbrian    if (pos)
79346102Sbrian      p->cfg.devlist[pos++] = '\0';
79436285Sbrian    strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
79536285Sbrian    pos += strlen(p->cfg.devlist + pos);
79636285Sbrian  }
79746102Sbrian  p->cfg.ndev = f;
79836285Sbrian}
79936285Sbrian
80036285Sbrianvoid
80146686Sbrianphysical_SetSync(struct physical *p)
80246686Sbrian{
80346686Sbrian   p->cfg.speed = 0;
80436285Sbrian}
80536285Sbrian
80636285Sbrianint
80746686Sbrianphysical_SetRtsCts(struct physical *p, int enable)
80846686Sbrian{
80946686Sbrian   p->cfg.rts_cts = enable ? 1 : 0;
81036285Sbrian   return 1;
81136285Sbrian}
81236285Sbrian
81336285Sbrianssize_t
81446686Sbrianphysical_Read(struct physical *p, void *buf, size_t nbytes)
81546686Sbrian{
81647061Sbrian  ssize_t ret;
81747061Sbrian
81847061Sbrian  if (p->handler && p->handler->read)
81947061Sbrian    ret = (*p->handler->read)(p, buf, nbytes);
82047061Sbrian  else
82147061Sbrian    ret = read(p->fd, buf, nbytes);
82247061Sbrian
82347061Sbrian  log_DumpBuff(LogPHYSICAL, "read", buf, ret);
82447061Sbrian
82547061Sbrian  return ret;
82636285Sbrian}
82736285Sbrian
82836285Sbrianssize_t
82946686Sbrianphysical_Write(struct physical *p, const void *buf, size_t nbytes)
83046686Sbrian{
83147061Sbrian  log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
83247061Sbrian
83347061Sbrian  if (p->handler && p->handler->write)
83447061Sbrian    return (*p->handler->write)(p, buf, nbytes);
83547061Sbrian
83647061Sbrian  return write(p->fd, buf, nbytes);
83736285Sbrian}
83836285Sbrian
83936285Sbrianint
84058028Sbrianphysical_doUpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
84146686Sbrian                     int *n, int force)
84236285Sbrian{
84336285Sbrian  struct physical *p = descriptor2physical(d);
84436285Sbrian  int sets;
84536285Sbrian
84636285Sbrian  sets = 0;
84736285Sbrian  if (p->fd >= 0) {
84836285Sbrian    if (r) {
84936285Sbrian      FD_SET(p->fd, r);
85036285Sbrian      log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
85136285Sbrian      sets++;
85236285Sbrian    }
85336285Sbrian    if (e) {
85436285Sbrian      FD_SET(p->fd, e);
85536285Sbrian      log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
85636285Sbrian      sets++;
85736285Sbrian    }
85836314Sbrian    if (w && (force || link_QueueLen(&p->link) || p->out)) {
85936285Sbrian      FD_SET(p->fd, w);
86036285Sbrian      log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
86136285Sbrian      sets++;
86236285Sbrian    }
86336285Sbrian    if (sets && *n < p->fd + 1)
86436285Sbrian      *n = p->fd + 1;
86536285Sbrian  }
86636285Sbrian
86736285Sbrian  return sets;
86836285Sbrian}
86936285Sbrian
87036285Sbrianint
87136285Sbrianphysical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
87236285Sbrian{
87352942Sbrian  if (p->handler && p->handler->removefromset)
87452942Sbrian    return (*p->handler->removefromset)(p, r, w, e);
87552942Sbrian  else {
87652942Sbrian    int sets;
87736285Sbrian
87852942Sbrian    sets = 0;
87952942Sbrian    if (p->fd >= 0) {
88052942Sbrian      if (r && FD_ISSET(p->fd, r)) {
88152942Sbrian        FD_CLR(p->fd, r);
88252942Sbrian        log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
88352942Sbrian        sets++;
88452942Sbrian      }
88552942Sbrian      if (e && FD_ISSET(p->fd, e)) {
88652942Sbrian        FD_CLR(p->fd, e);
88752942Sbrian        log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
88852942Sbrian        sets++;
88952942Sbrian      }
89052942Sbrian      if (w && FD_ISSET(p->fd, w)) {
89152942Sbrian        FD_CLR(p->fd, w);
89252942Sbrian        log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
89352942Sbrian        sets++;
89452942Sbrian      }
89536285Sbrian    }
89652942Sbrian
89752942Sbrian    return sets;
89836285Sbrian  }
89936285Sbrian}
90036285Sbrian
90136285Sbrianint
90258028Sbrianphysical_IsSet(struct fdescriptor *d, const fd_set *fdset)
90336285Sbrian{
90436285Sbrian  struct physical *p = descriptor2physical(d);
90536285Sbrian  return p->fd >= 0 && FD_ISSET(p->fd, fdset);
90636285Sbrian}
90736285Sbrian
90836285Sbrianvoid
90946686Sbrianphysical_Login(struct physical *p, const char *name)
91036285Sbrian{
91146830Sbrian  if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
912202192Sed    struct utmpx ut;
91346686Sbrian    const char *connstr;
91452413Sbrian    char *colon;
91536285Sbrian
91646686Sbrian    memset(&ut, 0, sizeof ut);
917202192Sed    ut.ut_type = USER_PROCESS;
918202192Sed    gettimeofday(&ut.ut_tv, NULL);
919202192Sed    snprintf(ut.ut_id, sizeof ut.ut_id, "%xppp", (int)getpid());
920202192Sed    strncpy(ut.ut_user, name, sizeof ut.ut_user);
92152413Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
92252413Sbrian                       p->handler->type == UDP_DEVICE)) {
92352413Sbrian      strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host);
92452413Sbrian      colon = memchr(ut.ut_host, ':', sizeof ut.ut_host);
92552413Sbrian      if (colon)
92652413Sbrian        *colon = '\0';
92752413Sbrian    } else
92852413Sbrian      strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
92946686Sbrian    if ((connstr = getenv("CONNECT")))
93046686Sbrian      /* mgetty sets this to the connection speed */
93146686Sbrian      strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
93246686Sbrian    ID0login(&ut);
933202192Sed    p->Utmp = 1;
93436285Sbrian  }
93536285Sbrian}
93636285Sbrian
93736285Sbrianint
93836285Sbrianphysical_SetMode(struct physical *p, int mode)
93936285Sbrian{
94038174Sbrian  if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
94138174Sbrian       mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
94238174Sbrian      (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
94353830Sbrian    /* Note:  The -direct -> -background is for callback ! */
94436285Sbrian    log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
94536285Sbrian               mode2Nam(p->type), mode2Nam(mode));
94636285Sbrian    return 0;
94736285Sbrian  }
94836285Sbrian  p->type = mode;
94936285Sbrian  return 1;
95036285Sbrian}
95138544Sbrian
95238544Sbrianvoid
95338544Sbrianphysical_DeleteQueue(struct physical *p)
95438544Sbrian{
95538544Sbrian  if (p->out) {
95654912Sbrian    m_freem(p->out);
95738544Sbrian    p->out = NULL;
95838544Sbrian  }
95938544Sbrian  link_DeleteQueue(&p->link);
96038544Sbrian}
96146686Sbrian
96246686Sbrianvoid
96346686Sbrianphysical_SetDevice(struct physical *p, const char *name)
96446686Sbrian{
96546686Sbrian  int len = strlen(_PATH_DEV);
96646686Sbrian
96747682Sbrian  if (name != p->name.full) {
96847682Sbrian    strncpy(p->name.full, name, sizeof p->name.full - 1);
96947682Sbrian    p->name.full[sizeof p->name.full - 1] = '\0';
97047682Sbrian  }
97146686Sbrian  p->name.base = *p->name.full == '!' ?  p->name.full + 1 :
97246686Sbrian                 strncmp(p->name.full, _PATH_DEV, len) ?
97346686Sbrian                 p->name.full : p->name.full + len;
97446686Sbrian}
97546686Sbrian
97646686Sbrianstatic void
97746686Sbrianphysical_Found(struct physical *p)
97846686Sbrian{
97947286Sbrian  FILE *lockfile;
98074001Sbrian  char fn[PATH_MAX];
98147286Sbrian
98247286Sbrian  if (*p->name.full == '/') {
98347286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
98447286Sbrian    lockfile = ID0fopen(fn, "w");
98547286Sbrian    if (lockfile != NULL) {
98647286Sbrian      fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
98747286Sbrian      fclose(lockfile);
98847286Sbrian    }
98947286Sbrian#ifndef RELEASE_CRUNCH
99047286Sbrian    else
99147286Sbrian      log_Printf(LogALERT, "%s: Can't create %s: %s\n",
99247286Sbrian                 p->link.name, fn, strerror(errno));
99347286Sbrian#endif
99447286Sbrian  }
99547286Sbrian
99664652Sbrian  throughput_start(&p->link.stats.total, "physical throughput",
99746686Sbrian                   Enabled(p->dl->bundle, OPT_THROUGHPUT));
99846686Sbrian  p->connect_count++;
99946686Sbrian  p->input.sz = 0;
100046686Sbrian
100146686Sbrian  log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
100246686Sbrian}
100346686Sbrian
100446686Sbrianint
1005134789Sbrianphysical_Open(struct physical *p)
100646686Sbrian{
100746686Sbrian  char *dev;
1008134789Sbrian  int devno, wasfd, err;
1009134789Sbrian  unsigned h;
101046686Sbrian
101146686Sbrian  if (p->fd >= 0)
101246686Sbrian    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
101346686Sbrian    /* We're going back into "term" mode */
101446686Sbrian  else if (p->type == PHYS_DIRECT) {
101547061Sbrian    physical_SetDevice(p, "");
101647061Sbrian    p->fd = STDIN_FILENO;
101747061Sbrian    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
101852942Sbrian      p->handler = (*devices[h].create)(p);
1019196514Sbrian    close(STDOUT_FILENO);
102047061Sbrian    if (p->fd >= 0) {
102147124Sbrian      if (p->handler == NULL) {
102247461Sbrian        physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
102347124Sbrian        log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
102447124Sbrian      }
102546686Sbrian      physical_Found(p);
102646686Sbrian    }
102746686Sbrian  } else {
102846686Sbrian    dev = p->cfg.devlist;
102946686Sbrian    devno = 0;
103046686Sbrian    while (devno < p->cfg.ndev && p->fd < 0) {
103146686Sbrian      physical_SetDevice(p, dev);
103247286Sbrian      if (physical_Lock(p)) {
103347878Sbrian        err = 0;
103447878Sbrian
103547878Sbrian        if (*p->name.full == '/') {
103647286Sbrian          p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
103747878Sbrian          if (p->fd < 0)
103847878Sbrian            err = errno;
103947878Sbrian        }
104046686Sbrian
104152942Sbrian        wasfd = p->fd;
104247286Sbrian        for (h = 0; h < NDEVICES && p->handler == NULL; h++)
104352942Sbrian          if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd)
104447286Sbrian            break;
104546686Sbrian
104647286Sbrian        if (p->fd < 0) {
104747878Sbrian          if (h == NDEVICES) {
104847878Sbrian            if (err)
104947878Sbrian	      log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
105047878Sbrian                         strerror(errno));
105147878Sbrian            else
105247878Sbrian	      log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
105352942Sbrian                         " a '!' or contain at least one ':'\n", p->link.name,
105447878Sbrian                         p->name.full);
105547878Sbrian          }
105647286Sbrian          physical_Unlock(p);
105747286Sbrian        } else
105847286Sbrian          physical_Found(p);
105947286Sbrian      }
106046686Sbrian      dev += strlen(dev) + 1;
106146686Sbrian      devno++;
106246686Sbrian    }
106346686Sbrian  }
106446686Sbrian
106546686Sbrian  return p->fd;
106646686Sbrian}
106746686Sbrian
106846686Sbrianvoid
106947461Sbrianphysical_SetupStack(struct physical *p, const char *who, int how)
107046686Sbrian{
107146686Sbrian  link_EmptyStack(&p->link);
107252942Sbrian  if (how == PHYSICAL_FORCE_SYNC || how == PHYSICAL_FORCE_SYNCNOACF ||
107347061Sbrian      (how == PHYSICAL_NOFORCE && physical_IsSync(p)))
107446686Sbrian    link_Stack(&p->link, &synclayer);
107546686Sbrian  else {
107646686Sbrian    link_Stack(&p->link, &asynclayer);
107746686Sbrian    link_Stack(&p->link, &hdlclayer);
107846686Sbrian  }
107952942Sbrian  if (how != PHYSICAL_FORCE_SYNCNOACF)
108052942Sbrian    link_Stack(&p->link, &acflayer);
108146686Sbrian  link_Stack(&p->link, &protolayer);
108246686Sbrian  link_Stack(&p->link, &lqrlayer);
108346686Sbrian  link_Stack(&p->link, &ccplayer);
108446686Sbrian  link_Stack(&p->link, &vjlayer);
108569303Sbrian  link_Stack(&p->link, &tcpmsslayer);
108650059Sbrian#ifndef NONAT
108750059Sbrian  link_Stack(&p->link, &natlayer);
108846686Sbrian#endif
108947061Sbrian  if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) {
109047461Sbrian    log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who);
109147061Sbrian    p->cfg.speed = MODEM_SPEED;
109247061Sbrian  } else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) {
109347061Sbrian    log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n",
109447461Sbrian               who);
109547061Sbrian    physical_SetSync(p);
109647061Sbrian  }
109746686Sbrian}
109847061Sbrian
109947061Sbrianvoid
110047061Sbrianphysical_StopDeviceTimer(struct physical *p)
110147061Sbrian{
110247061Sbrian  if (p->handler && p->handler->stoptimer)
110347061Sbrian    (*p->handler->stoptimer)(p);
110447061Sbrian}
110549472Sbrian
110649472Sbrianint
110749472Sbrianphysical_AwaitCarrier(struct physical *p)
110849472Sbrian{
110949472Sbrian  if (p->handler && p->handler->awaitcarrier)
111049472Sbrian    return (*p->handler->awaitcarrier)(p);
111149472Sbrian
111249472Sbrian  return CARRIER_OK;
111349472Sbrian}
111493418Sbrian
111593418Sbrian
111693418Sbrianvoid
111793418Sbrianphysical_SetAsyncParams(struct physical *p, u_int32_t mymap, u_int32_t hismap)
111893418Sbrian{
111993418Sbrian  if (p->handler && p->handler->setasyncparams)
112093418Sbrian    return (*p->handler->setasyncparams)(p, mymap, hismap);
112193418Sbrian
112293418Sbrian  async_SetLinkParams(&p->async, mymap, hismap);
112393418Sbrian}
112496582Sbrian
112596582Sbrianint
112696582Sbrianphysical_Slot(struct physical *p)
112796582Sbrian{
112896582Sbrian  if (p->handler && p->handler->slot)
112996582Sbrian    return (*p->handler->slot)(p);
113096582Sbrian
113196582Sbrian  return -1;
113296582Sbrian}
1133132818Sglebius
1134132818Sglebiusint
1135132818Sglebiusphysical_SetPPPoEnonstandard(struct physical *p, int enable)
1136132818Sglebius{
1137132818Sglebius   p->cfg.nonstandard_pppoe = enable ? 1 : 0;
1138132818Sglebius   p->cfg.pppoe_configured = 1;
1139132818Sglebius   return 1;
1140132818Sglebius}
1141