don't use sa_len from interface conf list
[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.3 1995/04/28 06:26:23 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 (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
591             if (errno != ENXIO)
592                 syslog(LOG_WARNING, "tcsetattr: %m");
593         ioctl(fd, TIOCSWINSZ, &wsinfo);
594         restore_term = 0;
595     }
596 }
597
598 /*
599  * setdtr - control the DTR line on the serial port.
600  * This is called from die(), so it shouldn't call die().
601  */
602 void
603 setdtr(fd, on)
604 int fd, on;
605 {
606     int modembits = TIOCM_DTR;
607
608     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
609 }
610
611
612 /*
613  * output - Output PPP packet.
614  */
615 void
616 output(unit, p, len)
617     int unit;
618     u_char *p;
619     int len;
620 {
621     struct strbuf       str;
622
623     if (unit != 0)
624         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
625     if (debug)
626         log_packet(p, len, "sent ");
627
628     str.len = len;
629     str.buf = (caddr_t) p;
630     if (putmsg(fd, NULL, &str, 0) < 0) {
631         if (errno != ENXIO) {
632             syslog(LOG_ERR, "putmsg: %m");
633             die(1);
634         }
635     }
636 }
637
638 /*
639  * wait_input - wait for input, for a length of time specified in *timo.
640  */
641 void
642 wait_input(timo)
643     struct timeval *timo;
644 {
645     int t;
646     struct pollfd pfd;
647
648     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
649     pfd.fd = fd;
650     pfd.events = POLLIN | POLLPRI | POLLHUP;
651     if (poll(&pfd, 1, t) < 0 && errno != EINTR) {
652         syslog(LOG_ERR, "poll: %m");
653         die(1);
654     }
655 }
656
657 /*
658  * read_packet - get a PPP packet from the serial device.
659  */
660 int
661 read_packet(buf)
662     u_char *buf;
663 {
664     struct strbuf str, ctl;
665     int len, i;
666     unsigned char ctlbuf[16];
667
668     str.maxlen = PPP_MTU + PPP_HDRLEN;
669     str.buf = (caddr_t) buf;
670     ctl.maxlen = sizeof(ctlbuf);
671     ctl.buf = (caddr_t) ctlbuf;
672     i = 0;
673     len = getmsg(fd, &ctl, &str, &i);
674     if (len < 0) {
675         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
676             return -1;
677         }
678         syslog(LOG_ERR, "getmsg(fd) %m");
679         die(1);
680     }
681     if (len) 
682         MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
683     if (ctl.len > 0)
684         syslog(LOG_NOTICE, "got ctrl msg len %d %x %x\n", ctl.len,
685                ctlbuf[0], ctlbuf[1]);
686
687     if (str.len < 0) {
688         MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
689         return -1;
690     }
691
692     return str.len;
693 }
694
695
696 /*
697  * ppp_send_config - configure the transmit characteristics of
698  * the ppp interface.
699  */
700 void
701 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
702     int unit, mtu;
703     u_int32_t asyncmap;
704     int pcomp, accomp;
705 {
706     char c;
707     struct ifreq ifr;
708
709     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
710     ifr.ifr_mtu = mtu;
711     if (ioctl(sockfd, (int)SIOCSIPMTU, (caddr_t) &ifr) < 0) {
712         syslog(LOG_ERR, "ioctl(SIOCSIPMTU): %m");
713         quit();
714     }
715
716     if(ioctl(fd, (int)SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
717         syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
718         quit();
719     }
720
721     c = (pcomp? 1: 0);
722     if(ioctl(fd, (int)SIOCSIFCOMPPROT, &c) < 0) {
723         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
724         quit();
725     }
726
727     c = (accomp? 1: 0);
728     if(ioctl(fd, (int)SIOCSIFCOMPAC, &c) < 0) {
729         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
730         quit();
731     }
732 }
733
734
735 /*
736  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
737  */
738 void
739 ppp_set_xaccm(unit, accm)
740     int unit;
741     ext_accm accm;
742 {
743     if (ioctl(fd, (int)SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY)
744         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
745 }
746
747
748 /*
749  * ppp_recv_config - configure the receive-side characteristics of
750  * the ppp interface.
751  */
752 void
753 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
754     int unit, mru;
755     u_int32_t asyncmap;
756     int pcomp, accomp;
757 {
758     char c;
759
760     if (ioctl(fd, (int)SIOCSIFMRU, &mru) < 0) {
761         syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
762     }
763
764     if (ioctl(fd, (int)SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
765         syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
766     }
767
768     c = 2 + (pcomp? 1: 0);
769     if(ioctl(fd, (int)SIOCSIFCOMPPROT, &c) < 0) {
770         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
771     }
772
773     c = 2 + (accomp? 1: 0);
774     if (ioctl(fd, (int)SIOCSIFCOMPAC, &c) < 0) {
775         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
776     }
777 }
778
779 /*
780  * ccp_test - ask kernel whether a given compression method
781  * is acceptable for use.
782  */
783 int
784 ccp_test(unit, opt_ptr, opt_len, for_transmit)
785     int unit, opt_len, for_transmit;
786     u_char *opt_ptr;
787 {
788     struct ppp_option_data data;
789
790     if ((unsigned) opt_len > MAX_PPP_OPTION)
791         opt_len = MAX_PPP_OPTION;
792     data.length = opt_len;
793     data.transmit = for_transmit;
794     BCOPY(opt_ptr, data.opt_data, opt_len);
795     return ioctl(fd, (int)SIOCSCOMPRESS, (caddr_t) &data) >= 0;
796 }
797
798 /*
799  * ccp_flags_set - inform kernel about the current state of CCP.
800  */
801 void
802 ccp_flags_set(unit, isopen, isup)
803     int unit, isopen, isup;
804 {
805     int x;
806
807     x = (isopen? 1: 0) + (isup? 2: 0);
808     if (ioctl(fd, (int)SIOCSIFCOMP, (caddr_t) &x) < 0 && errno != ENOTTY)
809         syslog(LOG_ERR, "ioctl (SIOCSIFCOMP): %m");
810 }
811
812 /*
813  * ccp_fatal_error - returns 1 if decompression was disabled as a
814  * result of an error detected after decompression of a packet,
815  * 0 otherwise.  This is necessary because of patent nonsense.
816  */
817 int
818 ccp_fatal_error(unit)
819     int unit;
820 {
821     int x;
822
823     if (ioctl(fd, (int)SIOCGIFCOMP, (caddr_t) &x) < 0) {
824         syslog(LOG_ERR, "ioctl(SIOCGIFCOMP): %m");
825         return 0;
826     }
827     return x & CCP_FATALERROR;
828 }
829
830 /*
831  * sifvjcomp - config tcp header compression
832  */
833 int
834 sifvjcomp(u, vjcomp, cidcomp, maxcid)
835     int u, vjcomp, cidcomp, maxcid;
836 {
837     char x;
838
839     x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
840     if (ioctl(fd, (int)SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
841         syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
842         return 0;
843     }
844     return 1;
845 }
846
847 /*
848  * sifup - Config the interface up and enable IP packets to pass.
849  */
850 int
851 sifup(u)
852     int u;
853 {
854     struct ifreq ifr;
855     struct npioctl npi;
856
857     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
858     if (ioctl(sockfd, (int)SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
859         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
860         return 0;
861     }
862     ifr.ifr_flags |= IFF_UP;
863     if (ioctl(sockfd, (int)SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
864         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
865         return 0;
866     }
867     npi.protocol = PPP_IP;
868     npi.mode = NPMODE_PASS;
869     if (ioctl(fd, (int)SIOCSETNPMODE, &npi) < 0) {
870         if (errno != ENOTTY) {
871             syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
872             return 0;
873         }
874     }
875     return 1;
876 }
877
878 /*
879  * sifdown - Config the interface down.
880  */
881 int
882 sifdown(u)
883     int u;
884 {
885     struct ifreq ifr;
886     int rv;
887     struct npioctl npi;
888
889     rv = 1;
890     npi.protocol = PPP_IP;
891     npi.mode = NPMODE_ERROR;
892     if (ioctl(fd, (int)SIOCSETNPMODE, (caddr_t) &npi) < 0) {
893         if (errno != ENOTTY) {
894             syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
895             rv = 0;
896         }
897     }
898
899     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
900     if (ioctl(sockfd, (int)SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
901         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
902         rv = 0;
903     } else {
904         ifr.ifr_flags &= ~IFF_UP;
905         if (ioctl(sockfd, (int)SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
906             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
907             rv = 0;
908         }
909     }
910     return rv;
911 }
912
913 /*
914  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
915  */
916 #define SET_SA_FAMILY(addr, family)             \
917     BZERO((char *) &(addr), sizeof(addr));      \
918     addr.sa_family = (family);
919
920 /*
921  * sifaddr - Config the interface IP addresses and netmask.
922  */
923 int
924 sifaddr(u, o, h, m)
925     int u;
926     u_int32_t o, h, m;
927 {
928     int ret;
929     struct ifreq ifr;
930
931     ret = 1;
932     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
933     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
934     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
935     if (ioctl(sockfd, (int)SIOCSIFADDR, (caddr_t) &ifr) < 0) {
936         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
937         ret = 0;
938     }
939     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
940     if (ioctl(sockfd, (int)SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
941         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
942         ret = 0;
943     }
944     if (m != 0) {
945         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
946         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
947         if (ioctl(sockfd, (int)SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
948             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
949             ret = 0;
950         }
951     }
952
953 /*  Reset if address --- This is stupid, but seems to be necessary...  */
954
955     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
956     if (ioctl(sockfd, (int)SIOCSIFADDR, (caddr_t) &ifr) < 0) {
957         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
958         ret = 0;
959     }
960
961     return ret;
962 }
963
964 /*
965  * cifaddr - Clear the interface IP addresses, and delete routes
966  * through the interface if possible.
967  */
968 int
969 cifaddr(u, o, h)
970     int u;
971     u_int32_t o, h;
972 {
973     struct ortentry rt;
974
975     SET_SA_FAMILY(rt.rt_dst, AF_INET);
976     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
977     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
978     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
979     rt.rt_flags = RTF_HOST;
980     if (ioctl(sockfd, (int)SIOCDELRT, (caddr_t) &rt) < 0) {
981         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
982         return 0;
983     }
984     return 1;
985 }
986
987 /*
988  * sifdefaultroute - assign a default route through the address given.
989  */
990 int
991 sifdefaultroute(u, g)
992     int u;
993     u_int32_t g;
994 {
995     struct ortentry rt;
996
997     SET_SA_FAMILY(rt.rt_dst, AF_INET);
998     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
999     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
1000     rt.rt_flags = RTF_GATEWAY;
1001     if (ioctl(sockfd, (int)SIOCADDRT, &rt) < 0) {
1002         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
1003         return 0;
1004     }
1005     return 1;
1006 }
1007
1008 /*
1009  * cifdefaultroute - delete a default route through the address given.
1010  */
1011 int
1012 cifdefaultroute(u, g)
1013     int u;
1014     u_int32_t g;
1015 {
1016     struct ortentry rt;
1017
1018     SET_SA_FAMILY(rt.rt_dst, AF_INET);
1019     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
1020     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
1021     rt.rt_flags = RTF_GATEWAY;
1022     if (ioctl(sockfd, (int)SIOCDELRT, &rt) < 0) {
1023         syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
1024         return 0;
1025     }
1026     return 1;
1027 }
1028
1029 /*
1030  * sifproxyarp - Make a proxy ARP entry for the peer.
1031  */
1032 int
1033 sifproxyarp(unit, hisaddr)
1034     int unit;
1035     u_int32_t hisaddr;
1036 {
1037     struct arpreq arpreq;
1038
1039     BZERO(&arpreq, sizeof(arpreq));
1040
1041     /*
1042      * Get the hardware address of an interface on the same subnet
1043      * as our local address.
1044      */
1045     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
1046         syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP");
1047         return 0;
1048     }
1049
1050     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1051     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1052     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1053     if (ioctl(sockfd, (int)SIOCSARP, (caddr_t)&arpreq) < 0) {
1054         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
1055         return 0;
1056     }
1057
1058     return 1;
1059 }
1060
1061 /*
1062  * cifproxyarp - Delete the proxy ARP entry for the peer.
1063  */
1064 int
1065 cifproxyarp(unit, hisaddr)
1066     int unit;
1067     u_int32_t hisaddr;
1068 {
1069     struct arpreq arpreq;
1070
1071     BZERO(&arpreq, sizeof(arpreq));
1072     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1073     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1074     if (ioctl(sockfd, (int)SIOCDARP, (caddr_t)&arpreq) < 0) {
1075         syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
1076         return 0;
1077     }
1078     return 1;
1079 }
1080
1081 /*
1082  * get_ether_addr - get the hardware address of an interface on the
1083  * the same subnet as ipaddr.
1084  */
1085 #define MAX_IFS         32
1086
1087 int s;
1088
1089 int
1090 get_ether_addr(ipaddr, hwaddr)
1091     u_int ipaddr;
1092     struct sockaddr *hwaddr;
1093 {
1094     struct ifreq *ifr, *ifend, *ifp;
1095     u_int ina, mask;
1096     struct sockaddr_dl *dla;
1097     struct ifreq ifreq;
1098     struct ifconf ifc;
1099     struct ifreq ifs[MAX_IFS];
1100     struct ifdevea ifdevreq;
1101
1102     ifc.ifc_len = sizeof(ifs);
1103     ifc.ifc_req = ifs;
1104     if (ioctl(sockfd, (int)SIOCGIFCONF, &ifc) < 0) {
1105         perror("ioctl(SIOCGIFCONF)");
1106         return 0;
1107     }
1108
1109     /*
1110      * Scan through looking for an interface with an Internet
1111      * address on the same subnet as `ipaddr'.
1112      */
1113     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1114     for (ifr = ifc.ifc_req; ifr < ifend; ) {
1115         if (ifr->ifr_addr.sa_family == AF_INET) {
1116             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1117             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1118             /*
1119              * Check that the interface is up, and not point-to-point
1120              * or loopback.
1121              */
1122             if (ioctl(sockfd, (int)SIOCGIFFLAGS, &ifreq) < 0)
1123                 continue;
1124             if ((ifreq.ifr_flags &
1125                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1126                  != (IFF_UP|IFF_BROADCAST))
1127                 continue;
1128             /*
1129              * Get its netmask and check that it's on the right subnet.
1130              */
1131             if (ioctl(sockfd, (int)SIOCGIFNETMASK, &ifreq) < 0)
1132                 continue;
1133             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1134             if ((ipaddr & mask) != (ina & mask))
1135                 continue;
1136
1137             break;
1138         }
1139         ifr++;
1140     }
1141
1142     if (ifr >= ifend)
1143         return 0;
1144     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1145
1146     strncpy(ifdevreq.ifr_name, ifr->ifr_name, sizeof(ifdevreq.ifr_name));
1147
1148     if (ioctl(sockfd, (int)SIOCRPHYSADDR, &ifdevreq) < 0) {
1149         perror("ioctl(SIOCRPHYSADDR)");
1150         return(0);
1151     }
1152
1153     hwaddr->sa_family = AF_UNSPEC;
1154     memcpy(hwaddr->sa_data, ifdevreq.current_pa, sizeof(ifdevreq.current_pa));
1155     return(1);
1156 }
1157
1158
1159 /*
1160  * Return user specified netmask, modified by any mask we might determine
1161  * for address `addr' (in network byte order).
1162  * Here we scan through the system's list of interfaces, looking for
1163  * any non-point-to-point interfaces which might appear to be on the same
1164  * network as `addr'.  If we find any, we OR in their netmask to the
1165  * user-specified netmask.
1166  */
1167 u_int32_t
1168 GetMask(addr)
1169     u_int32_t addr;
1170 {
1171     u_int32_t mask, nmask, ina;
1172     struct ifreq *ifr, *ifend, ifreq;
1173     struct ifconf ifc;
1174     struct ifreq ifs[MAX_IFS];
1175
1176     addr = ntohl(addr);
1177     if (IN_CLASSA(addr))        /* determine network mask for address class */
1178         nmask = IN_CLASSA_NET;
1179     else if (IN_CLASSB(addr))
1180         nmask = IN_CLASSB_NET;
1181     else
1182         nmask = IN_CLASSC_NET;
1183     /* class D nets are disallowed by bad_ip_adrs */
1184     mask = netmask | htonl(nmask);
1185
1186     /*
1187      * Scan through the system's network interfaces.
1188      */
1189     ifc.ifc_len = sizeof(ifs);
1190     ifc.ifc_req = ifs;
1191     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1192         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1193         return mask;
1194     }
1195     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1196     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1197         /*
1198          * Check the interface's internet address.
1199          */
1200         if (ifr->ifr_addr.sa_family != AF_INET)
1201             continue;
1202         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1203         if ((ntohl(ina) & nmask) != (addr & nmask))
1204             continue;
1205         /*
1206          * Check that the interface is up, and not point-to-point or loopback.
1207          */
1208         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1209         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1210             continue;
1211         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1212             != IFF_UP)
1213             continue;
1214         /*
1215          * Get its netmask and OR it into our mask.
1216          */
1217         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1218             continue;
1219         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1220     }
1221
1222     return mask;
1223 }
1224
1225
1226 #define WTMPFILE        "/usr/adm/wtmp"
1227 #include <sys/stat.h>
1228
1229 void
1230 logwtmp(line, name, host)
1231     char *line, *name, *host;
1232 {
1233     int fd;
1234     struct stat buf;
1235     struct utmp ut;
1236
1237     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1238         return;
1239     if (!fstat(fd, &buf)) {
1240         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1241         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1242         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1243         (void)time(&ut.ut_time);
1244         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1245             (void)ftruncate(fd, buf.st_size);
1246     }
1247     close(fd);
1248 }
1249
1250 /*
1251  * Code for locking/unlocking the serial device.
1252  * This code is derived from chat.c.
1253  */
1254
1255 #ifndef LOCK_DIR
1256 #  ifdef HDB
1257 #   define      PIDSTRING
1258 #   define      LOCK_PREFIX     "/usr/spool/locks/LCK.."
1259 #  else /* HDB */
1260 #   define      LOCK_PREFIX     "/usr/spool/uucp/LCK.."
1261 #  endif /* HDB */
1262 #endif /* LOCK_DIR */
1263
1264 static char *lock_file;
1265
1266 /*
1267  * lock - create a lock file for the named device
1268  */
1269 int
1270 lock(dev)
1271     char *dev;
1272 {
1273     char hdb_lock_buffer[12];
1274     int fd, pid, n;
1275     char *p;
1276
1277     if ((p = strrchr(dev, '/')) != NULL)
1278         dev = p + 1;
1279     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1280     if (lock_file == NULL)
1281         novm("lock file name");
1282     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1283
1284     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1285         if (errno == EEXIST
1286             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1287             /* Read the lock file to find out who has the device locked */
1288 #ifdef PIDSTRING
1289             n = read(fd, hdb_lock_buffer, 11);
1290             if (n > 0) {
1291                 hdb_lock_buffer[n] = 0;
1292                 pid = atoi(hdb_lock_buffer);
1293             }
1294 #else
1295             n = read(fd, &pid, sizeof(pid));
1296 #endif
1297             if (n <= 0) {
1298                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1299                 close(fd);
1300             } else {
1301                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1302                     /* pid no longer exists - remove the lock file */
1303                     if (unlink(lock_file) == 0) {
1304                         close(fd);
1305                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1306                                dev, pid);
1307                         continue;
1308                     } else
1309                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1310                                dev);
1311                 } else
1312                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1313                            dev, pid);
1314             }
1315             close(fd);
1316         } else
1317             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1318         free(lock_file);
1319         lock_file = NULL;
1320         return -1;
1321     }
1322
1323 # ifdef PIDSTRING
1324     sprintf(hdb_lock_buffer, "%10d\n", getpid());
1325     write(fd, hdb_lock_buffer, 11);
1326 # else
1327     pid = getpid();
1328     write(fd, &pid, sizeof pid);
1329 # endif
1330
1331     close(fd);
1332     return 0;
1333 }
1334
1335 /*
1336  * unlock - remove our lockfile
1337  */
1338 void
1339 unlock()
1340 {
1341     if (lock_file) {
1342         unlink(lock_file);
1343         free(lock_file);
1344         lock_file = NULL;
1345     }
1346 }
1347