physical.c revision 179568
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 179568 2008-06-05 17:46:32Z ed $
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>
2846686Sbrian#include <sys/un.h>
2946686Sbrian
3046686Sbrian#include <errno.h>
3146686Sbrian#include <fcntl.h>
3246686Sbrian#include <paths.h>
33134789Sbrian#ifdef NOSUID
34134789Sbrian#include <signal.h>
35134789Sbrian#endif
36102500Sbrian#include <stdarg.h>
3736285Sbrian#include <stdio.h>
3836285Sbrian#include <stdlib.h>
3936285Sbrian#include <string.h>
4046686Sbrian#include <sys/uio.h>
41136375Sbrian#include <sysexits.h>
42179568Sed#include <termios.h>
4336285Sbrian#include <time.h>
4436285Sbrian#include <unistd.h>
4536285Sbrian#include <utmp.h>
4646686Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__)
4746686Sbrian#include <sys/ioctl.h>
4846686Sbrian#include <util.h>
4946686Sbrian#else
5046686Sbrian#include <libutil.h>
5146686Sbrian#endif
5236285Sbrian
5346686Sbrian#include "layer.h"
5450059Sbrian#ifndef NONAT
5551075Sbrian#include "nat_cmd.h"
5646686Sbrian#endif
5746686Sbrian#include "proto.h"
5846686Sbrian#include "acf.h"
5946686Sbrian#include "vjcomp.h"
6036285Sbrian#include "defs.h"
6146686Sbrian#include "command.h"
6236285Sbrian#include "mbuf.h"
6346686Sbrian#include "log.h"
6446686Sbrian#include "id.h"
6536285Sbrian#include "timer.h"
6646686Sbrian#include "fsm.h"
6736285Sbrian#include "lqr.h"
6836285Sbrian#include "hdlc.h"
6946686Sbrian#include "lcp.h"
7036285Sbrian#include "throughput.h"
7146686Sbrian#include "sync.h"
7236285Sbrian#include "async.h"
7346686Sbrian#include "iplist.h"
7446686Sbrian#include "slcompress.h"
7581634Sbrian#include "ncpaddr.h"
7646686Sbrian#include "ipcp.h"
7746686Sbrian#include "filter.h"
7846686Sbrian#include "descriptor.h"
7936285Sbrian#include "ccp.h"
8036285Sbrian#include "link.h"
8136285Sbrian#include "physical.h"
8246686Sbrian#include "mp.h"
8346686Sbrian#ifndef NORADIUS
8446686Sbrian#include "radius.h"
8546686Sbrian#endif
8681634Sbrian#include "ipv6cp.h"
8781634Sbrian#include "ncp.h"
8846686Sbrian#include "bundle.h"
8946686Sbrian#include "prompt.h"
9046686Sbrian#include "chat.h"
9146686Sbrian#include "auth.h"
92136375Sbrian#include "main.h"
9346686Sbrian#include "chap.h"
9446686Sbrian#include "cbcp.h"
9546686Sbrian#include "datalink.h"
9646686Sbrian#include "tcp.h"
9747061Sbrian#include "udp.h"
9846686Sbrian#include "exec.h"
9946686Sbrian#include "tty.h"
10052942Sbrian#ifndef NONETGRAPH
10152942Sbrian#include "ether.h"
10293418Sbrian#include "netgraph.h"
10352942Sbrian#endif
10465862Sbrian#ifndef NOATM
10565862Sbrian#include "atm.h"
10665862Sbrian#endif
10769303Sbrian#include "tcpmss.h"
10836285Sbrian
10952429Sbrian#define PPPOTCPLINE "ppp"
11052429Sbrian
11158028Sbrianstatic int physical_DescriptorWrite(struct fdescriptor *, struct bundle *,
11246686Sbrian                                    const fd_set *);
11336285Sbrian
114134789Sbrianstatic unsigned
11547769Sbrianphysical_DeviceSize(void)
11647769Sbrian{
11747769Sbrian  return sizeof(struct device);
11847769Sbrian}
11947769Sbrian
12047061Sbrianstruct {
12147061Sbrian  struct device *(*create)(struct physical *);
12252942Sbrian  struct device *(*iov2device)(int, struct physical *, struct iovec *,
12352942Sbrian                               int *, int, int *, int *);
124134789Sbrian  unsigned (*DeviceSize)(void);
12547061Sbrian} devices[] = {
12647769Sbrian  { tty_Create, tty_iov2device, tty_DeviceSize },
12752942Sbrian#ifndef NONETGRAPH
12871006Sbrian  /*
12971006Sbrian   * This must come before ``udp'' so that the probe routine is
13071006Sbrian   * able to identify it as a more specific type of SOCK_DGRAM.
13171006Sbrian   */
13252942Sbrian  { ether_Create, ether_iov2device, ether_DeviceSize },
13393418Sbrian#ifdef EXPERIMENTAL_NETGRAPH
13493418Sbrian  { ng_Create, ng_iov2device, ng_DeviceSize },
13552942Sbrian#endif
13693418Sbrian#endif
13765862Sbrian#ifndef NOATM
13871006Sbrian  /* Ditto for ATM devices */
13965862Sbrian  { atm_Create, atm_iov2device, atm_DeviceSize },
14065862Sbrian#endif
14147769Sbrian  { tcp_Create, tcp_iov2device, tcp_DeviceSize },
14247769Sbrian  { udp_Create, udp_iov2device, udp_DeviceSize },
14347769Sbrian  { exec_Create, exec_iov2device, exec_DeviceSize }
14446686Sbrian};
14546686Sbrian
14647061Sbrian#define NDEVICES (sizeof devices / sizeof devices[0])
14746686Sbrian
14846686Sbrianstatic int
14958028Sbrianphysical_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
15046686Sbrian                   int *n)
15146686Sbrian{
15246686Sbrian  return physical_doUpdateSet(d, r, w, e, n, 0);
15346686Sbrian}
15446686Sbrian
15552942Sbrianvoid
15652942Sbrianphysical_SetDescriptor(struct physical *p)
15752942Sbrian{
15852942Sbrian  p->desc.type = PHYSICAL_DESCRIPTOR;
15952942Sbrian  p->desc.UpdateSet = physical_UpdateSet;
16052942Sbrian  p->desc.IsSet = physical_IsSet;
16152942Sbrian  p->desc.Read = physical_DescriptorRead;
16252942Sbrian  p->desc.Write = physical_DescriptorWrite;
16352942Sbrian}
16452942Sbrian
16546686Sbrianstruct physical *
16646686Sbrianphysical_Create(struct datalink *dl, int type)
16746686Sbrian{
16846686Sbrian  struct physical *p;
16946686Sbrian
17046686Sbrian  p = (struct physical *)malloc(sizeof(struct physical));
17146686Sbrian  if (!p)
17246686Sbrian    return NULL;
17346686Sbrian
17446686Sbrian  p->link.type = PHYSICAL_LINK;
17546686Sbrian  p->link.name = dl->name;
17646686Sbrian  p->link.len = sizeof *p;
17746686Sbrian
17849434Sbrian  /* The sample period is fixed - see physical2iov() & iov2physical() */
17964652Sbrian  throughput_init(&p->link.stats.total, SAMPLE_PERIOD);
18064652Sbrian  p->link.stats.parent = dl->bundle->ncp.mp.active ?
18164652Sbrian    &dl->bundle->ncp.mp.link.stats.total : NULL;
18264652Sbrian  p->link.stats.gather = 1;
18349434Sbrian
18446686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
18546686Sbrian  memset(p->link.proto_in, '\0', sizeof p->link.proto_in);
18646686Sbrian  memset(p->link.proto_out, '\0', sizeof p->link.proto_out);
18746686Sbrian  link_EmptyStack(&p->link);
18846686Sbrian
18946686Sbrian  p->handler = NULL;
19052942Sbrian  physical_SetDescriptor(p);
19146686Sbrian  p->type = type;
19246686Sbrian
19346686Sbrian  hdlc_Init(&p->hdlc, &p->link.lcp);
19446686Sbrian  async_Init(&p->async);
19546686Sbrian
19646686Sbrian  p->fd = -1;
19746686Sbrian  p->out = NULL;
19846686Sbrian  p->connect_count = 0;
19946686Sbrian  p->dl = dl;
20046686Sbrian  p->input.sz = 0;
20146686Sbrian  *p->name.full = '\0';
20246686Sbrian  p->name.base = p->name.full;
20346686Sbrian
20446686Sbrian  p->Utmp = 0;
20546686Sbrian  p->session_owner = (pid_t)-1;
20646686Sbrian
20746686Sbrian  p->cfg.rts_cts = MODEM_CTSRTS;
20846686Sbrian  p->cfg.speed = MODEM_SPEED;
20946686Sbrian  p->cfg.parity = CS8;
21046686Sbrian  memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST);
21146686Sbrian  p->cfg.ndev = NMODEMS;
21253733Sbrian  p->cfg.cd.necessity = CD_DEFAULT;
21353733Sbrian  p->cfg.cd.delay = 0;		/* reconfigured or device specific default */
21446686Sbrian
21546686Sbrian  lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp);
21646686Sbrian  ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp);
21746686Sbrian
21846686Sbrian  return p;
21946686Sbrian}
22046686Sbrian
22146686Sbrianstatic const struct parity {
22246686Sbrian  const char *name;
22346686Sbrian  const char *name1;
22446686Sbrian  int set;
22546686Sbrian} validparity[] = {
22646686Sbrian  { "even", "P_EVEN", CS7 | PARENB },
22746686Sbrian  { "odd", "P_ODD", CS7 | PARENB | PARODD },
22846686Sbrian  { "none", "P_ZERO", CS8 },
229134789Sbrian  { NULL, NULL, 0 },
23046686Sbrian};
23146686Sbrian
23246686Sbrianstatic int
23346686SbrianGetParityValue(const char *str)
23446686Sbrian{
23546686Sbrian  const struct parity *pp;
23646686Sbrian
23746686Sbrian  for (pp = validparity; pp->name; pp++) {
23846686Sbrian    if (strcasecmp(pp->name, str) == 0 ||
23946686Sbrian	strcasecmp(pp->name1, str) == 0) {
24046686Sbrian      return pp->set;
24146686Sbrian    }
24246686Sbrian  }
24346686Sbrian  return (-1);
24446686Sbrian}
24546686Sbrian
24636285Sbrianint
24746686Sbrianphysical_SetParity(struct physical *p, const char *str)
24846686Sbrian{
24946686Sbrian  struct termios rstio;
25046686Sbrian  int val;
25146686Sbrian
25246686Sbrian  val = GetParityValue(str);
25346686Sbrian  if (val > 0) {
25446686Sbrian    p->cfg.parity = val;
25546686Sbrian    if (p->fd >= 0) {
25646686Sbrian      tcgetattr(p->fd, &rstio);
25746686Sbrian      rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
25846686Sbrian      rstio.c_cflag |= val;
25946686Sbrian      tcsetattr(p->fd, TCSADRAIN, &rstio);
26046686Sbrian    }
26146686Sbrian    return 0;
26246686Sbrian  }
26346686Sbrian  log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str);
26446686Sbrian  return -1;
26536285Sbrian}
26636285Sbrian
267134789Sbrianunsigned
26846686Sbrianphysical_GetSpeed(struct physical *p)
26946686Sbrian{
27046686Sbrian  if (p->handler && p->handler->speed)
27146686Sbrian    return (*p->handler->speed)(p);
27246686Sbrian
27349434Sbrian  return 0;
27436285Sbrian}
27536285Sbrian
27646686Sbrianint
277134789Sbrianphysical_SetSpeed(struct physical *p, unsigned speed)
27836285Sbrian{
279134789Sbrian  if (UnsignedToSpeed(speed) != B0) {
28046686Sbrian      p->cfg.speed = speed;
28146686Sbrian      return 1;
28246686Sbrian  }
28346686Sbrian
28446686Sbrian  return 0;
28536285Sbrian}
28636285Sbrian
28746686Sbrianint
28846686Sbrianphysical_Raw(struct physical *p)
28946686Sbrian{
29046686Sbrian  if (p->handler && p->handler->raw)
29146686Sbrian    return (*p->handler->raw)(p);
29246686Sbrian
29346686Sbrian  return 1;
29446686Sbrian}
29546686Sbrian
29636285Sbrianvoid
29746686Sbrianphysical_Offline(struct physical *p)
29846686Sbrian{
29946686Sbrian  if (p->handler && p->handler->offline)
30046686Sbrian    (*p->handler->offline)(p);
30146686Sbrian  log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name);
30246686Sbrian}
30346686Sbrian
30447286Sbrianstatic int
30547286Sbrianphysical_Lock(struct physical *p)
30646686Sbrian{
30747286Sbrian  int res;
30846686Sbrian
30947286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
31047286Sbrian      (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
31147286Sbrian    if (res == UU_LOCK_INUSE)
31247286Sbrian      log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
31347286Sbrian    else
31447286Sbrian      log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
31547286Sbrian                 p->link.name, p->name.full, uu_lockerr(res));
31647286Sbrian    return 0;
31746686Sbrian  }
31847286Sbrian
31947286Sbrian  return 1;
32046686Sbrian}
32146686Sbrian
32247286Sbrianstatic void
32347286Sbrianphysical_Unlock(struct physical *p)
32447286Sbrian{
32547286Sbrian  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
32647286Sbrian      ID0uu_unlock(p->name.base) == -1)
32774001Sbrian    log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name,
32874001Sbrian               p->name.base);
32947286Sbrian}
33047286Sbrian
33146686Sbrianvoid
33246686Sbrianphysical_Close(struct physical *p)
33346686Sbrian{
33447286Sbrian  int newsid;
33574001Sbrian  char fn[PATH_MAX];
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) {
34752429Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
34852487Sbrian                       p->handler->type == UDP_DEVICE))
34952487Sbrian      /* Careful - we logged in on line ``ppp'' with IP as our host */
35052487Sbrian      ID0logout(PPPOTCPLINE, 1);
35152487Sbrian    else
35252487Sbrian      ID0logout(p->name.base, 0);
35347286Sbrian    p->Utmp = 0;
35447286Sbrian  }
35547286Sbrian  newsid = tcgetpgrp(p->fd) == getpgrp();
35647286Sbrian  close(p->fd);
35747286Sbrian  p->fd = -1;
35847286Sbrian  log_SetTtyCommandMode(p->dl);
35947286Sbrian
36064652Sbrian  throughput_stop(&p->link.stats.total);
36164652Sbrian  throughput_log(&p->link.stats.total, LogPHASE, p->link.name);
36247286Sbrian
36347286Sbrian  if (p->session_owner != (pid_t)-1) {
36497360Sbrian    log_Printf(LogPHASE, "%s: HUPing %ld\n", p->link.name,
36597360Sbrian               (long)p->session_owner);
36647286Sbrian    ID0kill(p->session_owner, SIGHUP);
36747286Sbrian    p->session_owner = (pid_t)-1;
36847286Sbrian  }
36947286Sbrian
37047286Sbrian  if (newsid)
37147286Sbrian    bundle_setsid(p->dl->bundle, 0);
37247286Sbrian
37347286Sbrian  if (*p->name.full == '/') {
37447286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
37547286Sbrian#ifndef RELEASE_CRUNCH
37647286Sbrian    if (ID0unlink(fn) == -1)
37747286Sbrian      log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
37847286Sbrian                 p->link.name, fn, strerror(errno));
37947286Sbrian#else
38047286Sbrian    ID0unlink(fn);
38147286Sbrian#endif
38247286Sbrian  }
38347286Sbrian  physical_Unlock(p);
38447286Sbrian  if (p->handler && p->handler->destroy)
38547286Sbrian    (*p->handler->destroy)(p);
38647286Sbrian  p->handler = NULL;
38747286Sbrian  p->name.base = p->name.full;
38847286Sbrian  *p->name.full = '\0';
38946686Sbrian}
39046686Sbrian
39146686Sbrianvoid
39246686Sbrianphysical_Destroy(struct physical *p)
39346686Sbrian{
39446686Sbrian  physical_Close(p);
39564652Sbrian  throughput_destroy(&p->link.stats.total);
39646686Sbrian  free(p);
39746686Sbrian}
39846686Sbrian
39946686Sbrianstatic int
400134789Sbrianphysical_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle __unused,
401134789Sbrian                         const fd_set *fdset __unused)
40246686Sbrian{
40346686Sbrian  struct physical *p = descriptor2physical(d);
40446686Sbrian  int nw, result = 0;
40546686Sbrian
40646686Sbrian  if (p->out == NULL)
40746686Sbrian    p->out = link_Dequeue(&p->link);
40846686Sbrian
40946686Sbrian  if (p->out) {
41054912Sbrian    nw = physical_Write(p, MBUF_CTOP(p->out), p->out->m_len);
41158042Sbrian    log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%lu) to %d\n",
41258042Sbrian               p->link.name, nw, (unsigned long)p->out->m_len, p->fd);
41346686Sbrian    if (nw > 0) {
41454912Sbrian      p->out->m_len -= nw;
41554912Sbrian      p->out->m_offset += nw;
41654912Sbrian      if (p->out->m_len == 0)
41754912Sbrian	p->out = m_free(p->out);
41846686Sbrian      result = 1;
41946686Sbrian    } else if (nw < 0) {
42066900Sbrian      if (errno == EAGAIN)
42166900Sbrian        result = 1;
42266900Sbrian      else if (errno != ENOBUFS) {
423134833Smarcel	log_Printf(LogPHASE, "%s: write (fd %d, len %zd): %s\n", p->link.name,
424132423Sbrian                   p->fd, p->out->m_len, strerror(errno));
42546686Sbrian        datalink_Down(p->dl, CLOSE_NORMAL);
42646686Sbrian      }
42746686Sbrian    }
42846686Sbrian    /* else we shouldn't really have been called !  select() is broken ! */
42946686Sbrian  }
43046686Sbrian
43146686Sbrian  return result;
43246686Sbrian}
43346686Sbrian
43446686Sbrianint
43546686Sbrianphysical_ShowStatus(struct cmdargs const *arg)
43646686Sbrian{
43746686Sbrian  struct physical *p = arg->cx->physical;
43853733Sbrian  struct cd *cd;
43946686Sbrian  const char *dev;
44099097Sbrian  int n, slot;
44146686Sbrian
44246686Sbrian  prompt_Printf(arg->prompt, "Name: %s\n", p->link.name);
44346686Sbrian  prompt_Printf(arg->prompt, " State:           ");
44446686Sbrian  if (p->fd < 0)
44546686Sbrian    prompt_Printf(arg->prompt, "closed\n");
44699097Sbrian  else {
44799097Sbrian    slot = physical_Slot(p);
44899097Sbrian    if (p->handler && p->handler->openinfo) {
44999097Sbrian      if (slot == -1)
45099097Sbrian        prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
45199097Sbrian      else
45299097Sbrian        prompt_Printf(arg->prompt, "open (%s, port %d)\n",
45399097Sbrian                      (*p->handler->openinfo)(p), slot);
45499097Sbrian    } else if (slot == -1)
45599097Sbrian      prompt_Printf(arg->prompt, "open\n");
45699097Sbrian    else
45799097Sbrian      prompt_Printf(arg->prompt, "open (port %d)\n", slot);
45899097Sbrian  }
45946686Sbrian
46046686Sbrian  prompt_Printf(arg->prompt, " Device:          %s",
46146686Sbrian                *p->name.full ?  p->name.full :
46246686Sbrian                p->type == PHYS_DIRECT ? "unknown" : "N/A");
46346686Sbrian  if (p->session_owner != (pid_t)-1)
46497360Sbrian    prompt_Printf(arg->prompt, " (session owner: %ld)", (long)p->session_owner);
46546686Sbrian
46646686Sbrian  prompt_Printf(arg->prompt, "\n Link Type:       %s\n", mode2Nam(p->type));
46746686Sbrian  prompt_Printf(arg->prompt, " Connect Count:   %d\n", p->connect_count);
46846686Sbrian#ifdef TIOCOUTQ
46946686Sbrian  if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
47046686Sbrian      prompt_Printf(arg->prompt, " Physical outq:   %d\n", n);
47146686Sbrian#endif
47246686Sbrian
47354912Sbrian  prompt_Printf(arg->prompt, " Queued Packets:  %lu\n",
47454912Sbrian                (u_long)link_QueueLen(&p->link));
47546686Sbrian  prompt_Printf(arg->prompt, " Phone Number:    %s\n", arg->cx->phone.chosen);
47646686Sbrian
47746686Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
47846686Sbrian
47946686Sbrian  prompt_Printf(arg->prompt, " Device List:     ");
48046686Sbrian  dev = p->cfg.devlist;
48146686Sbrian  for (n = 0; n < p->cfg.ndev; n++) {
48246686Sbrian    if (n)
48346686Sbrian      prompt_Printf(arg->prompt, ", ");
48446686Sbrian    prompt_Printf(arg->prompt, "\"%s\"", dev);
48546686Sbrian    dev += strlen(dev) + 1;
48646686Sbrian  }
48798243Sbrian
48846686Sbrian  prompt_Printf(arg->prompt, "\n Characteristics: ");
48946686Sbrian  if (physical_IsSync(arg->cx->physical))
49046686Sbrian    prompt_Printf(arg->prompt, "sync");
49146686Sbrian  else
49246686Sbrian    prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
49346686Sbrian
49446686Sbrian  switch (p->cfg.parity & CSIZE) {
49546686Sbrian  case CS7:
49646686Sbrian    prompt_Printf(arg->prompt, ", cs7");
49746686Sbrian    break;
49846686Sbrian  case CS8:
49946686Sbrian    prompt_Printf(arg->prompt, ", cs8");
50046686Sbrian    break;
50146686Sbrian  }
50246686Sbrian  if (p->cfg.parity & PARENB) {
50346686Sbrian    if (p->cfg.parity & PARODD)
50446686Sbrian      prompt_Printf(arg->prompt, ", odd parity");
50546686Sbrian    else
50646686Sbrian      prompt_Printf(arg->prompt, ", even parity");
50746686Sbrian  } else
50846686Sbrian    prompt_Printf(arg->prompt, ", no parity");
50946686Sbrian
51046686Sbrian  prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
51146686Sbrian
51251699Sbrian  prompt_Printf(arg->prompt, " CD check delay:  ");
51353733Sbrian  cd = p->handler ? &p->handler->cd : &p->cfg.cd;
51453733Sbrian  if (cd->necessity == CD_NOTREQUIRED)
51551699Sbrian    prompt_Printf(arg->prompt, "no cd");
51653733Sbrian  else if (p->cfg.cd.necessity == CD_DEFAULT) {
51753733Sbrian    prompt_Printf(arg->prompt, "device specific");
51853733Sbrian  } else {
51951699Sbrian    prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay,
52051699Sbrian                  p->cfg.cd.delay == 1 ? "" : "s");
52151699Sbrian    if (p->cfg.cd.necessity == CD_REQUIRED)
52251699Sbrian      prompt_Printf(arg->prompt, " (required!)");
52351699Sbrian  }
52451699Sbrian  prompt_Printf(arg->prompt, "\n\n");
52546686Sbrian
52664652Sbrian  throughput_disp(&p->link.stats.total, arg->prompt);
52746686Sbrian
52846686Sbrian  return 0;
52946686Sbrian}
53046686Sbrian
53152942Sbrianvoid
53258028Sbrianphysical_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
533134789Sbrian                     const fd_set *fdset __unused)
53446686Sbrian{
53546686Sbrian  struct physical *p = descriptor2physical(d);
53646686Sbrian  u_char *rbuff;
53746686Sbrian  int n, found;
53846686Sbrian
53946686Sbrian  rbuff = p->input.buf + p->input.sz;
54046686Sbrian
54146686Sbrian  /* something to read */
54246686Sbrian  n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
54346686Sbrian  log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
54446686Sbrian             p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
54546686Sbrian  if (n <= 0) {
54646686Sbrian    if (n < 0)
54746686Sbrian      log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
54846686Sbrian                 strerror(errno));
54946686Sbrian    else
55046686Sbrian      log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
55146686Sbrian                 p->link.name, p->fd);
55246686Sbrian    datalink_Down(p->dl, CLOSE_NORMAL);
55346686Sbrian    return;
55446686Sbrian  }
55546686Sbrian
55646686Sbrian  rbuff -= p->input.sz;
55746686Sbrian  n += p->input.sz;
55846686Sbrian
55946686Sbrian  if (p->link.lcp.fsm.state <= ST_CLOSED) {
56046686Sbrian    if (p->type != PHYS_DEDICATED) {
56146686Sbrian      found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
56246686Sbrian      if (rbuff != p->input.buf)
56346686Sbrian        log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
56446686Sbrian                         p->input.buf);
56546686Sbrian      p->input.sz = n - (rbuff - p->input.buf);
56646686Sbrian
56746686Sbrian      if (found) {
56846686Sbrian        /* LCP packet is detected. Turn ourselves into packet mode */
56946686Sbrian        log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
57046686Sbrian                   p->link.name);
57146686Sbrian        log_SetTtyCommandMode(p->dl);
57246686Sbrian        datalink_Up(p->dl, 0, 1);
57346686Sbrian        link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
57446686Sbrian        p->input.sz = 0;
57546686Sbrian      } else
57646686Sbrian        bcopy(rbuff, p->input.buf, p->input.sz);
57746686Sbrian    } else
57846686Sbrian      /* In -dedicated mode, we just discard input until LCP is started */
57946686Sbrian      p->input.sz = 0;
58046686Sbrian  } else if (n > 0)
58146686Sbrian    link_PullPacket(&p->link, rbuff, n, bundle);
58246686Sbrian}
58346686Sbrian
58446686Sbrianstruct physical *
58546686Sbrianiov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
58652942Sbrian             int fd, int *auxfd, int *nauxfd)
58746686Sbrian{
58846686Sbrian  struct physical *p;
589134789Sbrian  int len, type;
590134789Sbrian  unsigned h;
59146686Sbrian
59246686Sbrian  p = (struct physical *)iov[(*niov)++].iov_base;
59346686Sbrian  p->link.name = dl->name;
59446686Sbrian  memset(p->link.Queue, '\0', sizeof p->link.Queue);
59546686Sbrian
59646686Sbrian  p->desc.UpdateSet = physical_UpdateSet;
59746686Sbrian  p->desc.IsSet = physical_IsSet;
59846686Sbrian  p->desc.Read = physical_DescriptorRead;
59946686Sbrian  p->desc.Write = physical_DescriptorWrite;
60046686Sbrian  p->type = PHYS_DIRECT;
60146686Sbrian  p->dl = dl;
60246686Sbrian  len = strlen(_PATH_DEV);
60346686Sbrian  p->out = NULL;
60446686Sbrian  p->connect_count = 1;
60546686Sbrian
60647682Sbrian  physical_SetDevice(p, p->name.full);
60747682Sbrian
60846686Sbrian  p->link.lcp.fsm.bundle = dl->bundle;
60946686Sbrian  p->link.lcp.fsm.link = &p->link;
61046686Sbrian  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
61146686Sbrian  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
61246686Sbrian  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
61346686Sbrian         sizeof p->link.lcp.fsm.StoppedTimer);
61446686Sbrian  p->link.lcp.fsm.parent = &dl->fsmp;
61546686Sbrian  lcp_SetupCallbacks(&p->link.lcp);
61646686Sbrian
61746686Sbrian  p->link.ccp.fsm.bundle = dl->bundle;
61846686Sbrian  p->link.ccp.fsm.link = &p->link;
61946686Sbrian  /* Our in.state & out.state are NULL (no link-level ccp yet) */
62046686Sbrian  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
62146686Sbrian  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
62246686Sbrian  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
62346686Sbrian         sizeof p->link.ccp.fsm.StoppedTimer);
62446686Sbrian  p->link.ccp.fsm.parent = &dl->fsmp;
62546686Sbrian  ccp_SetupCallbacks(&p->link.ccp);
62646686Sbrian
62746686Sbrian  p->hdlc.lqm.owner = &p->link.lcp;
62846686Sbrian  p->hdlc.ReportTimer.state = TIMER_STOPPED;
62946686Sbrian  p->hdlc.lqm.timer.state = TIMER_STOPPED;
63046686Sbrian
63146686Sbrian  p->fd = fd;
63264670Sbrian  p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base;
63364670Sbrian  p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base;
63464652Sbrian  p->link.stats.parent = dl->bundle->ncp.mp.active ?
63564652Sbrian    &dl->bundle->ncp.mp.link.stats.total : NULL;
63664652Sbrian  p->link.stats.gather = 1;
63746686Sbrian
63847769Sbrian  type = (long)p->handler;
63947769Sbrian  p->handler = NULL;
64047769Sbrian  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
64152942Sbrian    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
64252942Sbrian                                          auxfd, nauxfd);
64347769Sbrian  if (p->handler == NULL) {
64452942Sbrian    log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
64547769Sbrian    free(iov[(*niov)++].iov_base);
64647769Sbrian    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
64747769Sbrian  } else
64847769Sbrian    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
64947769Sbrian               p->link.name, p->name.full, p->handler->name);
65047769Sbrian
65146686Sbrian  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
65246686Sbrian    lqr_reStart(&p->link.lcp);
65346686Sbrian  hdlc_StartTimer(&p->hdlc);
65446686Sbrian
65564652Sbrian  throughput_restart(&p->link.stats.total, "physical throughput",
65649434Sbrian                     Enabled(dl->bundle, OPT_THROUGHPUT));
65746686Sbrian
65847769Sbrian  return p;
65947769Sbrian}
66047061Sbrian
661134789Sbrianunsigned
66247769Sbrianphysical_MaxDeviceSize()
66347769Sbrian{
664134789Sbrian  unsigned biggest, sz, n;
66547061Sbrian
66647769Sbrian  biggest = sizeof(struct device);
667134789Sbrian  for (n = 0; n < NDEVICES; n++)
66847769Sbrian    if (devices[n].DeviceSize) {
66947769Sbrian      sz = (*devices[n].DeviceSize)();
67047769Sbrian      if (biggest < sz)
67147769Sbrian        biggest = sz;
67247769Sbrian    }
67347769Sbrian
67447769Sbrian  return biggest;
67546686Sbrian}
67646686Sbrian
67746686Sbrianint
67846686Sbrianphysical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
67953684Sbrian             int *auxfd, int *nauxfd)
68046686Sbrian{
68147769Sbrian  struct device *h;
68247769Sbrian  int sz;
68347769Sbrian
68447769Sbrian  h = NULL;
68546686Sbrian  if (p) {
68646686Sbrian    hdlc_StopTimer(&p->hdlc);
68746686Sbrian    lqr_StopTimer(p);
68846686Sbrian    timer_Stop(&p->link.lcp.fsm.FsmTimer);
68946686Sbrian    timer_Stop(&p->link.ccp.fsm.FsmTimer);
69046686Sbrian    timer_Stop(&p->link.lcp.fsm.OpenTimer);
69146686Sbrian    timer_Stop(&p->link.ccp.fsm.OpenTimer);
69246686Sbrian    timer_Stop(&p->link.lcp.fsm.StoppedTimer);
69346686Sbrian    timer_Stop(&p->link.ccp.fsm.StoppedTimer);
69447061Sbrian    if (p->handler) {
69553684Sbrian      h = p->handler;
69647061Sbrian      p->handler = (struct device *)(long)p->handler->type;
69746686Sbrian    }
69847061Sbrian
69947689Sbrian    if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
70047689Sbrian        tcgetpgrp(p->fd) == getpgrp())
70146686Sbrian      p->session_owner = getpid();      /* So I'll eventually get HUP'd */
70247689Sbrian    else
70347689Sbrian      p->session_owner = (pid_t)-1;
70464652Sbrian    timer_Stop(&p->link.stats.total.Timer);
70546686Sbrian  }
70646686Sbrian
70749434Sbrian  if (*niov + 2 >= maxiov) {
70849434Sbrian    log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
70949434Sbrian               " + device !\n");
71046686Sbrian    if (p)
71146686Sbrian      free(p);
71246686Sbrian    return -1;
71346686Sbrian  }
71446686Sbrian
71553684Sbrian  iov[*niov].iov_base = (void *)p;
71646686Sbrian  iov[*niov].iov_len = sizeof *p;
71746686Sbrian  (*niov)++;
71846686Sbrian
71964670Sbrian  iov[*niov].iov_base = p ? (void *)p->link.stats.total.in.SampleOctets : NULL;
72049434Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
72149434Sbrian  (*niov)++;
72264670Sbrian  iov[*niov].iov_base = p ? (void *)p->link.stats.total.out.SampleOctets : NULL;
72364670Sbrian  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
72464670Sbrian  (*niov)++;
72549434Sbrian
72647769Sbrian  sz = physical_MaxDeviceSize();
72747769Sbrian  if (p) {
72853684Sbrian    if (h && h->device2iov)
72953684Sbrian      (*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd);
73047769Sbrian    else {
731136375Sbrian      if ((iov[*niov].iov_base = malloc(sz)) == NULL) {
732136375Sbrian	log_Printf(LogALERT, "physical2iov: Out of memory (%d bytes)\n", sz);
733136375Sbrian	AbortProgram(EX_OSERR);
734136375Sbrian      }
73553684Sbrian      if (h)
73653684Sbrian        memcpy(iov[*niov].iov_base, h, sizeof *h);
73747769Sbrian      iov[*niov].iov_len = sz;
73847769Sbrian      (*niov)++;
73947769Sbrian    }
74047769Sbrian  } else {
74153684Sbrian    iov[*niov].iov_base = NULL;
74247769Sbrian    iov[*niov].iov_len = sz;
74347769Sbrian    (*niov)++;
74447769Sbrian  }
74547769Sbrian
74646686Sbrian  return p ? p->fd : 0;
74746686Sbrian}
74846686Sbrian
74953684Sbrianconst char *
75053684Sbrianphysical_LockedDevice(struct physical *p)
75153684Sbrian{
75253684Sbrian  if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT)
75353684Sbrian    return p->name.base;
75453684Sbrian
75553684Sbrian  return NULL;
75653684Sbrian}
75753684Sbrian
75846686Sbrianvoid
75946686Sbrianphysical_ChangedPid(struct physical *p, pid_t newpid)
76046686Sbrian{
76153684Sbrian  if (physical_LockedDevice(p)) {
76246686Sbrian    int res;
76346686Sbrian
76446686Sbrian    if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
76546686Sbrian      log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
76646686Sbrian  }
76746686Sbrian}
76846686Sbrian
76946686Sbrianint
77046686Sbrianphysical_IsSync(struct physical *p)
77146686Sbrian{
77246686Sbrian   return p->cfg.speed == 0;
77346686Sbrian}
77446686Sbrian
77578410Sbrianu_short
77678410Sbrianphysical_DeviceMTU(struct physical *p)
77778410Sbrian{
77878410Sbrian  return p->handler ? p->handler->mtu : 0;
77978410Sbrian}
78078410Sbrian
78146686Sbrianconst char *physical_GetDevice(struct physical *p)
78246686Sbrian{
78346686Sbrian   return p->name.full;
78446686Sbrian}
78546686Sbrian
78646686Sbrianvoid
78736285Sbrianphysical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
78836285Sbrian{
789134789Sbrian  unsigned pos;
790134789Sbrian  int f;
79136285Sbrian
79236285Sbrian  p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
79336285Sbrian  for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
79436285Sbrian    if (pos)
79546102Sbrian      p->cfg.devlist[pos++] = '\0';
79636285Sbrian    strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
79736285Sbrian    pos += strlen(p->cfg.devlist + pos);
79836285Sbrian  }
79946102Sbrian  p->cfg.ndev = f;
80036285Sbrian}
80136285Sbrian
80236285Sbrianvoid
80346686Sbrianphysical_SetSync(struct physical *p)
80446686Sbrian{
80546686Sbrian   p->cfg.speed = 0;
80636285Sbrian}
80736285Sbrian
80836285Sbrianint
80946686Sbrianphysical_SetRtsCts(struct physical *p, int enable)
81046686Sbrian{
81146686Sbrian   p->cfg.rts_cts = enable ? 1 : 0;
81236285Sbrian   return 1;
81336285Sbrian}
81436285Sbrian
81536285Sbrianssize_t
81646686Sbrianphysical_Read(struct physical *p, void *buf, size_t nbytes)
81746686Sbrian{
81847061Sbrian  ssize_t ret;
81947061Sbrian
82047061Sbrian  if (p->handler && p->handler->read)
82147061Sbrian    ret = (*p->handler->read)(p, buf, nbytes);
82247061Sbrian  else
82347061Sbrian    ret = read(p->fd, buf, nbytes);
82447061Sbrian
82547061Sbrian  log_DumpBuff(LogPHYSICAL, "read", buf, ret);
82647061Sbrian
82747061Sbrian  return ret;
82836285Sbrian}
82936285Sbrian
83036285Sbrianssize_t
83146686Sbrianphysical_Write(struct physical *p, const void *buf, size_t nbytes)
83246686Sbrian{
83347061Sbrian  log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
83447061Sbrian
83547061Sbrian  if (p->handler && p->handler->write)
83647061Sbrian    return (*p->handler->write)(p, buf, nbytes);
83747061Sbrian
83847061Sbrian  return write(p->fd, buf, nbytes);
83936285Sbrian}
84036285Sbrian
84136285Sbrianint
84258028Sbrianphysical_doUpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
84346686Sbrian                     int *n, int force)
84436285Sbrian{
84536285Sbrian  struct physical *p = descriptor2physical(d);
84636285Sbrian  int sets;
84736285Sbrian
84836285Sbrian  sets = 0;
84936285Sbrian  if (p->fd >= 0) {
85036285Sbrian    if (r) {
85136285Sbrian      FD_SET(p->fd, r);
85236285Sbrian      log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
85336285Sbrian      sets++;
85436285Sbrian    }
85536285Sbrian    if (e) {
85636285Sbrian      FD_SET(p->fd, e);
85736285Sbrian      log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
85836285Sbrian      sets++;
85936285Sbrian    }
86036314Sbrian    if (w && (force || link_QueueLen(&p->link) || p->out)) {
86136285Sbrian      FD_SET(p->fd, w);
86236285Sbrian      log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
86336285Sbrian      sets++;
86436285Sbrian    }
86536285Sbrian    if (sets && *n < p->fd + 1)
86636285Sbrian      *n = p->fd + 1;
86736285Sbrian  }
86836285Sbrian
86936285Sbrian  return sets;
87036285Sbrian}
87136285Sbrian
87236285Sbrianint
87336285Sbrianphysical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
87436285Sbrian{
87552942Sbrian  if (p->handler && p->handler->removefromset)
87652942Sbrian    return (*p->handler->removefromset)(p, r, w, e);
87752942Sbrian  else {
87852942Sbrian    int sets;
87936285Sbrian
88052942Sbrian    sets = 0;
88152942Sbrian    if (p->fd >= 0) {
88252942Sbrian      if (r && FD_ISSET(p->fd, r)) {
88352942Sbrian        FD_CLR(p->fd, r);
88452942Sbrian        log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
88552942Sbrian        sets++;
88652942Sbrian      }
88752942Sbrian      if (e && FD_ISSET(p->fd, e)) {
88852942Sbrian        FD_CLR(p->fd, e);
88952942Sbrian        log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
89052942Sbrian        sets++;
89152942Sbrian      }
89252942Sbrian      if (w && FD_ISSET(p->fd, w)) {
89352942Sbrian        FD_CLR(p->fd, w);
89452942Sbrian        log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
89552942Sbrian        sets++;
89652942Sbrian      }
89736285Sbrian    }
89852942Sbrian
89952942Sbrian    return sets;
90036285Sbrian  }
90136285Sbrian}
90236285Sbrian
90336285Sbrianint
90458028Sbrianphysical_IsSet(struct fdescriptor *d, const fd_set *fdset)
90536285Sbrian{
90636285Sbrian  struct physical *p = descriptor2physical(d);
90736285Sbrian  return p->fd >= 0 && FD_ISSET(p->fd, fdset);
90836285Sbrian}
90936285Sbrian
91036285Sbrianvoid
91146686Sbrianphysical_Login(struct physical *p, const char *name)
91236285Sbrian{
91346830Sbrian  if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
91446686Sbrian    struct utmp ut;
91546686Sbrian    const char *connstr;
91652413Sbrian    char *colon;
91736285Sbrian
91846686Sbrian    memset(&ut, 0, sizeof ut);
919106966Speter    ut.ut_time = time(NULL);
92046686Sbrian    strncpy(ut.ut_name, name, sizeof ut.ut_name);
92152413Sbrian    if (p->handler && (p->handler->type == TCP_DEVICE ||
92252413Sbrian                       p->handler->type == UDP_DEVICE)) {
92352429Sbrian      strncpy(ut.ut_line, PPPOTCPLINE, sizeof ut.ut_line);
92452413Sbrian      strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host);
92552413Sbrian      colon = memchr(ut.ut_host, ':', sizeof ut.ut_host);
92652413Sbrian      if (colon)
92752413Sbrian        *colon = '\0';
92852413Sbrian    } else
92952413Sbrian      strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
93046686Sbrian    if ((connstr = getenv("CONNECT")))
93146686Sbrian      /* mgetty sets this to the connection speed */
93246686Sbrian      strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
93346686Sbrian    ID0login(&ut);
93452429Sbrian    p->Utmp = ut.ut_time;
93536285Sbrian  }
93636285Sbrian}
93736285Sbrian
93836285Sbrianint
93936285Sbrianphysical_SetMode(struct physical *p, int mode)
94036285Sbrian{
94138174Sbrian  if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
94238174Sbrian       mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
94338174Sbrian      (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
94453830Sbrian    /* Note:  The -direct -> -background is for callback ! */
94536285Sbrian    log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
94636285Sbrian               mode2Nam(p->type), mode2Nam(mode));
94736285Sbrian    return 0;
94836285Sbrian  }
94936285Sbrian  p->type = mode;
95036285Sbrian  return 1;
95136285Sbrian}
95238544Sbrian
95338544Sbrianvoid
95438544Sbrianphysical_DeleteQueue(struct physical *p)
95538544Sbrian{
95638544Sbrian  if (p->out) {
95754912Sbrian    m_freem(p->out);
95838544Sbrian    p->out = NULL;
95938544Sbrian  }
96038544Sbrian  link_DeleteQueue(&p->link);
96138544Sbrian}
96246686Sbrian
96346686Sbrianvoid
96446686Sbrianphysical_SetDevice(struct physical *p, const char *name)
96546686Sbrian{
96646686Sbrian  int len = strlen(_PATH_DEV);
96746686Sbrian
96847682Sbrian  if (name != p->name.full) {
96947682Sbrian    strncpy(p->name.full, name, sizeof p->name.full - 1);
97047682Sbrian    p->name.full[sizeof p->name.full - 1] = '\0';
97147682Sbrian  }
97246686Sbrian  p->name.base = *p->name.full == '!' ?  p->name.full + 1 :
97346686Sbrian                 strncmp(p->name.full, _PATH_DEV, len) ?
97446686Sbrian                 p->name.full : p->name.full + len;
97546686Sbrian}
97646686Sbrian
97746686Sbrianstatic void
97846686Sbrianphysical_Found(struct physical *p)
97946686Sbrian{
98047286Sbrian  FILE *lockfile;
98174001Sbrian  char fn[PATH_MAX];
98247286Sbrian
98347286Sbrian  if (*p->name.full == '/') {
98447286Sbrian    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
98547286Sbrian    lockfile = ID0fopen(fn, "w");
98647286Sbrian    if (lockfile != NULL) {
98747286Sbrian      fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
98847286Sbrian      fclose(lockfile);
98947286Sbrian    }
99047286Sbrian#ifndef RELEASE_CRUNCH
99147286Sbrian    else
99247286Sbrian      log_Printf(LogALERT, "%s: Can't create %s: %s\n",
99347286Sbrian                 p->link.name, fn, strerror(errno));
99447286Sbrian#endif
99547286Sbrian  }
99647286Sbrian
99764652Sbrian  throughput_start(&p->link.stats.total, "physical throughput",
99846686Sbrian                   Enabled(p->dl->bundle, OPT_THROUGHPUT));
99946686Sbrian  p->connect_count++;
100046686Sbrian  p->input.sz = 0;
100146686Sbrian
100246686Sbrian  log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
100346686Sbrian}
100446686Sbrian
100546686Sbrianint
1006134789Sbrianphysical_Open(struct physical *p)
100746686Sbrian{
100846686Sbrian  char *dev;
1009134789Sbrian  int devno, wasfd, err;
1010134789Sbrian  unsigned h;
101146686Sbrian
101246686Sbrian  if (p->fd >= 0)
101346686Sbrian    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
101446686Sbrian    /* We're going back into "term" mode */
101546686Sbrian  else if (p->type == PHYS_DIRECT) {
101647061Sbrian    physical_SetDevice(p, "");
101747061Sbrian    p->fd = STDIN_FILENO;
101847061Sbrian    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
101952942Sbrian      p->handler = (*devices[h].create)(p);
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