old DLPI doesn't have dl_sap_length
[ppp.git] / pppd / sys-sunos4.c
1 /*
2  * System-dependent procedures for pppd under SunOS 4.
3  *
4  * Copyright (c) 1994 The Australian National University.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.  This software is provided without any
10  * warranty, express or implied. The Australian National University
11  * makes no representations about the suitability of this software for
12  * any purpose.
13  *
14  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
18  * OF SUCH DAMAGE.
19  *
20  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
25  * OR MODIFICATIONS.
26  */
27
28 #ifndef lint
29 static char rcsid[] = "$Id: sys-sunos4.c,v 1.1 1995/10/27 03:54:02 paulus Exp $";
30 #endif
31
32 #include <stdio.h>
33 #include <stddef.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <termios.h>
41 #include <signal.h>
42 #include <malloc.h>
43 #include <utmp.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/stream.h>
49 #include <sys/stropts.h>
50 #include <sys/syslog.h>
51 #include <sys/stat.h>
52 #include <sys/time.h>
53 #include <sys/poll.h>
54 #include <net/if.h>
55 #include <net/if_arp.h>
56 #include <net/nit_if.h>
57 #include <net/route.h>
58 #include <net/ppp_defs.h>
59 #include <net/pppio.h>
60 #include <netinet/in.h>
61
62 #include "pppd.h"
63
64 static int      pppfd;
65 static int      fdmuxid = -1;
66 static int      iffd;
67 static int      sockfd;
68
69 static int      restore_term;
70 static struct termios inittermios;
71 static struct winsize wsinfo;   /* Initial window size info */
72 static pid_t    parent_pid;     /* PID of our parent */
73
74 static int      link_mtu, link_mru;
75
76 #define NMODULES        32
77 static int      tty_nmodules;
78 static char     tty_modules[NMODULES][FMNAMESZ+1];
79
80 static int      if_is_up;       /* Interface has been marked up */
81 static u_int32_t default_route_gateway; /* Gateway for default route added */
82 static u_int32_t proxy_arp_addr;        /* Addr for proxy arp entry added */
83
84 /* Prototypes for procedures local to this file. */
85 static int translate_speed __P((int));
86 static int baud_rate_of __P((int));
87 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
88 static int strioctl __P((int, int, void *, int, int));
89
90
91 /*
92  * sys_init - System-dependent initialization.
93  */
94 void
95 sys_init()
96 {
97     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
98     setlogmask(LOG_UPTO(LOG_INFO));
99     if (debug)
100         setlogmask(LOG_UPTO(LOG_DEBUG));
101
102     /* Get an internet socket for doing socket ioctl's on. */
103     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
104         syslog(LOG_ERR, "Couldn't create IP socket: %m");
105         die(1);
106     }
107
108     /*
109      * We may want to send a SIGHUP to the session leader associated
110      * with our controlling terminal later.  Because SunOS doesn't
111      * have getsid(), we make do with sending the signal to our
112      * parent process.
113      */
114     parent_pid = getppid();
115 }
116
117 /*
118  * sys_cleanup - restore any system state we modified before exiting:
119  * mark the interface down, delete default route and/or proxy arp entry.
120  * This should call die() because it's called from die().
121  */
122 void
123 sys_cleanup()
124 {
125     struct ifreq ifr;
126
127     if (if_is_up)
128         sifdown(0);
129     if (default_route_gateway)
130         cifdefaultroute(0, default_route_gateway);
131     if (proxy_arp_addr)
132         cifproxyarp(0, proxy_arp_addr);
133 }
134
135 /*
136  * daemon - Detach us from controlling terminal session.
137  */
138 int
139 daemon(nochdir, noclose)
140     int nochdir, noclose;
141 {
142     int pid;
143
144     if ((pid = fork()) < 0)
145         return -1;
146     if (pid != 0)
147         exit(0);                /* parent dies */
148     setsid();
149     if (!nochdir)
150         chdir("/");
151     if (!noclose) {
152         fclose(stdin);          /* don't need stdin, stdout, stderr */
153         fclose(stdout);
154         fclose(stderr);
155     }
156     return 0;
157 }
158
159 /*
160  * note_debug_level - note a change in the debug level.
161  */
162 void
163 note_debug_level()
164 {
165     if (debug) {
166         syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
167         setlogmask(LOG_UPTO(LOG_DEBUG));
168     } else {
169         setlogmask(LOG_UPTO(LOG_WARNING));
170     }
171 }
172
173 /*
174  * ppp_available - check whether the system has any ppp interfaces
175  */
176 int
177 ppp_available()
178 {
179     struct stat buf;
180
181     return stat("/dev/ppp", &buf) >= 0;
182 }
183
184 /*
185  * establish_ppp - Turn the serial port into a ppp interface.
186  */
187 void
188 establish_ppp()
189 {
190     int i, x;
191     struct ifreq ifr;
192
193     pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
194     if (pppfd < 0) {
195         syslog(LOG_ERR, "Can't open /dev/ppp: %m");
196         die(1);
197     }
198     if (kdebugflag) {
199         x = PPPDBG_LOG + PPPDBG_DRIVER;
200         strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
201     }
202
203     /* Assign a new PPA and get its unit number. */
204     if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) {
205         syslog(LOG_ERR, "Can't create new PPP interface: %m");
206         die(1);
207     }
208
209     /*
210      * Open the ppp device again and push the if_ppp module on it.
211      */
212     iffd = open("/dev/ppp", O_RDWR, 0);
213     if (iffd < 0) {
214         syslog(LOG_ERR, "Can't open /dev/ppp (2): %m");
215         die(1);
216     }
217     if (kdebugflag) {
218         x = PPPDBG_LOG + PPPDBG_DRIVER;
219         strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
220     }
221     if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0) {
222         syslog(LOG_ERR, "Couldn't attach ppp interface to device: %m");
223         die(1);
224     }
225     if (ioctl(iffd, I_PUSH, "if_ppp") < 0) {
226         syslog(LOG_ERR, "Can't push ppp interface module: %m");
227         die(1);
228     }
229     if (kdebugflag) {
230         x = PPPDBG_LOG + PPPDBG_IF;
231         strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
232     }
233     if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0) {
234         syslog(LOG_ERR, "Couldn't create ppp interface unit: %m");
235         die(1);
236     }
237     x = PPP_IP;
238     if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0) {
239         syslog(LOG_ERR, "Couldn't bind ppp interface to IP SAP: %m");
240         die(1);
241     }
242
243     /* Pop any existing modules off the tty stream. */
244     for (i = 0;; ++i)
245         if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
246             || ioctl(fd, I_POP, 0) < 0)
247             break;
248     tty_nmodules = i;
249
250     /* Push the async hdlc module and the compressor module. */
251     if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) {
252         syslog(LOG_ERR, "Couldn't push PPP Async HDLC module: %m");
253         die(1);
254     }
255     if (ioctl(fd, I_PUSH, "ppp_comp") < 0) {
256         syslog(LOG_ERR, "Couldn't push PPP compression module: %m");
257 /*      die(1); */
258     }
259
260     /* Link the serial port under the PPP multiplexor. */
261     if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) {
262         syslog(LOG_ERR, "Can't link tty to PPP mux: %m");
263         die(1);
264     }
265
266     do {
267         char buf[PPP_MRU];
268
269         i = read(fd, buf, PPP_MRU);
270         syslog(LOG_DEBUG, "read %d bytes from fd", i);
271     } while (i > 0);
272 }
273
274 /*
275  * disestablish_ppp - Restore the serial port to normal operation.
276  * This shouldn't call die() because it's called from die().
277  */
278 void
279 disestablish_ppp()
280 {
281     int i;
282
283     if (fdmuxid >= 0) {
284         if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
285             if (!hungup)
286                 syslog(LOG_ERR, "Can't unlink tty from PPP mux: %m");
287         }
288         fdmuxid = -1;
289
290         if (!hungup) {
291             while (ioctl(fd, I_POP, 0) >= 0)
292                 ;
293             for (i = tty_nmodules - 1; i >= 0; --i)
294                 if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
295                     syslog(LOG_ERR, "Couldn't restore tty module %s: %m",
296                            tty_modules[i]);
297         }
298         if (hungup && default_device && parent_pid > 0) {
299             /*
300              * If we have received a hangup, we need to send a SIGHUP
301              * to the terminal's controlling process.  The reason is
302              * that the original stream head for the terminal hasn't
303              * seen the M_HANGUP message (it went up through the ppp
304              * driver to the stream head for our fd to /dev/ppp).
305              * Actually we send the signal to the process that invoked
306              * pppd, since SunOS doesn't have getsid().
307              */
308             kill(parent_pid, SIGHUP);
309         }
310     }
311 }
312
313 /*
314  * List of valid speeds.
315  */
316 struct speed {
317     int speed_int, speed_val;
318 } speeds[] = {
319 #ifdef B50
320     { 50, B50 },
321 #endif
322 #ifdef B75
323     { 75, B75 },
324 #endif
325 #ifdef B110
326     { 110, B110 },
327 #endif
328 #ifdef B134
329     { 134, B134 },
330 #endif
331 #ifdef B150
332     { 150, B150 },
333 #endif
334 #ifdef B200
335     { 200, B200 },
336 #endif
337 #ifdef B300
338     { 300, B300 },
339 #endif
340 #ifdef B600
341     { 600, B600 },
342 #endif
343 #ifdef B1200
344     { 1200, B1200 },
345 #endif
346 #ifdef B1800
347     { 1800, B1800 },
348 #endif
349 #ifdef B2000
350     { 2000, B2000 },
351 #endif
352 #ifdef B2400
353     { 2400, B2400 },
354 #endif
355 #ifdef B3600
356     { 3600, B3600 },
357 #endif
358 #ifdef B4800
359     { 4800, B4800 },
360 #endif
361 #ifdef B7200
362     { 7200, B7200 },
363 #endif
364 #ifdef B9600
365     { 9600, B9600 },
366 #endif
367 #ifdef B19200
368     { 19200, B19200 },
369 #endif
370 #ifdef B38400
371     { 38400, B38400 },
372 #endif
373 #ifdef EXTA
374     { 19200, EXTA },
375 #endif
376 #ifdef EXTB
377     { 38400, EXTB },
378 #endif
379 #ifdef B57600
380     { 57600, B57600 },
381 #endif
382 #ifdef B115200
383     { 115200, B115200 },
384 #endif
385     { 0, 0 }
386 };
387
388 /*
389  * Translate from bits/second to a speed_t.
390  */
391 static int
392 translate_speed(bps)
393     int bps;
394 {
395     struct speed *speedp;
396
397     if (bps == 0)
398         return 0;
399     for (speedp = speeds; speedp->speed_int; speedp++)
400         if (bps == speedp->speed_int)
401             return speedp->speed_val;
402     syslog(LOG_WARNING, "speed %d not supported", bps);
403     return 0;
404 }
405
406 /*
407  * Translate from a speed_t to bits/second.
408  */
409 static int
410 baud_rate_of(speed)
411     int speed;
412 {
413     struct speed *speedp;
414
415     if (speed == 0)
416         return 0;
417     for (speedp = speeds; speedp->speed_int; speedp++)
418         if (speed == speedp->speed_val)
419             return speedp->speed_int;
420     return 0;
421 }
422
423 /*
424  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
425  * at the requested speed, etc.  If `local' is true, set CLOCAL
426  * regardless of whether the modem option was specified.
427  */
428 void
429 set_up_tty(fd, local)
430     int fd, local;
431 {
432     int speed;
433     struct termios tios;
434
435     if (tcgetattr(fd, &tios) < 0) {
436         syslog(LOG_ERR, "tcgetattr: %m");
437         die(1);
438     }
439
440     if (!restore_term) {
441         inittermios = tios;
442         ioctl(fd, TIOCGWINSZ, &wsinfo);
443     }
444
445     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
446     if (crtscts > 0)
447         tios.c_cflag |= CRTSCTS;
448     else if (crtscts < 0)
449         tios.c_cflag &= ~CRTSCTS;
450
451     tios.c_cflag |= CS8 | CREAD | HUPCL;
452     if (local || !modem)
453         tios.c_cflag |= CLOCAL;
454     tios.c_iflag = IGNBRK | IGNPAR;
455     tios.c_oflag = 0;
456     tios.c_lflag = 0;
457     tios.c_cc[VMIN] = 1;
458     tios.c_cc[VTIME] = 0;
459
460     if (crtscts == -2) {
461         tios.c_iflag |= IXON | IXOFF;
462         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
463         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
464     }
465
466     speed = translate_speed(inspeed);
467     if (speed) {
468         cfsetospeed(&tios, speed);
469         cfsetispeed(&tios, speed);
470     } else {
471         speed = cfgetospeed(&tios);
472         /*
473          * We can't proceed if the serial port speed is 0,
474          * since that implies that the serial port is disabled.
475          */
476         if (speed == B0) {
477             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
478                    devnam);
479             die(1);
480         }
481     }
482
483     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
484         syslog(LOG_ERR, "tcsetattr: %m");
485         die(1);
486     }
487
488     baud_rate = inspeed = baud_rate_of(speed);
489     restore_term = 1;
490 }
491
492 /*
493  * restore_tty - restore the terminal to the saved settings.
494  */
495 void
496 restore_tty()
497 {
498     if (restore_term) {
499         if (!default_device) {
500             /*
501              * Turn off echoing, because otherwise we can get into
502              * a loop with the tty and the modem echoing to each other.
503              * We presume we are the sole user of this tty device, so
504              * when we close it, it will revert to its defaults anyway.
505              */
506             inittermios.c_lflag &= ~(ECHO | ECHONL);
507         }
508         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
509             if (!hungup && errno != ENXIO)
510                 syslog(LOG_WARNING, "tcsetattr: %m");
511         ioctl(fd, TIOCSWINSZ, &wsinfo);
512         restore_term = 0;
513     }
514 }
515
516 /*
517  * setdtr - control the DTR line on the serial port.
518  * This is called from die(), so it shouldn't call die().
519  */
520 void
521 setdtr(fd, on)
522 int fd, on;
523 {
524     int modembits = TIOCM_DTR;
525
526     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
527 }
528
529 /*
530  * output - Output PPP packet.
531  */
532 void
533 output(unit, p, len)
534     int unit;
535     u_char *p;
536     int len;
537 {
538     struct strbuf data;
539     int retries;
540     struct pollfd pfd;
541
542     if (debug)
543         log_packet(p, len, "sent ");
544
545     data.len = len;
546     data.buf = (caddr_t) p;
547     while (putmsg(pppfd, NULL, &data, 0) < 0) {
548         if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
549             if (errno != ENXIO)
550                 syslog(LOG_ERR, "Couldn't send packet: %m");
551             break;
552         }
553         pfd.fd = fd;
554         pfd.events = POLLOUT;
555         poll(&pfd, 1, 250);     /* wait for up to 0.25 seconds */
556     }
557 }
558
559 /*
560  * wait_input - wait until there is data available on fd,
561  * for the length of time specified by *timo (indefinite
562  * if timo is NULL).
563  */
564 void
565 wait_input(timo)
566     struct timeval *timo;
567 {
568     int t;
569     struct pollfd pfd;
570
571     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
572     pfd.fd = pppfd;
573     pfd.events = POLLIN | POLLPRI | POLLHUP;
574     if (poll(&pfd, 1, t) < 0 && errno != EINTR) {
575         syslog(LOG_ERR, "poll: %m");
576         die(1);
577     }
578 }
579
580 /*
581  * read_packet - get a PPP packet from the serial device.
582  */
583 int
584 read_packet(buf)
585     u_char *buf;
586 {
587     struct strbuf ctrl, data;
588     int flags, len;
589     unsigned char ctrlbuf[64];
590
591     for (;;) {
592         data.maxlen = PPP_MRU + PPP_HDRLEN;
593         data.buf = (caddr_t) buf;
594         ctrl.maxlen = sizeof(ctrlbuf);
595         ctrl.buf = (caddr_t) ctrlbuf;
596         flags = 0;
597         len = getmsg(pppfd, &ctrl, &data, &flags);
598         if (len < 0) {
599             if (errno = EAGAIN || errno == EINTR)
600                 return -1;
601             syslog(LOG_ERR, "Error reading packet: %m");
602             die(1);
603         }
604
605         if (ctrl.len <= 0)
606             return data.len;
607
608         /*
609          * Got a M_PROTO or M_PCPROTO message.  Huh?
610          */
611         if (debug)
612             syslog(LOG_DEBUG, "got ctrl msg len=%d", ctrl.len);
613
614     }
615 }
616
617 /*
618  * ppp_send_config - configure the transmit characteristics of
619  * the ppp interface.
620  */
621 void
622 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
623     int unit, mtu;
624     u_int32_t asyncmap;
625     int pcomp, accomp;
626 {
627     int cf[2];
628
629     link_mtu = mtu;
630     if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
631         if (hungup && errno == ENXIO)
632             return;
633         syslog(LOG_ERR, "Couldn't set MTU: %m");
634     }
635     if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
636         syslog(LOG_ERR, "Couldn't set transmit ACCM: %m");
637     }
638     cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
639     cf[1] = COMP_PROT | COMP_AC;
640     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
641         syslog(LOG_ERR, "Couldn't set prot/AC compression: %m");
642     }
643 }
644
645 /*
646  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
647  */
648 void
649 ppp_set_xaccm(unit, accm)
650     int unit;
651     ext_accm accm;
652 {
653     if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
654         if (!hungup || errno != ENXIO)
655             syslog(LOG_WARNING, "Couldn't set extended ACCM: %m");
656     }
657 }
658
659 /*
660  * ppp_recv_config - configure the receive-side characteristics of
661  * the ppp interface.
662  */
663 void
664 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
665     int unit, mru;
666     u_int32_t asyncmap;
667     int pcomp, accomp;
668 {
669     int cf[2];
670
671     link_mru = mru;
672     if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
673         if (hungup && errno == ENXIO)
674             return;
675         syslog(LOG_ERR, "Couldn't set MRU: %m");
676     }
677     if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
678         syslog(LOG_ERR, "Couldn't set receive ACCM: %m");
679     }
680     cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
681     cf[1] = DECOMP_PROT | DECOMP_AC;
682     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
683         syslog(LOG_ERR, "Couldn't set prot/AC decompression: %m");
684     }
685 }
686
687 /*
688  * ccp_test - ask kernel whether a given compression method
689  * is acceptable for use.
690  */
691 int
692 ccp_test(unit, opt_ptr, opt_len, for_transmit)
693     int unit, opt_len, for_transmit;
694     u_char *opt_ptr;
695 {
696     if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
697                  opt_ptr, opt_len, 0) >= 0)
698         return 1;
699     return (errno == ENOSR)? 0: -1;
700 }
701
702 /*
703  * ccp_flags_set - inform kernel about the current state of CCP.
704  */
705 void
706 ccp_flags_set(unit, isopen, isup)
707     int unit, isopen, isup;
708 {
709     int cf[2];
710
711     cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
712     cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
713     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
714         if (!hungup || errno != ENXIO)
715             syslog(LOG_ERR, "Couldn't set kernel CCP state: %m");
716     }
717 }
718
719 /*
720  * ccp_fatal_error - returns 1 if decompression was disabled as a
721  * result of an error detected after decompression of a packet,
722  * 0 otherwise.  This is necessary because of patent nonsense.
723  */
724 int
725 ccp_fatal_error(unit)
726     int unit;
727 {
728     int cf[2];
729
730     cf[0] = cf[1] = 0;
731     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
732         if (errno != ENXIO && errno != EINVAL)
733             syslog(LOG_ERR, "Couldn't get compression flags: %m");
734         return 0;
735     }
736     return cf[0] & CCP_FATALERROR;
737 }
738
739 /*
740  * sifvjcomp - config tcp header compression
741  */
742 int
743 sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
744     int u, vjcomp, xcidcomp, xmaxcid;
745 {
746     int cf[2];
747     char maxcid[2];
748
749     if (vjcomp) {
750         maxcid[0] = xcidcomp;
751         maxcid[1] = 15;         /* XXX should be rmaxcid */
752         if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
753             syslog(LOG_ERR, "Couldn't initialize VJ compression: %m");
754         }
755     }
756
757     cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0)  /* XXX this is wrong */
758         + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
759     cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
760     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
761         if (vjcomp)
762             syslog(LOG_ERR, "Couldn't enable VJ compression: %m");
763     }
764
765     return 1;
766 }
767
768 /*
769  * sifup - Config the interface up and enable IP packets to pass.
770  */
771 int
772 sifup(u)
773     int u;
774 {
775     struct ifreq ifr;
776
777     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
778     if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
779         syslog(LOG_ERR, "Couldn't mark interface up (get): %m");
780         return 0;
781     }
782     ifr.ifr_flags |= IFF_UP;
783     if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
784         syslog(LOG_ERR, "Couldn't mark interface up (set): %m");
785         return 0;
786     }
787     if_is_up = 1;
788     return 1;
789 }
790
791 /*
792  * sifdown - Config the interface down and disable IP.
793  */
794 int
795 sifdown(u)
796     int u;
797 {
798     struct ifreq ifr;
799
800     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
801     if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
802         syslog(LOG_ERR, "Couldn't mark interface down (get): %m");
803         return 0;
804     }
805     if ((ifr.ifr_flags & IFF_UP) != 0) {
806         ifr.ifr_flags &= ~IFF_UP;
807         if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
808             syslog(LOG_ERR, "Couldn't mark interface down (set): %m");
809             return 0;
810         }
811     }
812     if_is_up = 0;
813     return 1;
814 }
815
816 #define INET_ADDR(x)    (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
817
818 /*
819  * sifaddr - Config the interface IP addresses and netmask.
820  */
821 int
822 sifaddr(u, o, h, m)
823     int u;
824     u_int32_t o, h, m;
825 {
826     struct ifreq ifr;
827
828     memset(&ifr, 0, sizeof(ifr));
829     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
830     ifr.ifr_addr.sa_family = AF_INET;
831     INET_ADDR(ifr.ifr_addr) = o;
832     if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
833         syslog(LOG_ERR, "Couldn't set local IP address: %m");
834     }
835     ifr.ifr_dstaddr.sa_family = AF_INET;
836     INET_ADDR(ifr.ifr_dstaddr) = h;
837     if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
838         syslog(LOG_ERR, "Couldn't set remote IP address: %m");
839     }
840     ifr.ifr_addr.sa_family = AF_INET;
841     INET_ADDR(ifr.ifr_addr) = m;
842     if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
843         syslog(LOG_ERR, "Couldn't set IP netmask: %m");
844     }
845     ifr.ifr_metric = link_mtu;
846     if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
847         syslog(LOG_ERR, "Couldn't set IP MTU: %m");
848     }
849
850     return 1;
851 }
852
853 /*
854  * cifaddr - Clear the interface IP addresses, and delete routes
855  * through the interface if possible.
856  */
857 int
858 cifaddr(u, o, h)
859     int u;
860     u_int32_t o, h;
861 {
862     struct rtentry rt;
863
864     rt.rt_dst.sa_family = AF_INET;
865     INET_ADDR(rt.rt_dst) = h;
866     rt.rt_gateway.sa_family = AF_INET;
867     INET_ADDR(rt.rt_gateway) = o;
868     rt.rt_flags = RTF_HOST;
869     ioctl(sockfd, SIOCDELRT, &rt);
870     return 1;
871 }
872
873 /*
874  * sifdefaultroute - assign a default route through the address given.
875  */
876 int
877 sifdefaultroute(u, g)
878     int u;
879     u_int32_t g;
880 {
881     struct rtentry rt;
882
883     rt.rt_dst.sa_family = AF_INET;
884     INET_ADDR(rt.rt_dst) = 0;
885     rt.rt_gateway.sa_family = AF_INET;
886     INET_ADDR(rt.rt_gateway) = g;
887     rt.rt_flags = RTF_GATEWAY;
888
889     if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
890         syslog(LOG_ERR, "Can't add default route: %m");
891         return 0;
892     }
893
894     default_route_gateway = g;
895     return 1;
896 }
897
898 /*
899  * cifdefaultroute - delete a default route through the address given.
900  */
901 int
902 cifdefaultroute(u, g)
903     int u;
904     u_int32_t g;
905 {
906     struct rtentry rt;
907
908     rt.rt_dst.sa_family = AF_INET;
909     INET_ADDR(rt.rt_dst) = 0;
910     rt.rt_gateway.sa_family = AF_INET;
911     INET_ADDR(rt.rt_gateway) = g;
912     rt.rt_flags = RTF_GATEWAY;
913
914     if (ioctl(sockfd, SIOCDELRT, &rt) < 0) {
915         syslog(LOG_ERR, "Can't delete default route: %m");
916         return 0;
917     }
918
919     default_route_gateway = 0;
920     return 1;
921 }
922
923 /*
924  * sifproxyarp - Make a proxy ARP entry for the peer.
925  */
926 int
927 sifproxyarp(unit, hisaddr)
928     int unit;
929     u_int32_t hisaddr;
930 {
931     struct arpreq arpreq;
932
933     bzero(&arpreq, sizeof(arpreq));
934     if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
935         return 0;
936
937     arpreq.arp_pa.sa_family = AF_INET;
938     INET_ADDR(arpreq.arp_pa) = hisaddr;
939     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
940     if (ioctl(sockfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
941         syslog(LOG_ERR, "Couldn't set proxy ARP entry: %m");
942         return 0;
943     }
944
945     proxy_arp_addr = hisaddr;
946     return 1;
947 }
948
949 /*
950  * cifproxyarp - Delete the proxy ARP entry for the peer.
951  */
952 int
953 cifproxyarp(unit, hisaddr)
954     int unit;
955     u_int32_t hisaddr;
956 {
957     struct arpreq arpreq;
958
959     bzero(&arpreq, sizeof(arpreq));
960     arpreq.arp_pa.sa_family = AF_INET;
961     INET_ADDR(arpreq.arp_pa) = hisaddr;
962     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
963         syslog(LOG_ERR, "Couldn't delete proxy ARP entry: %m");
964         return 0;
965     }
966
967     proxy_arp_addr = 0;
968     return 1;
969 }
970
971 /*
972  * get_ether_addr - get the hardware address of an interface on the
973  * the same subnet as ipaddr.
974  */
975 #define MAX_IFS         32
976
977 static int
978 get_ether_addr(ipaddr, hwaddr)
979     u_int32_t ipaddr;
980     struct sockaddr *hwaddr;
981 {
982     struct ifreq *ifr, *ifend;
983     u_int32_t ina, mask;
984     struct ifreq ifreq;
985     struct ifconf ifc;
986     struct ifreq ifs[MAX_IFS];
987     int nit_fd;
988
989     ifc.ifc_len = sizeof(ifs);
990     ifc.ifc_req = ifs;
991     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
992         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
993         return 0;
994     }
995
996     /*
997      * Scan through looking for an interface with an Internet
998      * address on the same subnet as `ipaddr'.
999      */
1000     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1001     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1002             ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
1003         if (ifr->ifr_addr.sa_family == AF_INET) {
1004
1005             /*
1006              * Check that the interface is up, and not point-to-point
1007              * or loopback.
1008              */
1009             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1010             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1011                 continue;
1012             if ((ifreq.ifr_flags &
1013                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1014                  != (IFF_UP|IFF_BROADCAST))
1015                 continue;
1016
1017             /*
1018              * Get its netmask and check that it's on the right subnet.
1019              */
1020             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1021                 continue;
1022             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1023             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1024             if ((ipaddr & mask) != (ina & mask))
1025                 continue;
1026
1027             break;
1028         }
1029     }
1030
1031     if (ifr >= ifend)
1032         return 0;
1033     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1034
1035     /*
1036      * Grab the physical address for this interface.
1037      */
1038     if ((nit_fd = open("/dev/nit", O_RDONLY)) < 0) {
1039         syslog(LOG_ERR, "Couldn't open /dev/nit: %m");
1040         return 0;
1041     }
1042     strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1043     if (ioctl(nit_fd, NIOCBIND, &ifreq) < 0
1044         || ioctl(nit_fd, SIOCGIFADDR, &ifreq) < 0) {
1045         syslog(LOG_ERR, "Couldn't get hardware address for %s: %m",
1046                ifreq.ifr_name);
1047         close(nit_fd);
1048         return 0;
1049     }
1050
1051     hwaddr->sa_family = AF_UNSPEC;
1052     memcpy(hwaddr->sa_data, ifreq.ifr_addr.sa_data, 6);
1053     close(nit_fd);
1054     return 1;
1055 }
1056
1057 #define WTMPFILE        "/usr/adm/wtmp"
1058
1059 int
1060 logwtmp(line, name, host)
1061     char *line, *name, *host;
1062 {
1063     int fd;
1064     struct stat buf;
1065     struct utmp ut;
1066
1067     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
1068         return;
1069     if (!fstat(fd, &buf)) {
1070         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1071         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1072         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1073         (void)time(&ut.ut_time);
1074         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
1075             (void)ftruncate(fd, buf.st_size);
1076     }
1077     close(fd);
1078 }
1079
1080 /*
1081  * Return user specified netmask, modified by any mask we might determine
1082  * for address `addr' (in network byte order).
1083  * Here we scan through the system's list of interfaces, looking for
1084  * any non-point-to-point interfaces which might appear to be on the same
1085  * network as `addr'.  If we find any, we OR in their netmask to the
1086  * user-specified netmask.
1087  */
1088 u_int32_t
1089 GetMask(addr)
1090     u_int32_t addr;
1091 {
1092     u_int32_t mask, nmask, ina;
1093     struct ifreq *ifr, *ifend, ifreq;
1094     struct ifconf ifc;
1095
1096     addr = ntohl(addr);
1097     if (IN_CLASSA(addr))        /* determine network mask for address class */
1098         nmask = IN_CLASSA_NET;
1099     else if (IN_CLASSB(addr))
1100         nmask = IN_CLASSB_NET;
1101     else
1102         nmask = IN_CLASSC_NET;
1103     /* class D nets are disallowed by bad_ip_adrs */
1104     mask = netmask | htonl(nmask);
1105
1106     /*
1107      * Scan through the system's network interfaces.
1108      */
1109     ifc.ifc_len = MAX_IFS * sizeof(struct ifreq);
1110     ifc.ifc_req = alloca(ifc.ifc_len);
1111     if (ifc.ifc_req == 0)
1112         return mask;
1113     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1114         syslog(LOG_WARNING, "Couldn't get system interface list: %m");
1115         return mask;
1116     }
1117     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1118     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1119         /*
1120          * Check the interface's internet address.
1121          */
1122         if (ifr->ifr_addr.sa_family != AF_INET)
1123             continue;
1124         ina = INET_ADDR(ifr->ifr_addr);
1125         if ((ntohl(ina) & nmask) != (addr & nmask))
1126             continue;
1127         /*
1128          * Check that the interface is up, and not point-to-point or loopback.
1129          */
1130         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1131         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1132             continue;
1133         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1134             != IFF_UP)
1135             continue;
1136         /*
1137          * Get its netmask and OR it into our mask.
1138          */
1139         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1140             continue;
1141         mask |= INET_ADDR(ifreq.ifr_addr);
1142     }
1143
1144     return mask;
1145 }
1146
1147 static int
1148 strioctl(fd, cmd, ptr, ilen, olen)
1149     int fd, cmd, ilen, olen;
1150     void *ptr;
1151 {
1152     struct strioctl str;
1153
1154     str.ic_cmd = cmd;
1155     str.ic_timout = 0;
1156     str.ic_len = ilen;
1157     str.ic_dp = ptr;
1158     if (ioctl(fd, I_STR, &str) == -1)
1159         return -1;
1160     if (str.ic_len != olen)
1161         syslog(LOG_DEBUG, "strioctl: expected %d bytes, got %d for cmd %x\n",
1162                olen, str.ic_len, cmd);
1163     return 0;
1164 }
1165
1166 /*
1167  * Code for locking/unlocking the serial device.
1168  * This code is derived from chat.c.
1169  */
1170
1171 #if !defined(HDB) && !defined(SUNOS3)
1172 #define HDB     1               /* ascii lock files are the default */
1173 #endif
1174
1175 #ifndef LOCK_DIR
1176 # if HDB
1177 #  define       PIDSTRING
1178 #  define       LOCK_PREFIX     "/usr/spool/locks/LCK.."
1179 # else /* HDB */
1180 #  define       LOCK_PREFIX     "/usr/spool/uucp/LCK.."
1181 # endif /* HDB */
1182 #endif /* LOCK_DIR */
1183
1184 static char *lock_file;         /* name of lock file created */
1185
1186 /*
1187  * lock - create a lock file for the named device.
1188  */
1189 int
1190 lock(dev)
1191     char *dev;
1192 {
1193     char hdb_lock_buffer[12];
1194     int fd, pid, n;
1195     char *p;
1196
1197     if ((p = strrchr(dev, '/')) != NULL)
1198         dev = p + 1;
1199     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1200     if (lock_file == NULL)
1201         novm("lock file name");
1202     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1203
1204     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1205         if (errno == EEXIST
1206             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1207             /* Read the lock file to find out who has the device locked */
1208 #ifdef PIDSTRING
1209             n = read(fd, hdb_lock_buffer, 11);
1210             if (n > 0) {
1211                 hdb_lock_buffer[n] = 0;
1212                 pid = atoi(hdb_lock_buffer);
1213             }
1214 #else
1215             n = read(fd, &pid, sizeof(pid));
1216 #endif
1217             if (n <= 0) {
1218                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1219                 close(fd);
1220             } else {
1221                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1222                     /* pid no longer exists - remove the lock file */
1223                     if (unlink(lock_file) == 0) {
1224                         close(fd);
1225                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1226                                dev, pid);
1227                         continue;
1228                     } else
1229                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1230                                dev);
1231                 } else
1232                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1233                            dev, pid);
1234             }
1235             close(fd);
1236         } else
1237             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1238         free(lock_file);
1239         lock_file = NULL;
1240         return -1;
1241     }
1242
1243 #ifdef PIDSTRING
1244     sprintf(hdb_lock_buffer, "%10d\n", getpid());
1245     write(fd, hdb_lock_buffer, 11);
1246 #else
1247     pid = getpid();
1248     write(fd, &pid, sizeof pid);
1249 #endif
1250
1251     close(fd);
1252     return 0;
1253 }
1254
1255 /*
1256  * unlock - remove our lockfile
1257  */
1258 void
1259 unlock()
1260 {
1261     if (lock_file) {
1262         unlink(lock_file);
1263         free(lock_file);
1264         lock_file = NULL;
1265     }
1266 }
1267
1268 /*
1269  * SunOS doesn't have strtoul :-(
1270  */
1271 unsigned long
1272 strtoul(str, ptr, base)
1273     char *str, **ptr;
1274     int base;
1275 {
1276     return (unsigned long) strtol(str, ptr, base);
1277 }