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