physical.c revision 64802
1/*
2 * Written by Eivind Eklund <eivind@yes.no>
3 *    for Yes Interactive
4 *
5 * Copyright (C) 1998, Yes Interactive.  All rights reserved.
6 *
7 * Redistribution and use in any form is permitted.  Redistribution in
8 * source form should include the above copyright and this set of
9 * conditions, because large sections american law seems to have been
10 * created by a bunch of jerks on drugs that are now illegal, forcing
11 * me to include this copyright-stuff instead of placing this in the
12 * public domain.  The name of of 'Yes Interactive' or 'Eivind Eklund'
13 * may not be used to endorse or promote products derived from this
14 * software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * $FreeBSD: head/usr.sbin/ppp/physical.c 64802 2000-08-18 00:01:44Z brian $
20 *
21 */
22
23#include <sys/param.h>
24#include <netinet/in.h>
25#include <netinet/in_systm.h>
26#include <netinet/ip.h>
27#include <sys/un.h>
28
29#include <errno.h>
30#include <fcntl.h>
31#include <paths.h>
32#ifdef NOSUID
33#include <signal.h>
34#endif
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/tty.h>	/* TIOCOUTQ */
39#include <sys/uio.h>
40#include <time.h>
41#include <unistd.h>
42#include <utmp.h>
43#if defined(__OpenBSD__) || defined(__NetBSD__)
44#include <sys/ioctl.h>
45#include <util.h>
46#else
47#include <libutil.h>
48#endif
49
50#include "layer.h"
51#ifndef NONAT
52#include "nat_cmd.h"
53#endif
54#include "proto.h"
55#include "acf.h"
56#include "vjcomp.h"
57#include "defs.h"
58#include "command.h"
59#include "mbuf.h"
60#include "log.h"
61#include "id.h"
62#include "timer.h"
63#include "fsm.h"
64#include "lqr.h"
65#include "hdlc.h"
66#include "lcp.h"
67#include "throughput.h"
68#include "sync.h"
69#include "async.h"
70#include "iplist.h"
71#include "slcompress.h"
72#include "ipcp.h"
73#include "filter.h"
74#include "descriptor.h"
75#include "ccp.h"
76#include "link.h"
77#include "physical.h"
78#include "mp.h"
79#ifndef NORADIUS
80#include "radius.h"
81#endif
82#include "bundle.h"
83#include "prompt.h"
84#include "chat.h"
85#include "auth.h"
86#include "chap.h"
87#include "cbcp.h"
88#include "datalink.h"
89#include "tcp.h"
90#include "udp.h"
91#include "exec.h"
92#include "tty.h"
93#ifndef NOI4B
94#include "i4b.h"
95#endif
96#ifndef NONETGRAPH
97#include "ether.h"
98#endif
99
100
101#define PPPOTCPLINE "ppp"
102
103static int physical_DescriptorWrite(struct fdescriptor *, struct bundle *,
104                                    const fd_set *);
105
106static int
107physical_DeviceSize(void)
108{
109  return sizeof(struct device);
110}
111
112struct {
113  struct device *(*create)(struct physical *);
114  struct device *(*iov2device)(int, struct physical *, struct iovec *,
115                               int *, int, int *, int *);
116  int (*DeviceSize)(void);
117} devices[] = {
118#ifndef NOI4B
119  { i4b_Create, i4b_iov2device, i4b_DeviceSize },
120#endif
121  { tty_Create, tty_iov2device, tty_DeviceSize },
122#ifndef NONETGRAPH
123  /* This must come before ``udp'' & ``tcp'' */
124  { ether_Create, ether_iov2device, ether_DeviceSize },
125#endif
126  { tcp_Create, tcp_iov2device, tcp_DeviceSize },
127  { udp_Create, udp_iov2device, udp_DeviceSize },
128  { exec_Create, exec_iov2device, exec_DeviceSize }
129};
130
131#define NDEVICES (sizeof devices / sizeof devices[0])
132
133static int
134physical_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
135                   int *n)
136{
137  return physical_doUpdateSet(d, r, w, e, n, 0);
138}
139
140void
141physical_SetDescriptor(struct physical *p)
142{
143  p->desc.type = PHYSICAL_DESCRIPTOR;
144  p->desc.UpdateSet = physical_UpdateSet;
145  p->desc.IsSet = physical_IsSet;
146  p->desc.Read = physical_DescriptorRead;
147  p->desc.Write = physical_DescriptorWrite;
148}
149
150struct physical *
151physical_Create(struct datalink *dl, int type)
152{
153  struct physical *p;
154
155  p = (struct physical *)malloc(sizeof(struct physical));
156  if (!p)
157    return NULL;
158
159  p->link.type = PHYSICAL_LINK;
160  p->link.name = dl->name;
161  p->link.len = sizeof *p;
162
163  /* The sample period is fixed - see physical2iov() & iov2physical() */
164  throughput_init(&p->link.stats.total, SAMPLE_PERIOD);
165  p->link.stats.parent = dl->bundle->ncp.mp.active ?
166    &dl->bundle->ncp.mp.link.stats.total : NULL;
167  p->link.stats.gather = 1;
168
169  memset(p->link.Queue, '\0', sizeof p->link.Queue);
170  memset(p->link.proto_in, '\0', sizeof p->link.proto_in);
171  memset(p->link.proto_out, '\0', sizeof p->link.proto_out);
172  link_EmptyStack(&p->link);
173
174  p->handler = NULL;
175  physical_SetDescriptor(p);
176  p->type = type;
177
178  hdlc_Init(&p->hdlc, &p->link.lcp);
179  async_Init(&p->async);
180
181  p->fd = -1;
182  p->out = NULL;
183  p->connect_count = 0;
184  p->dl = dl;
185  p->input.sz = 0;
186  *p->name.full = '\0';
187  p->name.base = p->name.full;
188
189  p->Utmp = 0;
190  p->session_owner = (pid_t)-1;
191
192  p->cfg.rts_cts = MODEM_CTSRTS;
193  p->cfg.speed = MODEM_SPEED;
194  p->cfg.parity = CS8;
195  memcpy(p->cfg.devlist, MODEM_LIST, sizeof MODEM_LIST);
196  p->cfg.ndev = NMODEMS;
197  p->cfg.cd.necessity = CD_DEFAULT;
198  p->cfg.cd.delay = 0;		/* reconfigured or device specific default */
199
200  lcp_Init(&p->link.lcp, dl->bundle, &p->link, &dl->fsmp);
201  ccp_Init(&p->link.ccp, dl->bundle, &p->link, &dl->fsmp);
202
203  return p;
204}
205
206static const struct parity {
207  const char *name;
208  const char *name1;
209  int set;
210} validparity[] = {
211  { "even", "P_EVEN", CS7 | PARENB },
212  { "odd", "P_ODD", CS7 | PARENB | PARODD },
213  { "none", "P_ZERO", CS8 },
214  { NULL, 0 },
215};
216
217static int
218GetParityValue(const char *str)
219{
220  const struct parity *pp;
221
222  for (pp = validparity; pp->name; pp++) {
223    if (strcasecmp(pp->name, str) == 0 ||
224	strcasecmp(pp->name1, str) == 0) {
225      return pp->set;
226    }
227  }
228  return (-1);
229}
230
231int
232physical_SetParity(struct physical *p, const char *str)
233{
234  struct termios rstio;
235  int val;
236
237  val = GetParityValue(str);
238  if (val > 0) {
239    p->cfg.parity = val;
240    if (p->fd >= 0) {
241      tcgetattr(p->fd, &rstio);
242      rstio.c_cflag &= ~(CSIZE | PARODD | PARENB);
243      rstio.c_cflag |= val;
244      tcsetattr(p->fd, TCSADRAIN, &rstio);
245    }
246    return 0;
247  }
248  log_Printf(LogWARN, "%s: %s: Invalid parity\n", p->link.name, str);
249  return -1;
250}
251
252int
253physical_GetSpeed(struct physical *p)
254{
255  if (p->handler && p->handler->speed)
256    return (*p->handler->speed)(p);
257
258  return 0;
259}
260
261int
262physical_SetSpeed(struct physical *p, int speed)
263{
264  if (IntToSpeed(speed) != B0) {
265      p->cfg.speed = speed;
266      return 1;
267  }
268
269  return 0;
270}
271
272int
273physical_Raw(struct physical *p)
274{
275  if (p->handler && p->handler->raw)
276    return (*p->handler->raw)(p);
277
278  return 1;
279}
280
281void
282physical_Offline(struct physical *p)
283{
284  if (p->handler && p->handler->offline)
285    (*p->handler->offline)(p);
286  log_Printf(LogPHASE, "%s: Disconnected!\n", p->link.name);
287}
288
289static int
290physical_Lock(struct physical *p)
291{
292  int res;
293
294  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
295      (res = ID0uu_lock(p->name.base)) != UU_LOCK_OK) {
296    if (res == UU_LOCK_INUSE)
297      log_Printf(LogPHASE, "%s: %s is in use\n", p->link.name, p->name.full);
298    else
299      log_Printf(LogPHASE, "%s: %s is in use: uu_lock: %s\n",
300                 p->link.name, p->name.full, uu_lockerr(res));
301    return 0;
302  }
303
304  return 1;
305}
306
307static void
308physical_Unlock(struct physical *p)
309{
310  char fn[MAXPATHLEN];
311  if (*p->name.full == '/' && p->type != PHYS_DIRECT &&
312      ID0uu_unlock(p->name.base) == -1)
313    log_Printf(LogALERT, "%s: Can't uu_unlock %s\n", p->link.name, fn);
314}
315
316void
317physical_Close(struct physical *p)
318{
319  int newsid;
320  char fn[MAXPATHLEN];
321
322  if (p->fd < 0)
323    return;
324
325  log_Printf(LogDEBUG, "%s: Close\n", p->link.name);
326
327  if (p->handler && p->handler->cooked)
328    (*p->handler->cooked)(p);
329
330  physical_StopDeviceTimer(p);
331  if (p->Utmp) {
332    if (p->handler && (p->handler->type == TCP_DEVICE ||
333                       p->handler->type == UDP_DEVICE))
334      /* Careful - we logged in on line ``ppp'' with IP as our host */
335      ID0logout(PPPOTCPLINE, 1);
336    else
337      ID0logout(p->name.base, 0);
338    p->Utmp = 0;
339  }
340  newsid = tcgetpgrp(p->fd) == getpgrp();
341  close(p->fd);
342  p->fd = -1;
343  log_SetTtyCommandMode(p->dl);
344
345  throughput_stop(&p->link.stats.total);
346  throughput_log(&p->link.stats.total, LogPHASE, p->link.name);
347
348  if (p->session_owner != (pid_t)-1) {
349    log_Printf(LogPHASE, "%s: HUPing %d\n", p->link.name,
350               (int)p->session_owner);
351    ID0kill(p->session_owner, SIGHUP);
352    p->session_owner = (pid_t)-1;
353  }
354
355  if (newsid)
356    bundle_setsid(p->dl->bundle, 0);
357
358  if (*p->name.full == '/') {
359    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
360#ifndef RELEASE_CRUNCH
361    if (ID0unlink(fn) == -1)
362      log_Printf(LogALERT, "%s: Can't remove %s: %s\n",
363                 p->link.name, fn, strerror(errno));
364#else
365    ID0unlink(fn);
366#endif
367  }
368  physical_Unlock(p);
369  if (p->handler && p->handler->destroy)
370    (*p->handler->destroy)(p);
371  p->handler = NULL;
372  p->name.base = p->name.full;
373  *p->name.full = '\0';
374}
375
376void
377physical_Destroy(struct physical *p)
378{
379  physical_Close(p);
380  throughput_destroy(&p->link.stats.total);
381  free(p);
382}
383
384static int
385physical_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle,
386                         const fd_set *fdset)
387{
388  struct physical *p = descriptor2physical(d);
389  int nw, result = 0;
390
391  if (p->out == NULL)
392    p->out = link_Dequeue(&p->link);
393
394  if (p->out) {
395    nw = physical_Write(p, MBUF_CTOP(p->out), p->out->m_len);
396    log_Printf(LogDEBUG, "%s: DescriptorWrite: wrote %d(%lu) to %d\n",
397               p->link.name, nw, (unsigned long)p->out->m_len, p->fd);
398    if (nw > 0) {
399      p->out->m_len -= nw;
400      p->out->m_offset += nw;
401      if (p->out->m_len == 0)
402	p->out = m_free(p->out);
403      result = 1;
404    } else if (nw < 0) {
405      if (errno != EAGAIN) {
406	log_Printf(LogPHASE, "%s: write (%d): %s\n", p->link.name,
407                   p->fd, strerror(errno));
408        datalink_Down(p->dl, CLOSE_NORMAL);
409      }
410      result = 1;
411    }
412    /* else we shouldn't really have been called !  select() is broken ! */
413  }
414
415  return result;
416}
417
418int
419physical_ShowStatus(struct cmdargs const *arg)
420{
421  struct physical *p = arg->cx->physical;
422  struct cd *cd;
423  const char *dev;
424  int n;
425
426  prompt_Printf(arg->prompt, "Name: %s\n", p->link.name);
427  prompt_Printf(arg->prompt, " State:           ");
428  if (p->fd < 0)
429    prompt_Printf(arg->prompt, "closed\n");
430  else if (p->handler && p->handler->openinfo)
431    prompt_Printf(arg->prompt, "open (%s)\n", (*p->handler->openinfo)(p));
432  else
433    prompt_Printf(arg->prompt, "open\n");
434
435  prompt_Printf(arg->prompt, " Device:          %s",
436                *p->name.full ?  p->name.full :
437                p->type == PHYS_DIRECT ? "unknown" : "N/A");
438  if (p->session_owner != (pid_t)-1)
439    prompt_Printf(arg->prompt, " (session owner: %d)", (int)p->session_owner);
440
441  prompt_Printf(arg->prompt, "\n Link Type:       %s\n", mode2Nam(p->type));
442  prompt_Printf(arg->prompt, " Connect Count:   %d\n", p->connect_count);
443#ifdef TIOCOUTQ
444  if (p->fd >= 0 && ioctl(p->fd, TIOCOUTQ, &n) >= 0)
445      prompt_Printf(arg->prompt, " Physical outq:   %d\n", n);
446#endif
447
448  prompt_Printf(arg->prompt, " Queued Packets:  %lu\n",
449                (u_long)link_QueueLen(&p->link));
450  prompt_Printf(arg->prompt, " Phone Number:    %s\n", arg->cx->phone.chosen);
451
452  prompt_Printf(arg->prompt, "\nDefaults:\n");
453
454  prompt_Printf(arg->prompt, " Device List:     ");
455  dev = p->cfg.devlist;
456  for (n = 0; n < p->cfg.ndev; n++) {
457    if (n)
458      prompt_Printf(arg->prompt, ", ");
459    prompt_Printf(arg->prompt, "\"%s\"", dev);
460    dev += strlen(dev) + 1;
461  }
462
463  prompt_Printf(arg->prompt, "\n Characteristics: ");
464  if (physical_IsSync(arg->cx->physical))
465    prompt_Printf(arg->prompt, "sync");
466  else
467    prompt_Printf(arg->prompt, "%dbps", p->cfg.speed);
468
469  switch (p->cfg.parity & CSIZE) {
470  case CS7:
471    prompt_Printf(arg->prompt, ", cs7");
472    break;
473  case CS8:
474    prompt_Printf(arg->prompt, ", cs8");
475    break;
476  }
477  if (p->cfg.parity & PARENB) {
478    if (p->cfg.parity & PARODD)
479      prompt_Printf(arg->prompt, ", odd parity");
480    else
481      prompt_Printf(arg->prompt, ", even parity");
482  } else
483    prompt_Printf(arg->prompt, ", no parity");
484
485  prompt_Printf(arg->prompt, ", CTS/RTS %s\n", (p->cfg.rts_cts ? "on" : "off"));
486
487  prompt_Printf(arg->prompt, " CD check delay:  ");
488  cd = p->handler ? &p->handler->cd : &p->cfg.cd;
489  if (cd->necessity == CD_NOTREQUIRED)
490    prompt_Printf(arg->prompt, "no cd");
491  else if (p->cfg.cd.necessity == CD_DEFAULT) {
492    prompt_Printf(arg->prompt, "device specific");
493  } else {
494    prompt_Printf(arg->prompt, "%d second%s", p->cfg.cd.delay,
495                  p->cfg.cd.delay == 1 ? "" : "s");
496    if (p->cfg.cd.necessity == CD_REQUIRED)
497      prompt_Printf(arg->prompt, " (required!)");
498  }
499  prompt_Printf(arg->prompt, "\n\n");
500
501  throughput_disp(&p->link.stats.total, arg->prompt);
502
503  return 0;
504}
505
506void
507physical_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
508                     const fd_set *fdset)
509{
510  struct physical *p = descriptor2physical(d);
511  u_char *rbuff;
512  int n, found;
513
514  rbuff = p->input.buf + p->input.sz;
515
516  /* something to read */
517  n = physical_Read(p, rbuff, sizeof p->input.buf - p->input.sz);
518  log_Printf(LogDEBUG, "%s: DescriptorRead: read %d/%d from %d\n",
519             p->link.name, n, (int)(sizeof p->input.buf - p->input.sz), p->fd);
520  if (n <= 0) {
521    if (n < 0)
522      log_Printf(LogPHASE, "%s: read (%d): %s\n", p->link.name, p->fd,
523                 strerror(errno));
524    else
525      log_Printf(LogPHASE, "%s: read (%d): Got zero bytes\n",
526                 p->link.name, p->fd);
527    datalink_Down(p->dl, CLOSE_NORMAL);
528    return;
529  }
530
531  rbuff -= p->input.sz;
532  n += p->input.sz;
533
534  if (p->link.lcp.fsm.state <= ST_CLOSED) {
535    if (p->type != PHYS_DEDICATED) {
536      found = hdlc_Detect((u_char const **)&rbuff, n, physical_IsSync(p));
537      if (rbuff != p->input.buf)
538        log_WritePrompts(p->dl, "%.*s", (int)(rbuff - p->input.buf),
539                         p->input.buf);
540      p->input.sz = n - (rbuff - p->input.buf);
541
542      if (found) {
543        /* LCP packet is detected. Turn ourselves into packet mode */
544        log_Printf(LogPHASE, "%s: PPP packet detected, coming up\n",
545                   p->link.name);
546        log_SetTtyCommandMode(p->dl);
547        datalink_Up(p->dl, 0, 1);
548        link_PullPacket(&p->link, rbuff, p->input.sz, bundle);
549        p->input.sz = 0;
550      } else
551        bcopy(rbuff, p->input.buf, p->input.sz);
552    } else
553      /* In -dedicated mode, we just discard input until LCP is started */
554      p->input.sz = 0;
555  } else if (n > 0)
556    link_PullPacket(&p->link, rbuff, n, bundle);
557}
558
559struct physical *
560iov2physical(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
561             int fd, int *auxfd, int *nauxfd)
562{
563  struct physical *p;
564  int len, h, type;
565
566  p = (struct physical *)iov[(*niov)++].iov_base;
567  p->link.name = dl->name;
568  memset(p->link.Queue, '\0', sizeof p->link.Queue);
569
570  p->desc.UpdateSet = physical_UpdateSet;
571  p->desc.IsSet = physical_IsSet;
572  p->desc.Read = physical_DescriptorRead;
573  p->desc.Write = physical_DescriptorWrite;
574  p->type = PHYS_DIRECT;
575  p->dl = dl;
576  len = strlen(_PATH_DEV);
577  p->out = NULL;
578  p->connect_count = 1;
579
580  physical_SetDevice(p, p->name.full);
581
582  p->link.lcp.fsm.bundle = dl->bundle;
583  p->link.lcp.fsm.link = &p->link;
584  memset(&p->link.lcp.fsm.FsmTimer, '\0', sizeof p->link.lcp.fsm.FsmTimer);
585  memset(&p->link.lcp.fsm.OpenTimer, '\0', sizeof p->link.lcp.fsm.OpenTimer);
586  memset(&p->link.lcp.fsm.StoppedTimer, '\0',
587         sizeof p->link.lcp.fsm.StoppedTimer);
588  p->link.lcp.fsm.parent = &dl->fsmp;
589  lcp_SetupCallbacks(&p->link.lcp);
590
591  p->link.ccp.fsm.bundle = dl->bundle;
592  p->link.ccp.fsm.link = &p->link;
593  /* Our in.state & out.state are NULL (no link-level ccp yet) */
594  memset(&p->link.ccp.fsm.FsmTimer, '\0', sizeof p->link.ccp.fsm.FsmTimer);
595  memset(&p->link.ccp.fsm.OpenTimer, '\0', sizeof p->link.ccp.fsm.OpenTimer);
596  memset(&p->link.ccp.fsm.StoppedTimer, '\0',
597         sizeof p->link.ccp.fsm.StoppedTimer);
598  p->link.ccp.fsm.parent = &dl->fsmp;
599  ccp_SetupCallbacks(&p->link.ccp);
600
601  p->hdlc.lqm.owner = &p->link.lcp;
602  p->hdlc.ReportTimer.state = TIMER_STOPPED;
603  p->hdlc.lqm.timer.state = TIMER_STOPPED;
604
605  p->fd = fd;
606  p->link.stats.total.in.SampleOctets = (long long *)iov[(*niov)++].iov_base;
607  p->link.stats.total.out.SampleOctets = (long long *)iov[(*niov)++].iov_base;
608  p->link.stats.parent = dl->bundle->ncp.mp.active ?
609    &dl->bundle->ncp.mp.link.stats.total : NULL;
610  p->link.stats.gather = 1;
611
612  type = (long)p->handler;
613  p->handler = NULL;
614  for (h = 0; h < NDEVICES && p->handler == NULL; h++)
615    p->handler = (*devices[h].iov2device)(type, p, iov, niov, maxiov,
616                                          auxfd, nauxfd);
617  if (p->handler == NULL) {
618    log_Printf(LogPHASE, "%s: Unknown link type\n", p->link.name);
619    free(iov[(*niov)++].iov_base);
620    physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
621  } else
622    log_Printf(LogPHASE, "%s: Device %s, link type is %s\n",
623               p->link.name, p->name.full, p->handler->name);
624
625  if (p->hdlc.lqm.method && p->hdlc.lqm.timer.load)
626    lqr_reStart(&p->link.lcp);
627  hdlc_StartTimer(&p->hdlc);
628
629  throughput_restart(&p->link.stats.total, "physical throughput",
630                     Enabled(dl->bundle, OPT_THROUGHPUT));
631
632  return p;
633}
634
635int
636physical_MaxDeviceSize()
637{
638  int biggest, sz, n;
639
640  biggest = sizeof(struct device);
641  for (sz = n = 0; n < NDEVICES; n++)
642    if (devices[n].DeviceSize) {
643      sz = (*devices[n].DeviceSize)();
644      if (biggest < sz)
645        biggest = sz;
646    }
647
648  return biggest;
649}
650
651int
652physical2iov(struct physical *p, struct iovec *iov, int *niov, int maxiov,
653             int *auxfd, int *nauxfd)
654{
655  struct device *h;
656  int sz;
657
658  h = NULL;
659  if (p) {
660    hdlc_StopTimer(&p->hdlc);
661    lqr_StopTimer(p);
662    timer_Stop(&p->link.lcp.fsm.FsmTimer);
663    timer_Stop(&p->link.ccp.fsm.FsmTimer);
664    timer_Stop(&p->link.lcp.fsm.OpenTimer);
665    timer_Stop(&p->link.ccp.fsm.OpenTimer);
666    timer_Stop(&p->link.lcp.fsm.StoppedTimer);
667    timer_Stop(&p->link.ccp.fsm.StoppedTimer);
668    if (p->handler) {
669      h = p->handler;
670      p->handler = (struct device *)(long)p->handler->type;
671    }
672
673    if (Enabled(p->dl->bundle, OPT_KEEPSESSION) ||
674        tcgetpgrp(p->fd) == getpgrp())
675      p->session_owner = getpid();      /* So I'll eventually get HUP'd */
676    else
677      p->session_owner = (pid_t)-1;
678    timer_Stop(&p->link.stats.total.Timer);
679  }
680
681  if (*niov + 2 >= maxiov) {
682    log_Printf(LogERROR, "physical2iov: No room for physical + throughput"
683               " + device !\n");
684    if (p)
685      free(p);
686    return -1;
687  }
688
689  iov[*niov].iov_base = (void *)p;
690  iov[*niov].iov_len = sizeof *p;
691  (*niov)++;
692
693  iov[*niov].iov_base = p ? (void *)p->link.stats.total.in.SampleOctets : NULL;
694  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
695  (*niov)++;
696  iov[*niov].iov_base = p ? (void *)p->link.stats.total.out.SampleOctets : NULL;
697  iov[*niov].iov_len = SAMPLE_PERIOD * sizeof(long long);
698  (*niov)++;
699
700  sz = physical_MaxDeviceSize();
701  if (p) {
702    if (h && h->device2iov)
703      (*h->device2iov)(h, iov, niov, maxiov, auxfd, nauxfd);
704    else {
705      iov[*niov].iov_base = malloc(sz);
706      if (h)
707        memcpy(iov[*niov].iov_base, h, sizeof *h);
708      iov[*niov].iov_len = sz;
709      (*niov)++;
710    }
711  } else {
712    iov[*niov].iov_base = NULL;
713    iov[*niov].iov_len = sz;
714    (*niov)++;
715  }
716
717  return p ? p->fd : 0;
718}
719
720const char *
721physical_LockedDevice(struct physical *p)
722{
723  if (p->fd >= 0 && *p->name.full == '/' && p->type != PHYS_DIRECT)
724    return p->name.base;
725
726  return NULL;
727}
728
729void
730physical_ChangedPid(struct physical *p, pid_t newpid)
731{
732  if (physical_LockedDevice(p)) {
733    int res;
734
735    if ((res = ID0uu_lock_txfr(p->name.base, newpid)) != UU_LOCK_OK)
736      log_Printf(LogPHASE, "uu_lock_txfr: %s\n", uu_lockerr(res));
737  }
738}
739
740int
741physical_IsSync(struct physical *p)
742{
743   return p->cfg.speed == 0;
744}
745
746const char *physical_GetDevice(struct physical *p)
747{
748   return p->name.full;
749}
750
751void
752physical_SetDeviceList(struct physical *p, int argc, const char *const *argv)
753{
754  int f, pos;
755
756  p->cfg.devlist[sizeof p->cfg.devlist - 1] = '\0';
757  for (f = 0, pos = 0; f < argc && pos < sizeof p->cfg.devlist - 1; f++) {
758    if (pos)
759      p->cfg.devlist[pos++] = '\0';
760    strncpy(p->cfg.devlist + pos, argv[f], sizeof p->cfg.devlist - pos - 1);
761    pos += strlen(p->cfg.devlist + pos);
762  }
763  p->cfg.ndev = f;
764}
765
766void
767physical_SetSync(struct physical *p)
768{
769   p->cfg.speed = 0;
770}
771
772int
773physical_SetRtsCts(struct physical *p, int enable)
774{
775   p->cfg.rts_cts = enable ? 1 : 0;
776   return 1;
777}
778
779ssize_t
780physical_Read(struct physical *p, void *buf, size_t nbytes)
781{
782  ssize_t ret;
783
784  if (p->handler && p->handler->read)
785    ret = (*p->handler->read)(p, buf, nbytes);
786  else
787    ret = read(p->fd, buf, nbytes);
788
789  log_DumpBuff(LogPHYSICAL, "read", buf, ret);
790
791  return ret;
792}
793
794ssize_t
795physical_Write(struct physical *p, const void *buf, size_t nbytes)
796{
797  log_DumpBuff(LogPHYSICAL, "write", buf, nbytes);
798
799  if (p->handler && p->handler->write)
800    return (*p->handler->write)(p, buf, nbytes);
801
802  return write(p->fd, buf, nbytes);
803}
804
805int
806physical_doUpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
807                     int *n, int force)
808{
809  struct physical *p = descriptor2physical(d);
810  int sets;
811
812  sets = 0;
813  if (p->fd >= 0) {
814    if (r) {
815      FD_SET(p->fd, r);
816      log_Printf(LogTIMER, "%s: fdset(r) %d\n", p->link.name, p->fd);
817      sets++;
818    }
819    if (e) {
820      FD_SET(p->fd, e);
821      log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, p->fd);
822      sets++;
823    }
824    if (w && (force || link_QueueLen(&p->link) || p->out)) {
825      FD_SET(p->fd, w);
826      log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, p->fd);
827      sets++;
828    }
829    if (sets && *n < p->fd + 1)
830      *n = p->fd + 1;
831  }
832
833  return sets;
834}
835
836int
837physical_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
838{
839  if (p->handler && p->handler->removefromset)
840    return (*p->handler->removefromset)(p, r, w, e);
841  else {
842    int sets;
843
844    sets = 0;
845    if (p->fd >= 0) {
846      if (r && FD_ISSET(p->fd, r)) {
847        FD_CLR(p->fd, r);
848        log_Printf(LogTIMER, "%s: fdunset(r) %d\n", p->link.name, p->fd);
849        sets++;
850      }
851      if (e && FD_ISSET(p->fd, e)) {
852        FD_CLR(p->fd, e);
853        log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, p->fd);
854        sets++;
855      }
856      if (w && FD_ISSET(p->fd, w)) {
857        FD_CLR(p->fd, w);
858        log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, p->fd);
859        sets++;
860      }
861    }
862
863    return sets;
864  }
865}
866
867int
868physical_IsSet(struct fdescriptor *d, const fd_set *fdset)
869{
870  struct physical *p = descriptor2physical(d);
871  return p->fd >= 0 && FD_ISSET(p->fd, fdset);
872}
873
874void
875physical_Login(struct physical *p, const char *name)
876{
877  if (p->type == PHYS_DIRECT && *p->name.base && !p->Utmp) {
878    struct utmp ut;
879    const char *connstr;
880    char *colon;
881
882    memset(&ut, 0, sizeof ut);
883    time(&ut.ut_time);
884    strncpy(ut.ut_name, name, sizeof ut.ut_name);
885    if (p->handler && (p->handler->type == TCP_DEVICE ||
886                       p->handler->type == UDP_DEVICE)) {
887      strncpy(ut.ut_line, PPPOTCPLINE, sizeof ut.ut_line);
888      strncpy(ut.ut_host, p->name.base, sizeof ut.ut_host);
889      colon = memchr(ut.ut_host, ':', sizeof ut.ut_host);
890      if (colon)
891        *colon = '\0';
892    } else
893      strncpy(ut.ut_line, p->name.base, sizeof ut.ut_line);
894    if ((connstr = getenv("CONNECT")))
895      /* mgetty sets this to the connection speed */
896      strncpy(ut.ut_host, connstr, sizeof ut.ut_host);
897    ID0login(&ut);
898    p->Utmp = ut.ut_time;
899  }
900}
901
902int
903physical_SetMode(struct physical *p, int mode)
904{
905  if ((p->type & (PHYS_DIRECT|PHYS_DEDICATED) ||
906       mode & (PHYS_DIRECT|PHYS_DEDICATED)) &&
907      (!(p->type & PHYS_DIRECT) || !(mode & PHYS_BACKGROUND))) {
908    /* Note:  The -direct -> -background is for callback ! */
909    log_Printf(LogWARN, "%s: Cannot change mode %s to %s\n", p->link.name,
910               mode2Nam(p->type), mode2Nam(mode));
911    return 0;
912  }
913  p->type = mode;
914  return 1;
915}
916
917void
918physical_DeleteQueue(struct physical *p)
919{
920  if (p->out) {
921    m_freem(p->out);
922    p->out = NULL;
923  }
924  link_DeleteQueue(&p->link);
925}
926
927void
928physical_SetDevice(struct physical *p, const char *name)
929{
930  int len = strlen(_PATH_DEV);
931
932  if (name != p->name.full) {
933    strncpy(p->name.full, name, sizeof p->name.full - 1);
934    p->name.full[sizeof p->name.full - 1] = '\0';
935  }
936  p->name.base = *p->name.full == '!' ?  p->name.full + 1 :
937                 strncmp(p->name.full, _PATH_DEV, len) ?
938                 p->name.full : p->name.full + len;
939}
940
941static void
942physical_Found(struct physical *p)
943{
944  FILE *lockfile;
945  char fn[MAXPATHLEN];
946
947  if (*p->name.full == '/') {
948    snprintf(fn, sizeof fn, "%s%s.if", _PATH_VARRUN, p->name.base);
949    lockfile = ID0fopen(fn, "w");
950    if (lockfile != NULL) {
951      fprintf(lockfile, "%s%d\n", TUN_NAME, p->dl->bundle->unit);
952      fclose(lockfile);
953    }
954#ifndef RELEASE_CRUNCH
955    else
956      log_Printf(LogALERT, "%s: Can't create %s: %s\n",
957                 p->link.name, fn, strerror(errno));
958#endif
959  }
960
961  throughput_start(&p->link.stats.total, "physical throughput",
962                   Enabled(p->dl->bundle, OPT_THROUGHPUT));
963  p->connect_count++;
964  p->input.sz = 0;
965
966  log_Printf(LogPHASE, "%s: Connected!\n", p->link.name);
967}
968
969int
970physical_Open(struct physical *p, struct bundle *bundle)
971{
972  int devno, h, wasfd, err;
973  char *dev;
974
975  if (p->fd >= 0)
976    log_Printf(LogDEBUG, "%s: Open: Modem is already open!\n", p->link.name);
977    /* We're going back into "term" mode */
978  else if (p->type == PHYS_DIRECT) {
979    physical_SetDevice(p, "");
980    p->fd = STDIN_FILENO;
981    for (h = 0; h < NDEVICES && p->handler == NULL && p->fd >= 0; h++)
982      p->handler = (*devices[h].create)(p);
983    if (p->fd >= 0) {
984      if (p->handler == NULL) {
985        physical_SetupStack(p, "unknown", PHYSICAL_NOFORCE);
986        log_Printf(LogDEBUG, "%s: stdin is unidentified\n", p->link.name);
987      }
988      physical_Found(p);
989    }
990  } else {
991    dev = p->cfg.devlist;
992    devno = 0;
993    while (devno < p->cfg.ndev && p->fd < 0) {
994      physical_SetDevice(p, dev);
995      if (physical_Lock(p)) {
996        err = 0;
997
998        if (*p->name.full == '/') {
999          p->fd = ID0open(p->name.full, O_RDWR | O_NONBLOCK);
1000          if (p->fd < 0)
1001            err = errno;
1002        }
1003
1004        wasfd = p->fd;
1005        for (h = 0; h < NDEVICES && p->handler == NULL; h++)
1006          if ((p->handler = (*devices[h].create)(p)) == NULL && wasfd != p->fd)
1007            break;
1008
1009        if (p->fd < 0) {
1010          if (h == NDEVICES) {
1011            if (err)
1012	      log_Printf(LogWARN, "%s: %s: %s\n", p->link.name, p->name.full,
1013                         strerror(errno));
1014            else
1015	      log_Printf(LogWARN, "%s: Device (%s) must begin with a '/',"
1016                         " a '!' or contain at least one ':'\n", p->link.name,
1017                         p->name.full);
1018          }
1019          physical_Unlock(p);
1020        } else
1021          physical_Found(p);
1022      }
1023      dev += strlen(dev) + 1;
1024      devno++;
1025    }
1026  }
1027
1028  return p->fd;
1029}
1030
1031void
1032physical_SetupStack(struct physical *p, const char *who, int how)
1033{
1034  link_EmptyStack(&p->link);
1035  if (how == PHYSICAL_FORCE_SYNC || how == PHYSICAL_FORCE_SYNCNOACF ||
1036      (how == PHYSICAL_NOFORCE && physical_IsSync(p)))
1037    link_Stack(&p->link, &synclayer);
1038  else {
1039    link_Stack(&p->link, &asynclayer);
1040    link_Stack(&p->link, &hdlclayer);
1041  }
1042  if (how != PHYSICAL_FORCE_SYNCNOACF)
1043    link_Stack(&p->link, &acflayer);
1044  link_Stack(&p->link, &protolayer);
1045  link_Stack(&p->link, &lqrlayer);
1046  link_Stack(&p->link, &ccplayer);
1047  link_Stack(&p->link, &vjlayer);
1048#ifndef NONAT
1049  link_Stack(&p->link, &natlayer);
1050#endif
1051  if (how == PHYSICAL_FORCE_ASYNC && physical_IsSync(p)) {
1052    log_Printf(LogWARN, "Sync device setting ignored for ``%s'' device\n", who);
1053    p->cfg.speed = MODEM_SPEED;
1054  } else if (how == PHYSICAL_FORCE_SYNC && !physical_IsSync(p)) {
1055    log_Printf(LogWARN, "Async device setting ignored for ``%s'' device\n",
1056               who);
1057    physical_SetSync(p);
1058  }
1059}
1060
1061void
1062physical_StopDeviceTimer(struct physical *p)
1063{
1064  if (p->handler && p->handler->stoptimer)
1065    (*p->handler->stoptimer)(p);
1066}
1067
1068int
1069physical_AwaitCarrier(struct physical *p)
1070{
1071  if (p->handler && p->handler->awaitcarrier)
1072    return (*p->handler->awaitcarrier)(p);
1073
1074  return CARRIER_OK;
1075}
1076