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