Added -vjccid and vj-max-slots options, and reorganized in
[ppp.git] / pppd / sys-osf.c
1 /*
2  * sys-osf.c - System-dependent procedures for setting up
3  * PPP interfaces on OSF/1 systems which use the STREAMS ppp interface.
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by Carnegie Mellon University.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20
21 #ifndef lint
22 static char rcsid[] = "$Id: sys-osf.c,v 1.4 1995/05/01 00:26:01 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <syslog.h>
33 #include <termios.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <time.h>
37 #include <utmp.h>
38 #include <poll.h>
39 #include <signal.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/time.h>
43 #include <sys/stream.h>
44 #include <sys/stropts.h>
45
46 #include <net/if.h>
47 #include <net/ppp_defs.h>
48 #include <net/ppp_str.h>
49 #include <net/route.h>
50 #include <net/if_arp.h>
51 #include <netinet/in.h>
52
53 #include "pppd.h"
54
55 #ifndef ifr_mtu
56 #define ifr_mtu         ifr_metric
57 #endif
58
59 #define MAXMODULES      10      /* max number of module names to save */
60 static struct   modlist {
61     char        modname[FMNAMESZ+1];
62 } str_modules[MAXMODULES];
63 static int      str_module_count = 0;
64 static int      pushed_ppp;
65 static int      closed_stdio;
66
67 static int      restore_term;   /* 1 => we've munged the terminal */
68 static struct termios inittermios; /* Initial TTY termios */
69 static struct winsize wsinfo;      /* Initial window size info */
70
71 int sockfd;                     /* socket for doing interface ioctls */
72
73 int ttyfd = -1;   /*  Original ttyfd if we did a streamify()  */
74
75 /*
76  * sys_init - System-dependent initialization.
77  */
78 void
79 sys_init()
80 {
81     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
82     setlogmask(LOG_UPTO(LOG_INFO));
83     if (debug)
84         setlogmask(LOG_UPTO(LOG_DEBUG));
85
86     /* Get an internet socket for doing socket ioctl's on. */
87     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
88         syslog(LOG_ERR, "Couldn't create IP socket: %m");
89         die(1);
90     }
91 }
92
93 /*
94  * note_debug_level - note a change in the debug level.
95  */
96 void
97 note_debug_level()
98 {
99     if (debug) {
100         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
101         setlogmask(LOG_UPTO(LOG_DEBUG));
102     } else {
103         setlogmask(LOG_UPTO(LOG_WARNING));
104     }
105 }
106
107 /*
108  * daemon - Detach us from the terminal session.
109  */
110 int
111 daemon(nochdir, noclose)
112     int nochdir, noclose;
113 {
114     int pid;
115
116     if ((pid = fork()) < 0)
117         return -1;
118     if (pid != 0)
119         exit(0);                /* parent dies */
120     setsid();
121     if (!nochdir)
122         chdir("/");
123     if (!noclose) {
124         fclose(stdin);          /* don't need stdin, stdout, stderr */
125         fclose(stdout);
126         fclose(stderr);
127     }
128     return 0;
129 }
130
131
132 char pipename[] = "/dev/streams/pipe";
133
134 /*
135  * ppp_available - check if this kernel supports PPP.
136  */
137 int
138 ppp_available()
139 {
140     int fd, ret;
141
142     fd = open(pipename, O_RDONLY, 0);
143     if (fd < 0)
144         return 0;               /* can't find out - assume we don't have ppp */
145     ret = ioctl(fd, I_FIND, "pppasync") >= 0;
146     close(fd);
147     return ret;
148 }
149
150
151 /*
152  *  streampipe -- Opens a STREAMS based pipe.  Used by streamify().
153  */
154
155 int 
156 streampipe(int fd[2])
157 {
158     if ((fd[0]=open(pipename, O_RDWR)) == -1)
159         return(-1);
160     else if ((fd[1]=open(pipename, O_RDWR)) == -1) {
161         close(fd[0]);
162         return(-1);
163     } else if (ioctl(fd[0], I_PIPE, fd[1]) != 0) {
164         close(fd[0]);
165         close(fd[1]);
166         return(-1);
167     } else {
168         return(ioctl(fd[0], I_PUSH, "pipemod"));
169     }
170 }
171
172 /*
173  *  streamify -- Needed for DEC OSF/1, since tty devices are not STREAMS
174  *               modules (but ptys are, and pipes can be).
175  */
176
177 #define BUFFSIZE 1000     /*  Size of buffer for streamify()  */
178
179 int 
180 streamify(int fd)
181 {
182     int fdes[2];
183     fd_set readfds;
184     int ret, fret, rret, maxfd;
185     static char buffer[BUFFSIZE];
186     struct sigaction sa;
187
188     if (streampipe(fdes) != 0)
189         syslog(LOG_ERR, "streampipe(): %m\n");
190     else if (isastream(fdes[0]) == 1) {
191         if ((fret=fork()) < 0) {
192             syslog(LOG_ERR, "fork(): %m\n");
193         } else if (fret == 0) {
194             /*  Process to forward things from pipe to tty  */
195             sigemptyset(&(sa.sa_mask));
196             sa.sa_handler = SIG_DFL;
197             sa.sa_flags = 0;
198             sigaction(SIGHUP, &sa, NULL);   /*  Go back to default actions */
199             sigaction(SIGINT, &sa, NULL);   /*  for changed signals.  */
200             sigaction(SIGTERM, &sa, NULL);
201             sigaction(SIGCHLD, &sa, NULL);
202             sigaction(SIGUSR1, &sa, NULL);
203             sigaction(SIGUSR2, &sa, NULL);
204             close(fdes[0]);
205
206             maxfd = (fdes[1]>fd)?fdes[1]:fd;
207             while (1) {
208                 FD_ZERO(&readfds);
209                 FD_SET(fdes[1], &readfds);
210                 FD_SET(fd, &readfds);
211                 ret = select(maxfd+1, &readfds, NULL, NULL, NULL);
212                 if (FD_ISSET(fd, &readfds)) {
213                     rret = read(fd, buffer, BUFFSIZE);
214                     if (rret == 0) {
215                         MAINDEBUG((LOG_DEBUG, "slave died:  EOF on tty."));
216                         exit(0);
217                     } else {
218                         write(fdes[1], buffer, rret);
219                     }
220                 }
221                 if (FD_ISSET(fdes[1], &readfds)) {
222                     rret = read(fdes[1], buffer, BUFFSIZE);
223                     if (rret == 0) {
224                         MAINDEBUG((LOG_DEBUG, "slave died:  EOF on pipe."));
225                         exit(0);
226                     } else {
227                         write(fd, buffer, rret);
228                     }
229                 }
230             }
231         } else {
232             close(fdes[1]);
233             ttyfd = fd;
234             return(fdes[0]);
235         }
236     }
237
238     return(-1);
239 }
240
241
242 /*
243  * establish_ppp - Turn the serial port into a ppp interface.
244  */
245 void
246 establish_ppp()
247 {
248     int ret;
249
250     if (isastream(fd) != 1) {
251         if ((fd=streamify(fd)) < 0) {
252             syslog(LOG_ERR, "Couldn't get a STREAMS module!\n");
253             die(1);
254         }
255     }
256
257     /* go through and save the name of all the modules, then pop em */
258     for (;;) { 
259         if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
260             ioctl(fd, I_POP, 0) < 0)
261             break;
262         MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
263                    str_modules[str_module_count].modname));
264         str_module_count++;
265     }
266
267     /* now push the async/fcs module */
268     if (ioctl(fd, I_PUSH, "pppasync") < 0) {
269         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
270         die(1);
271     }
272     /* push the compress module */
273     if (ioctl(fd, I_PUSH, "pppcomp") < 0) {
274         syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m");
275     }
276     /* finally, push the ppp_if module that actually handles the */
277     /* network interface */ 
278     if (ioctl(fd, I_PUSH, "pppif") < 0) {
279         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
280         die(1);
281     }
282     pushed_ppp = 1;
283     /* read mode, message non-discard mode */
284     if (ioctl(fd, I_SRDOPT, RMSGN|RPROTNORM) < 0) {
285         syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
286         die(1);
287     }
288     /*
289      * Find out which interface we were given.
290      * (ppp_if handles this ioctl)
291      */
292     if (ioctl(fd, (int)SIOCGETU, &ifunit) < 0) {
293         syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
294         die(1);
295     }
296
297     /* Set debug flags in driver */
298     if (ioctl(fd, (int)SIOCSIFDEBUG, &kdebugflag) < 0) {
299         syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
300     }
301
302     /* close stdin, stdout, stderr if they might refer to the device */
303     if (default_device && !closed_stdio) {
304         int i;
305
306         for (i = 0; i <= 2; ++i)
307             if (i != fd && i != sockfd) 
308                 close(i);
309         closed_stdio = 1;
310     }
311 }
312
313 /*  Debugging routine....  */
314
315 void prstrstack(int fd)
316 {
317     struct str_list sl;
318     struct str_mlist names[20];
319     int ret, i;
320
321     sl.sl_modlist = names;
322
323     ret = ioctl(fd, I_LIST, &sl);
324
325     if (ret >= 0) {
326         MAINDEBUG((LOG_DEBUG, "Current streams modules:\n"));
327         for (i=0; i<sl.sl_nmods; i++)
328             MAINDEBUG((LOG_DEBUG,"    %s\n", names[i].l_name));
329     } else {
330         MAINDEBUG((LOG_DEBUG,"I_LIST ioctl() failed.\n"));
331     }
332 }
333
334
335 /*
336  * disestablish_ppp - Restore the serial port to normal operation.
337  * It attempts to reconstruct the stream with the previously popped
338  * modules.  This shouldn't call die() because it's called from die().
339  */
340 void
341 disestablish_ppp()
342 {
343     int flags;
344     char *s;
345
346     if (hungup) {
347         /* we can't push or pop modules after the stream has hung up */
348         str_module_count = 0;
349         restore_term = 0;       /* nor can we fix up terminal settings */
350         return;
351     }
352
353     if (pushed_ppp) {
354         /*
355          * Check whether the link seems not to be 8-bit clean.
356          */
357         if (ioctl(fd, (int)SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
358             s = NULL;
359             switch (~flags & PAI_FLAGS_HIBITS) {
360               case PAI_FLAGS_B7_0:
361                 s = "bit 7 set to 1";
362                 break;
363               case PAI_FLAGS_B7_1:
364                 s = "bit 7 set to 0";
365                 break;
366               case PAI_FLAGS_PAR_EVEN:
367                 s = "odd parity";
368                 break;
369               case PAI_FLAGS_PAR_ODD:
370                 s = "even parity";
371                 break;
372             }
373             if (s != NULL) {
374                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
375                 syslog(LOG_WARNING, "All received characters had %s", s);
376             }
377         }
378
379         while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */
380             ;
381         pushed_ppp = 0;
382
383         for (; str_module_count > 0; str_module_count--) {
384             if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
385                 if (errno != ENXIO)
386                     syslog(LOG_WARNING, "str_restore: couldn't push module %s: %m",
387                            str_modules[str_module_count-1].modname);
388             } else {
389                 MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
390                            str_modules[str_module_count-1].modname));
391             }
392         }
393
394         if (ttyfd >= 0) {
395             close(fd);
396             fd = ttyfd;
397             ttyfd = -1;
398         }
399     }
400
401 }
402
403
404 /*
405  * List of valid speeds.
406  */
407 struct speed {
408     int speed_int, speed_val;
409 } speeds[] = {
410 #ifdef B50
411     { 50, B50 },
412 #endif
413 #ifdef B75
414     { 75, B75 },
415 #endif
416 #ifdef B110
417     { 110, B110 },
418 #endif
419 #ifdef B134
420     { 134, B134 },
421 #endif
422 #ifdef B150
423     { 150, B150 },
424 #endif
425 #ifdef B200
426     { 200, B200 },
427 #endif
428 #ifdef B300
429     { 300, B300 },
430 #endif
431 #ifdef B600
432     { 600, B600 },
433 #endif
434 #ifdef B1200
435     { 1200, B1200 },
436 #endif
437 #ifdef B1800
438     { 1800, B1800 },
439 #endif
440 #ifdef B2000
441     { 2000, B2000 },
442 #endif
443 #ifdef B2400
444     { 2400, B2400 },
445 #endif
446 #ifdef B3600
447     { 3600, B3600 },
448 #endif
449 #ifdef B4800
450     { 4800, B4800 },
451 #endif
452 #ifdef B7200
453     { 7200, B7200 },
454 #endif
455 #ifdef B9600
456     { 9600, B9600 },
457 #endif
458 #ifdef B19200
459     { 19200, B19200 },
460 #endif
461 #ifdef B38400
462     { 38400, B38400 },
463 #endif
464 #ifdef EXTA
465     { 19200, EXTA },
466 #endif
467 #ifdef EXTB
468     { 38400, EXTB },
469 #endif
470 #ifdef B57600
471     { 57600, B57600 },
472 #endif
473 #ifdef B115200
474     { 115200, B115200 },
475 #endif
476     { 0, 0 }
477 };
478
479 /*
480  * Translate from bits/second to a speed_t.
481  */
482 int
483 translate_speed(bps)
484     int bps;
485 {
486     struct speed *speedp;
487
488     if (bps == 0)
489         return 0;
490     for (speedp = speeds; speedp->speed_int; speedp++)
491         if (bps == speedp->speed_int)
492             return speedp->speed_val;
493     syslog(LOG_WARNING, "speed %d not supported", bps);
494     return 0;
495 }
496
497 /*
498  * Translate from a speed_t to bits/second.
499  */
500 int
501 baud_rate_of(speed)
502     int speed;
503 {
504     struct speed *speedp;
505
506     if (speed == 0)
507         return 0;
508     for (speedp = speeds; speedp->speed_int; speedp++)
509         if (speed == speedp->speed_val)
510             return speedp->speed_int;
511     return 0;
512 }
513
514 /*
515  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
516  * at the requested speed, etc.  If `local' is true, set CLOCAL
517  * regardless of whether the modem option was specified.
518  */
519 void
520 set_up_tty(fd, local)
521     int fd, local;
522 {
523     int speed;
524     struct termios tios;
525
526     if (tcgetattr(fd, &tios) < 0) {
527         syslog(LOG_ERR, "tcgetattr: %m");
528         die(1);
529     }
530
531     if (!restore_term) {
532         inittermios = tios;
533         ioctl(fd, TIOCGWINSZ, &wsinfo);
534     }
535
536     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
537     if (crtscts > 0)
538         tios.c_cflag |= CRTSCTS;
539     else if (crtscts < 0)
540         tios.c_cflag &= ~CRTSCTS;
541
542     tios.c_cflag |= CS8 | CREAD | HUPCL;
543     if (local || !modem)
544         tios.c_cflag |= CLOCAL;
545     tios.c_iflag = IGNBRK | IGNPAR;
546     tios.c_oflag = 0;
547     tios.c_lflag = 0;
548     tios.c_cc[VMIN] = 1;
549     tios.c_cc[VTIME] = 0;
550
551     if (crtscts == 2) {
552         tios.c_iflag |= IXOFF;
553         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
554         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
555     }
556
557     speed = translate_speed(inspeed);
558     if (speed) {
559         cfsetospeed(&tios, speed);
560         cfsetispeed(&tios, speed);
561     } else {
562         speed = cfgetospeed(&tios);
563         /*
564          * We can't proceed if the serial port speed is B0,
565          * since that implies that the serial port is disabled.
566          */
567         if (speed == B0) {
568             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
569                    devnam);
570             die(1);
571         }
572     }
573
574     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
575         syslog(LOG_ERR, "tcsetattr: %m");
576         die(1);
577     }
578
579     baud_rate = inspeed = baud_rate_of(speed);
580     restore_term = 1;
581 }
582
583 /*
584  * restore_tty - restore the terminal to the saved settings.
585  */
586 void
587 restore_tty()
588 {
589     if (restore_term) {
590         if (!default_device) {
591             /*
592              * Turn off echoing, because otherwise we can get into
593              * a loop with the tty and the modem echoing to each other.
594              * We presume we are the sole user of this tty device, so
595              * when we close it, it will revert to its defaults anyway.
596              */
597             inittermios.c_lflag &= ~(ECHO | ECHONL);
598         }
599         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
600             if (errno != ENXIO)
601                 syslog(LOG_WARNING, "tcsetattr: %m");
602         ioctl(fd, TIOCSWINSZ, &wsinfo);
603         restore_term = 0;
604     }
605 }
606
607 /*
608  * setdtr - control the DTR line on the serial port.
609  * This is called from die(), so it shouldn't call die().
610  */
611 void
612 setdtr(fd, on)
613 int fd, on;
614 {
615     int modembits = TIOCM_DTR;
616
617     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
618 }
619
620
621 /*
622  * output - Output PPP packet.
623  */
624 void
625 output(unit, p, len)
626     int unit;
627     u_char *p;
628     int len;
629 {
630     struct strbuf       str;
631
632     if (unit != 0)
633         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
634     if (debug)
635         log_packet(p, len, "sent ");
636
637     str.len = len;
638     str.buf = (caddr_t) p;
639     if (putmsg(fd, NULL, &str, 0) < 0) {
640         if (errno != ENXIO) {
641             syslog(LOG_ERR, "putmsg: %m");
642             die(1);
643         }
644     }
645 }
646
647 /*
648  * wait_input - wait for input, for a length of time specified in *timo.
649  */
650 void
651 wait_input(timo)
652     struct timeval *timo;
653 {
654     int t;
655     struct pollfd pfd;
656
657     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
658     pfd.fd = fd;
659     pfd.events = POLLIN | POLLPRI | POLLHUP;
660     if (poll(&pfd, 1, t) < 0 && errno != EINTR) {
661         syslog(LOG_ERR, "poll: %m");
662         die(1);
663     }
664 }
665
666 /*
667  * read_packet - get a PPP packet from the serial device.
668  */
669 int
670 read_packet(buf)
671     u_char *buf;
672 {
673     struct strbuf str, ctl;
674     int len, i;
675     unsigned char ctlbuf[16];
676
677     str.maxlen = PPP_MTU + PPP_HDRLEN;
678     str.buf = (caddr_t) buf;
679     ctl.maxlen = sizeof(ctlbuf);
680     ctl.buf = (caddr_t) ctlbuf;
681     i = 0;
682     len = getmsg(fd, &ctl, &str, &i);
683     if (len < 0) {
684         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
685             return -1;
686         }
687         syslog(LOG_ERR, "getmsg(fd) %m");
688         die(1);
689     }
690     if (len) 
691         MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
692     if (ctl.len > 0)
693         syslog(LOG_NOTICE, "got ctrl msg len %d %x %x\n", ctl.len,
694                ctlbuf[0], ctlbuf[1]);
695
696     if (str.len < 0) {
697         MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
698         return -1;
699     }
700
701     return str.len;
702 }
703
704
705 /*
706  * ppp_send_config - configure the transmit characteristics of
707  * the ppp interface.
708  */
709 void
710 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
711     int unit, mtu;
712     u_int32_t asyncmap;
713     int pcomp, accomp;
714 {
715     char c;
716     struct ifreq ifr;
717
718     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
719     ifr.ifr_mtu = mtu;
720     if (ioctl(sockfd, (int)SIOCSIPMTU, (caddr_t) &ifr) < 0) {
721         syslog(LOG_ERR, "ioctl(SIOCSIPMTU): %m");
722         quit();
723     }
724
725     if(ioctl(fd, (int)SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
726         syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
727         quit();
728     }
729
730     c = (pcomp? 1: 0);
731     if(ioctl(fd, (int)SIOCSIFCOMPPROT, &c) < 0) {
732         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
733         quit();
734     }
735
736     c = (accomp? 1: 0);
737     if(ioctl(fd, (int)SIOCSIFCOMPAC, &c) < 0) {
738         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
739         quit();
740     }
741 }
742
743
744 /*
745  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
746  */
747 void
748 ppp_set_xaccm(unit, accm)
749     int unit;
750     ext_accm accm;
751 {
752     if (ioctl(fd, (int)SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY)
753         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
754 }
755
756
757 /*
758  * ppp_recv_config - configure the receive-side characteristics of
759  * the ppp interface.
760  */
761 void
762 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
763     int unit, mru;
764     u_int32_t asyncmap;
765     int pcomp, accomp;
766 {
767     char c;
768
769     if (ioctl(fd, (int)SIOCSIFMRU, &mru) < 0) {
770         syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
771     }
772
773     if (ioctl(fd, (int)SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
774         syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
775     }
776
777     c = 2 + (pcomp? 1: 0);
778     if(ioctl(fd, (int)SIOCSIFCOMPPROT, &c) < 0) {
779         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
780     }
781
782     c = 2 + (accomp? 1: 0);
783     if (ioctl(fd, (int)SIOCSIFCOMPAC, &c) < 0) {
784         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
785     }
786 }
787
788 /*
789  * ccp_test - ask kernel whether a given compression method
790  * is acceptable for use.
791  */
792 int
793 ccp_test(unit, opt_ptr, opt_len, for_transmit)
794     int unit, opt_len, for_transmit;
795     u_char *opt_ptr;
796 {
797     struct ppp_option_data data;
798
799     if ((unsigned) opt_len > MAX_PPP_OPTION)
800         opt_len = MAX_PPP_OPTION;
801     data.length = opt_len;
802     data.transmit = for_transmit;
803     BCOPY(opt_ptr, data.opt_data, opt_len);
804     return ioctl(fd, (int)SIOCSCOMPRESS, (caddr_t) &data) >= 0;
805 }
806
807 /*
808  * ccp_flags_set - inform kernel about the current state of CCP.
809  */
810 void
811 ccp_flags_set(unit, isopen, isup)
812     int unit, isopen, isup;
813 {
814     int x;
815
816     x = (isopen? 1: 0) + (isup? 2: 0);
817     if (ioctl(fd, (int)SIOCSIFCOMP, (caddr_t) &x) < 0 && errno != ENOTTY)
818         syslog(LOG_ERR, "ioctl (SIOCSIFCOMP): %m");
819 }
820
821 /*
822  * ccp_fatal_error - returns 1 if decompression was disabled as a
823  * result of an error detected after decompression of a packet,
824  * 0 otherwise.  This is necessary because of patent nonsense.
825  */
826 int
827 ccp_fatal_error(unit)
828     int unit;
829 {
830     int x;
831
832     if (ioctl(fd, (int)SIOCGIFCOMP, (caddr_t) &x) < 0) {
833         syslog(LOG_ERR, "ioctl(SIOCGIFCOMP): %m");
834         return 0;
835     }
836     return x & CCP_FATALERROR;
837 }
838
839 /*
840  * sifvjcomp - config tcp header compression
841  */
842 int
843 sifvjcomp(u, vjcomp, cidcomp, maxcid)
844     int u, vjcomp, cidcomp, maxcid;
845 {
846     char x;
847
848     x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
849     if (ioctl(fd, (int)SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
850         syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
851         return 0;
852     }
853     return 1;
854 }
855
856 /*
857  * sifup - Config the interface up and enable IP packets to pass.
858  */
859 int
860 sifup(u)
861     int u;
862 {
863     struct ifreq ifr;
864     struct npioctl npi;
865
866     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
867     if (ioctl(sockfd, (int)SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
868         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
869         return 0;
870     }
871     ifr.ifr_flags |= IFF_UP;
872     if (ioctl(sockfd, (int)SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
873         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
874         return 0;
875     }
876     npi.protocol = PPP_IP;
877     npi.mode = NPMODE_PASS;
878     if (ioctl(fd, (int)SIOCSETNPMODE, &npi) < 0) {
879         if (errno != ENOTTY) {
880             syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
881             return 0;
882         }
883     }
884     return 1;
885 }
886
887 /*
888  * sifdown - Config the interface down.
889  */
890 int
891 sifdown(u)
892     int u;
893 {
894     struct ifreq ifr;
895     int rv;
896     struct npioctl npi;
897
898     rv = 1;
899     npi.protocol = PPP_IP;
900     npi.mode = NPMODE_ERROR;
901     if (ioctl(fd, (int)SIOCSETNPMODE, (caddr_t) &npi) < 0) {
902         if (errno != ENOTTY) {
903             syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
904             rv = 0;
905         }
906     }
907
908     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
909     if (ioctl(sockfd, (int)SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
910         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
911         rv = 0;
912     } else {
913         ifr.ifr_flags &= ~IFF_UP;
914         if (ioctl(sockfd, (int)SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
915             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
916             rv = 0;
917         }
918     }
919     return rv;
920 }
921
922 /*
923  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
924  */
925 #define SET_SA_FAMILY(addr, family)             \
926     BZERO((char *) &(addr), sizeof(addr));      \
927     addr.sa_family = (family);
928
929 /*
930  * sifaddr - Config the interface IP addresses and netmask.
931  */
932 int
933 sifaddr(u, o, h, m)
934     int u;
935     u_int32_t o, h, m;
936 {
937     int ret;
938     struct ifreq ifr;
939
940     ret = 1;
941     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
942     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
943     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
944     if (ioctl(sockfd, (int)SIOCSIFADDR, (caddr_t) &ifr) < 0) {
945         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
946         ret = 0;
947     }
948     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
949     if (ioctl(sockfd, (int)SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
950         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
951         ret = 0;
952     }
953     if (m != 0) {
954         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
955         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
956         if (ioctl(sockfd, (int)SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
957             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
958             ret = 0;
959         }
960     }
961
962 /*  Reset if address --- This is stupid, but seems to be necessary...  */
963
964     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
965     if (ioctl(sockfd, (int)SIOCSIFADDR, (caddr_t) &ifr) < 0) {
966         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
967         ret = 0;
968     }
969
970     return ret;
971 }
972
973 /*
974  * cifaddr - Clear the interface IP addresses, and delete routes
975  * through the interface if possible.
976  */
977 int
978 cifaddr(u, o, h)
979     int u;
980     u_int32_t o, h;
981 {
982     struct ortentry rt;
983
984     SET_SA_FAMILY(rt.rt_dst, AF_INET);
985     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
986     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
987     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
988     rt.rt_flags = RTF_HOST;
989     if (ioctl(sockfd, (int)SIOCDELRT, (caddr_t) &rt) < 0) {
990         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
991         return 0;
992     }
993     return 1;
994 }
995
996 /*
997  * sifdefaultroute - assign a default route through the address given.
998  */
999 int
1000 sifdefaultroute(u, g)
1001     int u;
1002     u_int32_t g;
1003 {
1004     struct ortentry rt;
1005
1006     SET_SA_FAMILY(rt.rt_dst, AF_INET);
1007     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
1008     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
1009     rt.rt_flags = RTF_GATEWAY;
1010     if (ioctl(sockfd, (int)SIOCADDRT, &rt) < 0) {
1011         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
1012         return 0;
1013     }
1014     return 1;
1015 }
1016
1017 /*
1018  * cifdefaultroute - delete a default route through the address given.
1019  */
1020 int
1021 cifdefaultroute(u, g)
1022     int u;
1023     u_int32_t g;
1024 {
1025     struct ortentry rt;
1026
1027     SET_SA_FAMILY(rt.rt_dst, AF_INET);
1028     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
1029     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
1030     rt.rt_flags = RTF_GATEWAY;
1031     if (ioctl(sockfd, (int)SIOCDELRT, &rt) < 0) {
1032         syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
1033         return 0;
1034     }
1035     return 1;
1036 }
1037
1038 /*
1039  * sifproxyarp - Make a proxy ARP entry for the peer.
1040  */
1041 int
1042 sifproxyarp(unit, hisaddr)
1043     int unit;
1044     u_int32_t hisaddr;
1045 {
1046     struct arpreq arpreq;
1047
1048     BZERO(&arpreq, sizeof(arpreq));
1049
1050     /*
1051      * Get the hardware address of an interface on the same subnet
1052      * as our local address.
1053      */
1054     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
1055         syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP");
1056         return 0;
1057     }
1058
1059     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1060     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1061     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1062     if (ioctl(sockfd, (int)SIOCSARP, (caddr_t)&arpreq) < 0) {
1063         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
1064         return 0;
1065     }
1066
1067     return 1;
1068 }
1069
1070 /*
1071  * cifproxyarp - Delete the proxy ARP entry for the peer.
1072  */
1073 int
1074 cifproxyarp(unit, hisaddr)
1075     int unit;
1076     u_int32_t hisaddr;
1077 {
1078     struct arpreq arpreq;
1079
1080     BZERO(&arpreq, sizeof(arpreq));
1081     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1082     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1083     if (ioctl(sockfd, (int)SIOCDARP, (caddr_t)&arpreq) < 0) {
1084         syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
1085         return 0;
1086     }
1087     return 1;
1088 }
1089
1090 /*
1091  * get_ether_addr - get the hardware address of an interface on the
1092  * the same subnet as ipaddr.
1093  */
1094 #define MAX_IFS         32
1095
1096 int s;
1097
1098 int
1099 get_ether_addr(ipaddr, hwaddr)
1100     u_int ipaddr;
1101     struct sockaddr *hwaddr;
1102 {
1103     struct ifreq *ifr, *ifend, *ifp;
1104     u_int ina, mask;
1105     struct sockaddr_dl *dla;
1106     struct ifreq ifreq;
1107     struct ifconf ifc;
1108     struct ifreq ifs[MAX_IFS];
1109     struct ifdevea ifdevreq;
1110
1111     ifc.ifc_len = sizeof(ifs);
1112     ifc.ifc_req = ifs;
1113     if (ioctl(sockfd, (int)SIOCGIFCONF, &ifc) < 0) {
1114         perror("ioctl(SIOCGIFCONF)");
1115         return 0;
1116     }
1117
1118     /*
1119      * Scan through looking for an interface with an Internet
1120      * address on the same subnet as `ipaddr'.
1121      */
1122     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1123     for (ifr = ifc.ifc_req; ifr < ifend; ) {
1124         if (ifr->ifr_addr.sa_family == AF_INET) {
1125             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1126             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1127             /*
1128              * Check that the interface is up, and not point-to-point
1129              * or loopback.
1130              */
1131             if (ioctl(sockfd, (int)SIOCGIFFLAGS, &ifreq) < 0)
1132                 continue;
1133             if ((ifreq.ifr_flags &
1134                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1135                  != (IFF_UP|IFF_BROADCAST))
1136                 continue;
1137             /*
1138              * Get its netmask and check that it's on the right subnet.
1139              */
1140             if (ioctl(sockfd, (int)SIOCGIFNETMASK, &ifreq) < 0)
1141                 continue;
1142             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1143             if ((ipaddr & mask) != (ina & mask))
1144                 continue;
1145
1146             break;
1147         }
1148         ifr++;
1149     }
1150
1151     if (ifr >= ifend)
1152         return 0;
1153     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1154
1155     strncpy(ifdevreq.ifr_name, ifr->ifr_name, sizeof(ifdevreq.ifr_name));
1156
1157     if (ioctl(sockfd, (int)SIOCRPHYSADDR, &ifdevreq) < 0) {
1158         perror("ioctl(SIOCRPHYSADDR)");
1159         return(0);
1160     }
1161
1162     hwaddr->sa_family = AF_UNSPEC;
1163     memcpy(hwaddr->sa_data, ifdevreq.current_pa, sizeof(ifdevreq.current_pa));
1164     return(1);
1165 }
1166
1167
1168 /*
1169  * Return user specified netmask, modified by any mask we might determine
1170  * for address `addr' (in network byte order).
1171  * Here we scan through the system's list of interfaces, looking for
1172  * any non-point-to-point interfaces which might appear to be on the same
1173  * network as `addr'.  If we find any, we OR in their netmask to the
1174  * user-specified netmask.
1175  */
1176 u_int32_t
1177 GetMask(addr)
1178     u_int32_t addr;
1179 {
1180     u_int32_t mask, nmask, ina;
1181     struct ifreq *ifr, *ifend, ifreq;
1182     struct ifconf ifc;
1183     struct ifreq ifs[MAX_IFS];
1184
1185     addr = ntohl(addr);
1186     if (IN_CLASSA(addr))        /* determine network mask for address class */
1187         nmask = IN_CLASSA_NET;
1188     else if (IN_CLASSB(addr))
1189         nmask = IN_CLASSB_NET;
1190     else
1191         nmask = IN_CLASSC_NET;
1192     /* class D nets are disallowed by bad_ip_adrs */
1193     mask = netmask | htonl(nmask);
1194
1195     /*
1196      * Scan through the system's network interfaces.
1197      */
1198     ifc.ifc_len = sizeof(ifs);
1199     ifc.ifc_req = ifs;
1200     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1201         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1202         return mask;
1203     }
1204     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1205     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1206         /*
1207          * Check the interface's internet address.
1208          */
1209         if (ifr->ifr_addr.sa_family != AF_INET)
1210             continue;
1211         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1212         if ((ntohl(ina) & nmask) != (addr & nmask))
1213             continue;
1214         /*
1215          * Check that the interface is up, and not point-to-point or loopback.
1216          */
1217         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1218         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1219             continue;
1220         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1221             != IFF_UP)
1222             continue;
1223         /*
1224          * Get its netmask and OR it into our mask.
1225          */
1226         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1227             continue;
1228         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1229     }
1230
1231     return mask;
1232 }
1233
1234
1235 #define WTMPFILE        "/usr/adm/wtmp"
1236 #include <sys/stat.h>
1237
1238 void
1239 logwtmp(line, name, host)
1240     char *line, *name, *host;
1241 {
1242     int fd;
1243     struct stat buf;
1244     struct utmp ut;
1245
1246     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1247         return;
1248     if (!fstat(fd, &buf)) {
1249         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1250         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1251         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1252         (void)time(&ut.ut_time);
1253         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1254             (void)ftruncate(fd, buf.st_size);
1255     }
1256     close(fd);
1257 }
1258
1259 /*
1260  * Code for locking/unlocking the serial device.
1261  * This code is derived from chat.c.
1262  */
1263
1264 #ifndef LOCK_DIR
1265 #  ifdef HDB
1266 #   define      PIDSTRING
1267 #   define      LOCK_PREFIX     "/usr/spool/locks/LCK.."
1268 #  else /* HDB */
1269 #   define      LOCK_PREFIX     "/usr/spool/uucp/LCK.."
1270 #  endif /* HDB */
1271 #endif /* LOCK_DIR */
1272
1273 static char *lock_file;
1274
1275 /*
1276  * lock - create a lock file for the named device
1277  */
1278 int
1279 lock(dev)
1280     char *dev;
1281 {
1282     char hdb_lock_buffer[12];
1283     int fd, pid, n;
1284     char *p;
1285
1286     if ((p = strrchr(dev, '/')) != NULL)
1287         dev = p + 1;
1288     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1289     if (lock_file == NULL)
1290         novm("lock file name");
1291     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1292
1293     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1294         if (errno == EEXIST
1295             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1296             /* Read the lock file to find out who has the device locked */
1297 #ifdef PIDSTRING
1298             n = read(fd, hdb_lock_buffer, 11);
1299             if (n > 0) {
1300                 hdb_lock_buffer[n] = 0;
1301                 pid = atoi(hdb_lock_buffer);
1302             }
1303 #else
1304             n = read(fd, &pid, sizeof(pid));
1305 #endif
1306             if (n <= 0) {
1307                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1308                 close(fd);
1309             } else {
1310                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1311                     /* pid no longer exists - remove the lock file */
1312                     if (unlink(lock_file) == 0) {
1313                         close(fd);
1314                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1315                                dev, pid);
1316                         continue;
1317                     } else
1318                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1319                                dev);
1320                 } else
1321                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1322                            dev, pid);
1323             }
1324             close(fd);
1325         } else
1326             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1327         free(lock_file);
1328         lock_file = NULL;
1329         return -1;
1330     }
1331
1332 # ifdef PIDSTRING
1333     sprintf(hdb_lock_buffer, "%10d\n", getpid());
1334     write(fd, hdb_lock_buffer, 11);
1335 # else
1336     pid = getpid();
1337     write(fd, &pid, sizeof pid);
1338 # endif
1339
1340     close(fd);
1341     return 0;
1342 }
1343
1344 /*
1345  * unlock - remove our lockfile
1346  */
1347 void
1348 unlock()
1349 {
1350     if (lock_file) {
1351         unlink(lock_file);
1352         free(lock_file);
1353         lock_file = NULL;
1354     }
1355 }
1356