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