]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-svr4.c
add packet filtering support; set netmask before interface addr
[ppp.git] / pppd / sys-svr4.c
1 /*
2  * System-dependent procedures for pppd under Solaris 2.
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-svr4.c,v 1.10 1996/04/04 04:07:30 paulus Exp $";
30 #endif
31
32 #include <limits.h>
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <alloca.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <termios.h>
42 #ifndef CRTSCTS
43 #include <sys/termiox.h>
44 #endif
45 #include <signal.h>
46 #include <utmpx.h>
47 #include <sys/types.h>
48 #include <sys/ioccom.h>
49 #include <sys/stream.h>
50 #include <sys/stropts.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/syslog.h>
54 #include <sys/sysmacros.h>
55 #include <sys/systeminfo.h>
56 #include <sys/dlpi.h>
57 #include <sys/stat.h>
58 #include <sys/mkdev.h>
59 #include <net/if.h>
60 #include <net/if_arp.h>
61 #include <net/route.h>
62 #include <net/ppp_defs.h>
63 #include <net/pppio.h>
64 #include <netinet/in.h>
65
66 #include "pppd.h"
67
68 static int      pppfd;
69 static int      fdmuxid = -1;
70 static int      ipfd;
71 static int      ipmuxid = -1;
72
73 static int      restore_term;
74 static struct termios inittermios;
75 #ifndef CRTSCTS
76 static struct termiox inittermiox;
77 #endif
78 static struct winsize wsinfo;   /* Initial window size info */
79 static pid_t    tty_sid;        /* original session ID for terminal */
80
81 extern u_char   inpacket_buf[]; /* borrowed from main.c */
82
83 static int      link_mtu, link_mru;
84
85 #define NMODULES        32
86 static int      tty_nmodules;
87 static char     tty_modules[NMODULES][FMNAMESZ+1];
88
89 static int      if_is_up;       /* Interface has been marked up */
90 static u_int32_t default_route_gateway; /* Gateway for default route added */
91 static u_int32_t proxy_arp_addr;        /* Addr for proxy arp entry added */
92
93 /* Prototypes for procedures local to this file. */
94 static int translate_speed __P((int));
95 static int baud_rate_of __P((int));
96 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
97 static int get_hw_addr __P((char *, struct sockaddr *));
98 static int dlpi_attach __P((int, int));
99 static int dlpi_info_req __P((int));
100 static int dlpi_get_reply __P((int, union DL_primitives *, int, int));
101 static int strioctl __P((int, int, void *, int, int));
102
103 /*
104  * sys_init - System-dependent initialization.
105  */
106 void
107 sys_init()
108 {
109     int ifd, x;
110 #ifndef sun
111     struct ifreq ifr;
112     struct {
113         union DL_primitives prim;
114         char space[64];
115     } reply;
116 #endif
117
118     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
119     setlogmask(LOG_UPTO(LOG_INFO));
120     if (debug)
121         setlogmask(LOG_UPTO(LOG_DEBUG));
122
123     ipfd = open("/dev/ip", O_RDWR, 0);
124     if (ipfd < 0) {
125         syslog(LOG_ERR, "Couldn't open IP device: %m");
126         die(1);
127     }
128
129     if (default_device)
130         tty_sid = getsid((pid_t)0);
131
132     pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
133     if (pppfd < 0) {
134         syslog(LOG_ERR, "Can't open /dev/ppp: %m");
135         die(1);
136     }
137     if (kdebugflag) {
138         x = PPPDBG_LOG + PPPDBG_DRIVER;
139         strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
140     }
141
142     /* Assign a new PPA and get its unit number. */
143     if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) {
144         syslog(LOG_ERR, "Can't create new PPP interface: %m");
145         die(1);
146     }
147
148     /*
149      * Open the ppp device again and link it under the ip multiplexor.
150      * IP will assign a unit number which hopefully is the same as ifunit.
151      * I don't know any way to be certain they will be the same. :-(
152      */
153     ifd = open("/dev/ppp", O_RDWR, 0);
154     if (ifd < 0) {
155         syslog(LOG_ERR, "Can't open /dev/ppp (2): %m");
156         die(1);
157     }
158     if (kdebugflag) {
159         x = PPPDBG_LOG + PPPDBG_DRIVER;
160         strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0);
161     }
162 #ifdef sun
163     if (ioctl(ifd, I_PUSH, "ip") < 0) {
164         syslog(LOG_ERR, "Can't push IP module: %m");
165         close(ifd);
166         die(1);
167     }
168 #else
169     if (dlpi_attach(ifd, ifunit) < 0 ||
170         dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
171         syslog(LOG_ERR, "Can't attach to ppp%d: %m", ifunit);
172         close(ifd);
173         die(1);
174     }
175 #endif
176     ipmuxid = ioctl(ipfd, I_LINK, ifd);
177     close(ifd);
178     if (ipmuxid < 0) {
179         syslog(LOG_ERR, "Can't link PPP device to IP: %m");
180         die(1);
181     }
182
183 #ifndef sun
184     /* Set the interface name for the link. */
185     (void) sprintf (ifr.ifr_name, "ppp%d", ifunit);
186     ifr.ifr_metric = ipmuxid;
187     if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0) {
188         syslog(LOG_ERR, "Can't set interface name %s: %m", ifr.ifr_name);
189         die(1);
190     }
191 #endif
192 }
193
194 /*
195  * sys_cleanup - restore any system state we modified before exiting:
196  * mark the interface down, delete default route and/or proxy arp entry.
197  * This should call die() because it's called from die().
198  */
199 void
200 sys_cleanup()
201 {
202     struct ifreq ifr;
203
204     if (if_is_up)
205         sifdown(0);
206     if (default_route_gateway)
207         cifdefaultroute(0, default_route_gateway);
208     if (proxy_arp_addr)
209         cifproxyarp(0, proxy_arp_addr);
210 }
211
212 /*
213  * sys_close - Clean up in a child process before execing.
214  */
215 void
216 sys_close()
217 {
218     close(ipfd);
219     if (pppfd >= 0)
220         close(pppfd);
221     closelog();
222 }
223
224 /*
225  * sys_check_options - check the options that the user specified
226  */
227 void
228 sys_check_options()
229 {
230 }
231
232
233 /*
234  * daemon - Detach us from controlling terminal session.
235  */
236 int
237 daemon(nochdir, noclose)
238     int nochdir, noclose;
239 {
240     int pid;
241
242     if ((pid = fork()) < 0)
243         return -1;
244     if (pid != 0)
245         exit(0);                /* parent dies */
246     setsid();
247     if (!nochdir)
248         chdir("/");
249     if (!noclose) {
250         fclose(stdin);          /* don't need stdin, stdout, stderr */
251         fclose(stdout);
252         fclose(stderr);
253     }
254     return 0;
255 }
256
257 /*
258  * note_debug_level - note a change in the debug level.
259  */
260 void
261 note_debug_level()
262 {
263     if (debug) {
264         setlogmask(LOG_UPTO(LOG_DEBUG));
265     } else {
266         setlogmask(LOG_UPTO(LOG_WARNING));
267     }
268 }
269
270 /*
271  * ppp_available - check whether the system has any ppp interfaces
272  */
273 int
274 ppp_available()
275 {
276     struct stat buf;
277
278     return stat("/dev/ppp", &buf) >= 0;
279 }
280
281 /*
282  * establish_ppp - Turn the serial port into a ppp interface.
283  */
284 void
285 establish_ppp(fd)
286     int fd;
287 {
288     int i;
289
290     /* Pop any existing modules off the tty stream. */
291     for (i = 0;; ++i)
292         if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
293             || ioctl(fd, I_POP, 0) < 0)
294             break;
295     tty_nmodules = i;
296
297     /* Push the async hdlc module and the compressor module. */
298     if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) {
299         syslog(LOG_ERR, "Couldn't push PPP Async HDLC module: %m");
300         die(1);
301     }
302     if (ioctl(fd, I_PUSH, "ppp_comp") < 0) {
303         syslog(LOG_ERR, "Couldn't push PPP compression module: %m");
304 /*      die(1); */
305     }
306
307     /* Link the serial port under the PPP multiplexor. */
308     if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) {
309         syslog(LOG_ERR, "Can't link tty to PPP mux: %m");
310         die(1);
311     }
312 }
313
314 /*
315  * restore_loop - reattach the ppp unit to the loopback.
316  * This doesn't need to do anything because disestablish_ppp does it.
317  */
318 void
319 restore_loop()
320 {
321 }
322
323 /*
324  * disestablish_ppp - Restore the serial port to normal operation.
325  * It attempts to reconstruct the stream with the previously popped
326  * modules.  This shouldn't call die() because it's called from die().
327  */
328 void
329 disestablish_ppp(fd)
330     int fd;
331 {
332     int i;
333
334     if (fdmuxid >= 0) {
335         if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
336             if (!hungup)
337                 syslog(LOG_ERR, "Can't unlink tty from PPP mux: %m");
338         }
339         fdmuxid = -1;
340
341         if (!hungup) {
342             while (ioctl(fd, I_POP, 0) >= 0)
343                 ;
344             for (i = tty_nmodules - 1; i >= 0; --i)
345                 if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
346                     syslog(LOG_ERR, "Couldn't restore tty module %s: %m",
347                            tty_modules[i]);
348         }
349         if (hungup && default_device && tty_sid > 0) {
350             /*
351              * If we have received a hangup, we need to send a SIGHUP
352              * to the terminal's controlling process.  The reason is
353              * that the original stream head for the terminal hasn't
354              * seen the M_HANGUP message (it went up through the ppp
355              * driver to the stream head for our fd to /dev/ppp).
356              */
357             kill(tty_sid, SIGHUP);
358         }
359     }
360 }
361
362 /*
363  * Check whether the link seems not to be 8-bit clean.
364  */
365 void
366 clean_check()
367 {
368     int x;
369     char *s;
370
371     if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
372         return;
373     s = NULL;
374     switch (~x) {
375     case RCV_B7_0:
376         s = "bit 7 set to 1";
377         break;
378     case RCV_B7_1:
379         s = "bit 7 set to 0";
380         break;
381     case RCV_EVNP:
382         s = "odd parity";
383         break;
384     case RCV_ODDP:
385         s = "even parity";
386         break;
387     }
388     if (s != NULL) {
389         syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
390         syslog(LOG_WARNING, "All received characters had %s", s);
391     }
392 }
393
394 /*
395  * List of valid speeds.
396  */
397 struct speed {
398     int speed_int, speed_val;
399 } speeds[] = {
400 #ifdef B50
401     { 50, B50 },
402 #endif
403 #ifdef B75
404     { 75, B75 },
405 #endif
406 #ifdef B110
407     { 110, B110 },
408 #endif
409 #ifdef B134
410     { 134, B134 },
411 #endif
412 #ifdef B150
413     { 150, B150 },
414 #endif
415 #ifdef B200
416     { 200, B200 },
417 #endif
418 #ifdef B300
419     { 300, B300 },
420 #endif
421 #ifdef B600
422     { 600, B600 },
423 #endif
424 #ifdef B1200
425     { 1200, B1200 },
426 #endif
427 #ifdef B1800
428     { 1800, B1800 },
429 #endif
430 #ifdef B2000
431     { 2000, B2000 },
432 #endif
433 #ifdef B2400
434     { 2400, B2400 },
435 #endif
436 #ifdef B3600
437     { 3600, B3600 },
438 #endif
439 #ifdef B4800
440     { 4800, B4800 },
441 #endif
442 #ifdef B7200
443     { 7200, B7200 },
444 #endif
445 #ifdef B9600
446     { 9600, B9600 },
447 #endif
448 #ifdef B19200
449     { 19200, B19200 },
450 #endif
451 #ifdef B38400
452     { 38400, B38400 },
453 #endif
454 #ifdef EXTA
455     { 19200, EXTA },
456 #endif
457 #ifdef EXTB
458     { 38400, EXTB },
459 #endif
460 #ifdef B57600
461     { 57600, B57600 },
462 #endif
463 #ifdef B115200
464     { 115200, B115200 },
465 #endif
466     { 0, 0 }
467 };
468
469 /*
470  * Translate from bits/second to a speed_t.
471  */
472 static int
473 translate_speed(bps)
474     int bps;
475 {
476     struct speed *speedp;
477
478     if (bps == 0)
479         return 0;
480     for (speedp = speeds; speedp->speed_int; speedp++)
481         if (bps == speedp->speed_int)
482             return speedp->speed_val;
483     syslog(LOG_WARNING, "speed %d not supported", bps);
484     return 0;
485 }
486
487 /*
488  * Translate from a speed_t to bits/second.
489  */
490 static int
491 baud_rate_of(speed)
492     int speed;
493 {
494     struct speed *speedp;
495
496     if (speed == 0)
497         return 0;
498     for (speedp = speeds; speedp->speed_int; speedp++)
499         if (speed == speedp->speed_val)
500             return speedp->speed_int;
501     return 0;
502 }
503
504 /*
505  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
506  * at the requested speed, etc.  If `local' is true, set CLOCAL
507  * regardless of whether the modem option was specified.
508  */
509 void
510 set_up_tty(fd, local)
511     int fd, local;
512 {
513     int speed;
514     struct termios tios;
515 #if !defined (CRTSCTS)
516     struct termiox tiox;
517 #endif
518
519     if (tcgetattr(fd, &tios) < 0) {
520         syslog(LOG_ERR, "tcgetattr: %m");
521         die(1);
522     }
523
524 #ifndef CRTSCTS
525     if (ioctl (fd, TCGETX, &tiox) < 0) {
526         syslog (LOG_ERR, "TCGETX: %m");
527         die (1);
528     }
529 #endif
530
531     if (!restore_term) {
532         inittermios = tios;
533 #ifndef CRTSCTS
534         inittermiox = tiox;
535 #endif
536         ioctl(fd, TIOCGWINSZ, &wsinfo);
537     }
538
539     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
540 #ifdef CRTSCTS
541     if (crtscts > 0)
542         tios.c_cflag |= CRTSCTS;
543     else if (crtscts < 0)
544         tios.c_cflag &= ~CRTSCTS;
545 #else
546     if (crtscts > 0) {
547         tiox.x_hflag |= RTSXOFF|CTSXON;
548     }
549     else if (crtscts < 0) {
550         tiox.x_hflag &= ~(RTSXOFF|CTSXON);
551     }
552 #endif
553
554     tios.c_cflag |= CS8 | CREAD | HUPCL;
555     if (local || !modem)
556         tios.c_cflag |= CLOCAL;
557     tios.c_iflag = IGNBRK | IGNPAR;
558     tios.c_oflag = 0;
559     tios.c_lflag = 0;
560     tios.c_cc[VMIN] = 1;
561     tios.c_cc[VTIME] = 0;
562
563     if (crtscts == -2) {
564         tios.c_iflag |= IXON | IXOFF;
565         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
566         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
567     }
568
569     speed = translate_speed(inspeed);
570     if (speed) {
571         cfsetospeed(&tios, speed);
572         cfsetispeed(&tios, speed);
573     } else {
574         speed = cfgetospeed(&tios);
575         /*
576          * We can't proceed if the serial port speed is 0,
577          * since that implies that the serial port is disabled.
578          */
579         if (speed == B0) {
580             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
581                    devnam);
582             die(1);
583         }
584     }
585
586     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
587         syslog(LOG_ERR, "tcsetattr: %m");
588         die(1);
589     }
590
591 #ifndef CRTSCTS
592     if (ioctl (fd, TCSETXF, &tiox) < 0){
593         syslog (LOG_ERR, "TCSETXF: %m");
594         die (1);
595     }
596 #endif
597
598     baud_rate = inspeed = baud_rate_of(speed);
599     restore_term = 1;
600 }
601
602 /*
603  * restore_tty - restore the terminal to the saved settings.
604  */
605 void
606 restore_tty(fd)
607     int fd;
608 {
609     if (restore_term) {
610         if (!default_device) {
611             /*
612              * Turn off echoing, because otherwise we can get into
613              * a loop with the tty and the modem echoing to each other.
614              * We presume we are the sole user of this tty device, so
615              * when we close it, it will revert to its defaults anyway.
616              */
617             inittermios.c_lflag &= ~(ECHO | ECHONL);
618         }
619         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
620             if (!hungup && errno != ENXIO)
621                 syslog(LOG_WARNING, "tcsetattr: %m");
622 #ifndef CRTSCTS
623         if (ioctl (fd, TCSETXF, &inittermiox) < 0){
624             if (!hungup && errno != ENXIO)
625                 syslog (LOG_ERR, "TCSETXF: %m");
626         }
627 #endif
628         ioctl(fd, TIOCSWINSZ, &wsinfo);
629         restore_term = 0;
630     }
631 }
632
633 /*
634  * setdtr - control the DTR line on the serial port.
635  * This is called from die(), so it shouldn't call die().
636  */
637 void
638 setdtr(fd, on)
639 int fd, on;
640 {
641     int modembits = TIOCM_DTR;
642
643     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
644 }
645
646 /*
647  * open_loopback - open the device we use for getting packets
648  * in demand mode.  Under Solaris 2, we use our existing fd
649  * to the ppp driver.
650  */
651 void
652 open_ppp_loopback()
653 {
654 }
655
656 /*
657  * output - Output PPP packet.
658  */
659 void
660 output(unit, p, len)
661     int unit;
662     u_char *p;
663     int len;
664 {
665     struct strbuf data;
666     int retries;
667     struct pollfd pfd;
668
669     if (debug)
670         log_packet(p, len, "sent ");
671
672     data.len = len;
673     data.buf = (caddr_t) p;
674     retries = 4;
675     while (putmsg(pppfd, NULL, &data, 0) < 0) {
676         if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
677             if (errno != ENXIO)
678                 syslog(LOG_ERR, "Couldn't send packet: %m");
679             break;
680         }
681         pfd.fd = pppfd;
682         pfd.events = POLLOUT;
683         poll(&pfd, 1, 250);     /* wait for up to 0.25 seconds */
684     }
685 }
686
687
688 /*
689  * wait_input - wait until there is data available on fd,
690  * for the length of time specified by *timo (indefinite
691  * if timo is NULL).
692  */
693 void
694 wait_input(timo)
695     struct timeval *timo;
696 {
697     int t;
698     struct pollfd pfd;
699
700     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
701     pfd.fd = pppfd;
702     pfd.events = POLLIN | POLLPRI | POLLHUP;
703     if (poll(&pfd, 1, t) < 0 && errno != EINTR) {
704         syslog(LOG_ERR, "poll: %m");
705         die(1);
706     }
707 }
708
709 /*
710  * wait_loop_output - wait until there is data available on the
711  * loopback, for the length of time specified by *timo (indefinite
712  * if timo is NULL).
713  */
714 void
715 wait_loop_output(timo)
716     struct timeval *timo;
717 {
718     wait_input(timo);
719 }
720
721 /*
722  * wait_time - wait for a given length of time or until a
723  * signal is received.
724  */
725 void
726 wait_time(timo)
727     struct timeval *timo;
728 {
729     int n;
730
731     n = select(0, NULL, NULL, NULL, timo);
732     if (n < 0 && errno != EINTR) {
733         syslog(LOG_ERR, "select: %m");
734         die(1);
735     }
736 }
737
738
739 /*
740  * read_packet - get a PPP packet from the serial device.
741  */
742 int
743 read_packet(buf)
744     u_char *buf;
745 {
746     struct strbuf ctrl, data;
747     int flags, len;
748     unsigned char ctrlbuf[sizeof(union DL_primitives) + 64];
749
750     for (;;) {
751         data.maxlen = PPP_MRU + PPP_HDRLEN;
752         data.buf = (caddr_t) buf;
753         ctrl.maxlen = sizeof(ctrlbuf);
754         ctrl.buf = (caddr_t) ctrlbuf;
755         flags = 0;
756         len = getmsg(pppfd, &ctrl, &data, &flags);
757         if (len < 0) {
758             if (errno = EAGAIN || errno == EINTR)
759                 return -1;
760             syslog(LOG_ERR, "Error reading packet: %m");
761             die(1);
762         }
763
764         if (ctrl.len <= 0)
765             return data.len;
766
767         /*
768          * Got a M_PROTO or M_PCPROTO message.  Interpret it
769          * as a DLPI primitive??
770          */
771         if (debug)
772             syslog(LOG_DEBUG, "got dlpi prim 0x%x, len=%d",
773                    ((union DL_primitives *)ctrlbuf)->dl_primitive, ctrl.len);
774
775     }
776 }
777
778 /*
779  * get_loop_output - get outgoing packets from the ppp device,
780  * and detect when we want to bring the real link up.
781  * Return value is 1 if we need to bring up the link, 0 otherwise.
782  */
783 int
784 get_loop_output()
785 {
786     int len;
787     int rv = 0;
788
789     while ((len = read_packet(inpacket_buf)) > 0) {
790         if (loop_frame(inpacket_buf, len))
791             rv = 1;
792     }
793     return rv;
794 }
795
796 /*
797  * ppp_send_config - configure the transmit characteristics of
798  * the ppp interface.
799  */
800 void
801 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
802     int unit, mtu;
803     u_int32_t asyncmap;
804     int pcomp, accomp;
805 {
806     int cf[2];
807
808     link_mtu = mtu;
809     if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
810         if (hungup && errno == ENXIO)
811             return;
812         syslog(LOG_ERR, "Couldn't set MTU: %m");
813     }
814     if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
815         syslog(LOG_ERR, "Couldn't set transmit ACCM: %m");
816     }
817     cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
818     cf[1] = COMP_PROT | COMP_AC;
819     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
820         syslog(LOG_ERR, "Couldn't set prot/AC compression: %m");
821     }
822 }
823
824 /*
825  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
826  */
827 void
828 ppp_set_xaccm(unit, accm)
829     int unit;
830     ext_accm accm;
831 {
832     if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
833         if (!hungup || errno != ENXIO)
834             syslog(LOG_WARNING, "Couldn't set extended ACCM: %m");
835     }
836 }
837
838 /*
839  * ppp_recv_config - configure the receive-side characteristics of
840  * the ppp interface.
841  */
842 void
843 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
844     int unit, mru;
845     u_int32_t asyncmap;
846     int pcomp, accomp;
847 {
848     int cf[2];
849
850     link_mru = mru;
851     if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
852         if (hungup && errno == ENXIO)
853             return;
854         syslog(LOG_ERR, "Couldn't set MRU: %m");
855     }
856     if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
857         syslog(LOG_ERR, "Couldn't set receive ACCM: %m");
858     }
859     cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
860     cf[1] = DECOMP_PROT | DECOMP_AC;
861     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
862         syslog(LOG_ERR, "Couldn't set prot/AC decompression: %m");
863     }
864 }
865
866 /*
867  * ccp_test - ask kernel whether a given compression method
868  * is acceptable for use.
869  */
870 int
871 ccp_test(unit, opt_ptr, opt_len, for_transmit)
872     int unit, opt_len, for_transmit;
873     u_char *opt_ptr;
874 {
875     if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
876                  opt_ptr, opt_len, 0) >= 0)
877         return 1;
878     return (errno == ENOSR)? 0: -1;
879 }
880
881 /*
882  * ccp_flags_set - inform kernel about the current state of CCP.
883  */
884 void
885 ccp_flags_set(unit, isopen, isup)
886     int unit, isopen, isup;
887 {
888     int cf[2];
889
890     cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
891     cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
892     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
893         if (!hungup || errno != ENXIO)
894             syslog(LOG_ERR, "Couldn't set kernel CCP state: %m");
895     }
896 }
897
898 /*
899  * get_idle_time - return how long the link has been idle.
900  */
901 int
902 get_idle_time(u, ip)
903     int u;
904     struct ppp_idle *ip;
905 {
906     return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
907 }
908
909
910 /*
911  * set_filters - transfer the pass and active filters to the kernel.
912  */
913 int
914 set_filters(pass, active)
915     struct bpf_program *pass, *active;
916 {
917     int ret = 1;
918
919     if (pass->bf_len > 0) {
920         if (strioctl(pppfd, PPPIO_PASSFILT, pass,
921                      sizeof(struct bpf_program), 0) < 0) {
922             syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m");
923             ret = 0;
924         }
925     }
926     if (active->bf_len > 0) {
927         if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
928                      sizeof(struct bpf_program), 0) < 0) {
929             syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m");
930             ret = 0;
931         }
932     }
933     return ret;
934 }
935
936
937 /*
938  * ccp_fatal_error - returns 1 if decompression was disabled as a
939  * result of an error detected after decompression of a packet,
940  * 0 otherwise.  This is necessary because of patent nonsense.
941  */
942 int
943 ccp_fatal_error(unit)
944     int unit;
945 {
946     int cf[2];
947
948     cf[0] = cf[1] = 0;
949     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
950         if (errno != ENXIO && errno != EINVAL)
951             syslog(LOG_ERR, "Couldn't get compression flags: %m");
952         return 0;
953     }
954     return cf[0] & CCP_FATALERROR;
955 }
956
957 /*
958  * sifvjcomp - config tcp header compression
959  */
960 int
961 sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
962     int u, vjcomp, xcidcomp, xmaxcid;
963 {
964     int cf[2];
965     char maxcid[2];
966
967     if (vjcomp) {
968         maxcid[0] = xcidcomp;
969         maxcid[1] = 15;         /* XXX should be rmaxcid */
970         if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
971             syslog(LOG_ERR, "Couldn't initialize VJ compression: %m");
972         }
973     }
974
975     cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0)  /* XXX this is wrong */
976         + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
977     cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
978     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
979         if (vjcomp)
980             syslog(LOG_ERR, "Couldn't enable VJ compression: %m");
981     }
982
983     return 1;
984 }
985
986 /*
987  * sifup - Config the interface up and enable IP packets to pass.
988  */
989 int
990 sifup(u)
991     int u;
992 {
993     struct ifreq ifr;
994
995     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
996     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
997         syslog(LOG_ERR, "Couldn't mark interface up (get): %m");
998         return 0;
999     }
1000     ifr.ifr_flags |= IFF_UP;
1001     if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
1002         syslog(LOG_ERR, "Couldn't mark interface up (set): %m");
1003         return 0;
1004     }
1005     if_is_up = 1;
1006     return 1;
1007 }
1008
1009 /*
1010  * sifdown - Config the interface down and disable IP.
1011  */
1012 int
1013 sifdown(u)
1014     int u;
1015 {
1016     struct ifreq ifr;
1017
1018     if (ipmuxid < 0)
1019         return 1;
1020     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1021     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
1022         syslog(LOG_ERR, "Couldn't mark interface down (get): %m");
1023         return 0;
1024     }
1025     ifr.ifr_flags &= ~IFF_UP;
1026     if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
1027         syslog(LOG_ERR, "Couldn't mark interface down (set): %m");
1028         return 0;
1029     }
1030     if_is_up = 0;
1031     return 1;
1032 }
1033
1034 /*
1035  * sifnpmode - Set the mode for handling packets for a given NP.
1036  */
1037 int
1038 sifnpmode(u, proto, mode)
1039     int u;
1040     int proto;
1041     enum NPmode mode;
1042 {
1043     int npi[2];
1044
1045     npi[0] = proto;
1046     npi[1] = (int) mode;
1047     if (strioctl(pppfd, PPPIO_NPMODE, &npi, 2 * sizeof(int), 0) < 0) {
1048         syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
1049         return 0;
1050     }
1051     return 1;
1052 }
1053
1054 #define INET_ADDR(x)    (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
1055
1056 /*
1057  * sifaddr - Config the interface IP addresses and netmask.
1058  */
1059 int
1060 sifaddr(u, o, h, m)
1061     int u;
1062     u_int32_t o, h, m;
1063 {
1064     struct ifreq ifr;
1065
1066     memset(&ifr, 0, sizeof(ifr));
1067     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1068     ifr.ifr_addr.sa_family = AF_INET;
1069     INET_ADDR(ifr.ifr_addr) = m;
1070     if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) {
1071         syslog(LOG_ERR, "Couldn't set IP netmask: %m");
1072     }
1073     ifr.ifr_addr.sa_family = AF_INET;
1074     INET_ADDR(ifr.ifr_addr) = o;
1075     if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
1076         syslog(LOG_ERR, "Couldn't set local IP address: %m");
1077     }
1078     ifr.ifr_dstaddr.sa_family = AF_INET;
1079     INET_ADDR(ifr.ifr_dstaddr) = h;
1080     if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
1081         syslog(LOG_ERR, "Couldn't set remote IP address: %m");
1082     }
1083     ifr.ifr_metric = link_mtu;
1084     if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
1085         syslog(LOG_ERR, "Couldn't set IP MTU: %m");
1086     }
1087
1088     return 1;
1089 }
1090
1091 /*
1092  * cifaddr - Clear the interface IP addresses, and delete routes
1093  * through the interface if possible.
1094  */
1095 int
1096 cifaddr(u, o, h)
1097     int u;
1098     u_int32_t o, h;
1099 {
1100 #if 0
1101     if (ipmuxid >= 0) {
1102         if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) {
1103             syslog(LOG_ERR, "Can't remove ppp interface unit: %m");
1104             return 0;
1105         }
1106         ipmuxid = -1;
1107     }
1108 #endif
1109     return 1;
1110 }
1111
1112 /*
1113  * sifdefaultroute - assign a default route through the address given.
1114  */
1115 int
1116 sifdefaultroute(u, g)
1117     int u;
1118     u_int32_t g;
1119 {
1120     struct rtentry rt;
1121
1122     memset(&rt, 0, sizeof(rt));
1123     rt.rt_dst.sa_family = AF_INET;
1124     INET_ADDR(rt.rt_dst) = 0;
1125     rt.rt_gateway.sa_family = AF_INET;
1126     INET_ADDR(rt.rt_gateway) = g;
1127     rt.rt_flags = RTF_GATEWAY;
1128
1129     if (ioctl(ipfd, SIOCADDRT, &rt) < 0) {
1130         syslog(LOG_ERR, "Can't add default route: %m");
1131         return 0;
1132     }
1133
1134     default_route_gateway = g;
1135     return 1;
1136 }
1137
1138 /*
1139  * cifdefaultroute - delete a default route through the address given.
1140  */
1141 int
1142 cifdefaultroute(u, g)
1143     int u;
1144     u_int32_t g;
1145 {
1146     struct rtentry rt;
1147
1148     memset(&rt, 0, sizeof(rt));
1149     rt.rt_dst.sa_family = AF_INET;
1150     INET_ADDR(rt.rt_dst) = 0;
1151     rt.rt_gateway.sa_family = AF_INET;
1152     INET_ADDR(rt.rt_gateway) = g;
1153     rt.rt_flags = RTF_GATEWAY;
1154
1155     if (ioctl(ipfd, SIOCDELRT, &rt) < 0) {
1156         syslog(LOG_ERR, "Can't delete default route: %m");
1157         return 0;
1158     }
1159
1160     default_route_gateway = 0;
1161     return 1;
1162 }
1163
1164 /*
1165  * sifproxyarp - Make a proxy ARP entry for the peer.
1166  */
1167 int
1168 sifproxyarp(unit, hisaddr)
1169     int unit;
1170     u_int32_t hisaddr;
1171 {
1172     struct arpreq arpreq;
1173
1174     memset(&arpreq, 0, sizeof(arpreq));
1175     if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
1176         return 0;
1177
1178     arpreq.arp_pa.sa_family = AF_INET;
1179     INET_ADDR(arpreq.arp_pa) = hisaddr;
1180     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1181     if (ioctl(ipfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
1182         syslog(LOG_ERR, "Couldn't set proxy ARP entry: %m");
1183         return 0;
1184     }
1185
1186     proxy_arp_addr = hisaddr;
1187     return 1;
1188 }
1189
1190 /*
1191  * cifproxyarp - Delete the proxy ARP entry for the peer.
1192  */
1193 int
1194 cifproxyarp(unit, hisaddr)
1195     int unit;
1196     u_int32_t hisaddr;
1197 {
1198     struct arpreq arpreq;
1199
1200     memset(&arpreq, 0, sizeof(arpreq));
1201     arpreq.arp_pa.sa_family = AF_INET;
1202     INET_ADDR(arpreq.arp_pa) = hisaddr;
1203     if (ioctl(ipfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1204         syslog(LOG_ERR, "Couldn't delete proxy ARP entry: %m");
1205         return 0;
1206     }
1207
1208     proxy_arp_addr = 0;
1209     return 1;
1210 }
1211
1212 /*
1213  * get_ether_addr - get the hardware address of an interface on the
1214  * the same subnet as ipaddr.
1215  */
1216 #define MAX_IFS         32
1217
1218 static int
1219 get_ether_addr(ipaddr, hwaddr)
1220     u_int32_t ipaddr;
1221     struct sockaddr *hwaddr;
1222 {
1223     struct ifreq *ifr, *ifend, ifreq;
1224     int nif;
1225     struct ifconf ifc;
1226     u_int32_t ina, mask;
1227
1228     /*
1229      * Scan through the system's network interfaces.
1230      */
1231 #ifdef SIOCGIFNUM
1232     if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
1233 #endif
1234         nif = MAX_IFS;
1235     ifc.ifc_len = nif * sizeof(struct ifreq);
1236     ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
1237     if (ifc.ifc_req == 0)
1238         return 0;
1239     if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
1240         syslog(LOG_WARNING, "Couldn't get system interface list: %m");
1241         return 0;
1242     }
1243     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1244     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1245         if (ifr->ifr_addr.sa_family != AF_INET)
1246             continue;
1247         /*
1248          * Check that the interface is up, and not point-to-point or loopback.
1249          */
1250         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1251         if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
1252             continue;
1253         if ((ifreq.ifr_flags &
1254              (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1255             != (IFF_UP|IFF_BROADCAST))
1256             continue;
1257         /*
1258          * Get its netmask and check that it's on the right subnet.
1259          */
1260         if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
1261             continue;
1262         ina = INET_ADDR(ifr->ifr_addr);
1263         mask = INET_ADDR(ifreq.ifr_addr);
1264         if ((ipaddr & mask) == (ina & mask))
1265             break;
1266     }
1267
1268     if (ifr >= ifend) {
1269         syslog(LOG_WARNING, "No suitable interface found for proxy ARP");
1270         return 0;
1271     }
1272
1273     syslog(LOG_INFO, "found interface %s for proxy ARP", ifr->ifr_name);
1274     if (!get_hw_addr(ifr->ifr_name, hwaddr)) {
1275         syslog(LOG_ERR, "Couldn't get hardware address for %s", ifr->ifr_name);
1276         return 0;
1277     }
1278
1279     return 1;
1280 }
1281
1282 /*
1283  * get_hw_addr - obtain the hardware address for a named interface.
1284  */
1285 static int
1286 get_hw_addr(name, hwaddr)
1287     char *name;
1288     struct sockaddr *hwaddr;
1289 {
1290     char *p, *q;
1291     int unit, iffd, adrlen;
1292     unsigned char *adrp;
1293     char ifdev[24];
1294     struct {
1295         union DL_primitives prim;
1296         char space[64];
1297     } reply;
1298
1299     /*
1300      * We have to open the device and ask it for its hardware address.
1301      * First split apart the device name and unit.
1302      */
1303     strcpy(ifdev, "/dev/");
1304     q = ifdev + 5;              /* strlen("/dev/") */
1305     while (*name != 0 && !isdigit(*name))
1306         *q++ = *name++;
1307     *q = 0;
1308     unit = atoi(name);
1309
1310     /*
1311      * Open the device and do a DLPI attach and phys_addr_req.
1312      */
1313     iffd = open(ifdev, O_RDWR);
1314     if (iffd < 0) {
1315         syslog(LOG_ERR, "Can't open %s: %m", ifdev);
1316         return 0;
1317     }
1318     if (dlpi_attach(iffd, unit) < 0
1319         || dlpi_get_reply(iffd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0
1320         || dlpi_info_req(iffd) < 0
1321         || dlpi_get_reply(iffd, &reply.prim, DL_INFO_ACK, sizeof(reply)) < 0) {
1322         close(iffd);
1323         return 0;
1324     }
1325
1326     adrlen = reply.prim.info_ack.dl_addr_length;
1327     adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset;
1328 #if DL_CURRENT_VERSION >= 2
1329     if (reply.prim.info_ack.dl_sap_length < 0)
1330         adrlen += reply.prim.info_ack.dl_sap_length;
1331     else
1332         adrp += reply.prim.info_ack.dl_sap_length;
1333 #endif
1334     hwaddr->sa_family = AF_UNSPEC;
1335     memcpy(hwaddr->sa_data, adrp, adrlen);
1336
1337     return 1;
1338 }
1339
1340 static int
1341 dlpi_attach(fd, ppa)
1342     int fd, ppa;
1343 {
1344     dl_attach_req_t req;
1345     struct strbuf buf;
1346
1347     req.dl_primitive = DL_ATTACH_REQ;
1348     req.dl_ppa = ppa;
1349     buf.len = sizeof(req);
1350     buf.buf = (void *) &req;
1351     return putmsg(fd, &buf, NULL, RS_HIPRI);
1352 }
1353
1354 static int
1355 dlpi_info_req(fd)
1356     int fd;
1357 {
1358     dl_info_req_t req;
1359     struct strbuf buf;
1360
1361     req.dl_primitive = DL_INFO_REQ;
1362     buf.len = sizeof(req);
1363     buf.buf = (void *) &req;
1364     return putmsg(fd, &buf, NULL, RS_HIPRI);
1365 }
1366
1367 static int
1368 dlpi_get_reply(fd, reply, expected_prim, maxlen)
1369     union DL_primitives *reply;
1370     int fd, expected_prim, maxlen;
1371 {
1372     struct strbuf buf;
1373     int flags, n;
1374     struct pollfd pfd;
1375
1376     /*
1377      * Use poll to wait for a message with a timeout.
1378      */
1379     pfd.fd = fd;
1380     pfd.events = POLLIN | POLLPRI;
1381     do {
1382         n = poll(&pfd, 1, 1000);
1383     } while (n == -1 && errno == EINTR);
1384     if (n <= 0)
1385         return -1;
1386
1387     /*
1388      * Get the reply.
1389      */
1390     buf.maxlen = maxlen;
1391     buf.buf = (void *) reply;
1392     flags = 0;
1393     if (getmsg(fd, &buf, NULL, &flags) < 0)
1394         return -1;
1395
1396     if (buf.len < sizeof(ulong)) {
1397         if (debug)
1398             syslog(LOG_DEBUG, "dlpi response short (len=%d)\n", buf.len);
1399         return -1;
1400     }
1401
1402     if (reply->dl_primitive == expected_prim)
1403         return 0;
1404
1405     if (debug) {
1406         if (reply->dl_primitive == DL_ERROR_ACK) {
1407             syslog(LOG_DEBUG, "dlpi error %d (unix errno %d) for prim %x\n",
1408                    reply->error_ack.dl_errno, reply->error_ack.dl_unix_errno,
1409                    reply->error_ack.dl_error_primitive);
1410         } else {
1411             syslog(LOG_DEBUG, "dlpi unexpected response prim %x\n",
1412                    reply->dl_primitive);
1413         }
1414     }
1415
1416     return -1;
1417 }
1418
1419 /*
1420  * Return user specified netmask, modified by any mask we might determine
1421  * for address `addr' (in network byte order).
1422  * Here we scan through the system's list of interfaces, looking for
1423  * any non-point-to-point interfaces which might appear to be on the same
1424  * network as `addr'.  If we find any, we OR in their netmask to the
1425  * user-specified netmask.
1426  */
1427 u_int32_t
1428 GetMask(addr)
1429     u_int32_t addr;
1430 {
1431     u_int32_t mask, nmask, ina;
1432     struct ifreq *ifr, *ifend, ifreq;
1433     int nif;
1434     struct ifconf ifc;
1435
1436     addr = ntohl(addr);
1437     if (IN_CLASSA(addr))        /* determine network mask for address class */
1438         nmask = IN_CLASSA_NET;
1439     else if (IN_CLASSB(addr))
1440         nmask = IN_CLASSB_NET;
1441     else
1442         nmask = IN_CLASSC_NET;
1443     /* class D nets are disallowed by bad_ip_adrs */
1444     mask = netmask | htonl(nmask);
1445
1446     /*
1447      * Scan through the system's network interfaces.
1448      */
1449 #ifdef SIOCGIFNUM
1450     if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
1451 #endif
1452         nif = MAX_IFS;
1453     ifc.ifc_len = nif * sizeof(struct ifreq);
1454     ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
1455     if (ifc.ifc_req == 0)
1456         return mask;
1457     if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
1458         syslog(LOG_WARNING, "Couldn't get system interface list: %m");
1459         return mask;
1460     }
1461     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1462     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1463         /*
1464          * Check the interface's internet address.
1465          */
1466         if (ifr->ifr_addr.sa_family != AF_INET)
1467             continue;
1468         ina = INET_ADDR(ifr->ifr_addr);
1469         if ((ntohl(ina) & nmask) != (addr & nmask))
1470             continue;
1471         /*
1472          * Check that the interface is up, and not point-to-point or loopback.
1473          */
1474         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1475         if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
1476             continue;
1477         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1478             != IFF_UP)
1479             continue;
1480         /*
1481          * Get its netmask and OR it into our mask.
1482          */
1483         if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
1484             continue;
1485         mask |= INET_ADDR(ifreq.ifr_addr);
1486     }
1487
1488     return mask;
1489 }
1490
1491 /*
1492  * logwtmp - write an accounting record to the /var/adm/wtmp file.
1493  */
1494 int
1495 logwtmp(line, name, host)
1496     char *line, *name, *host;
1497 {
1498     static struct utmpx utmpx;
1499
1500     if (name[0] != 0) {
1501         /* logging in */
1502         strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user));
1503         strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id));
1504         strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
1505         utmpx.ut_pid = getpid();
1506         utmpx.ut_type = USER_PROCESS;
1507     } else {
1508         utmpx.ut_type = DEAD_PROCESS;
1509     }
1510     gettimeofday(&utmpx.ut_tv, NULL);
1511     updwtmpx("/var/adm/wtmpx", &utmpx);
1512     return 0;
1513 }
1514
1515 /*
1516  * gethostid - return the serial number of this machine.
1517  */
1518 int
1519 gethostid()
1520 {
1521     char buf[32];
1522
1523     if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) < 0) {
1524         syslog(LOG_ERR, "sysinfo: %m");
1525         return 0;
1526     }
1527     return (int) strtoul(buf, NULL, 16);
1528 }
1529
1530 static int
1531 strioctl(fd, cmd, ptr, ilen, olen)
1532     int fd, cmd, ilen, olen;
1533     void *ptr;
1534 {
1535     struct strioctl str;
1536
1537     str.ic_cmd = cmd;
1538     str.ic_timout = 0;
1539     str.ic_len = ilen;
1540     str.ic_dp = ptr;
1541     if (ioctl(fd, I_STR, &str) == -1)
1542         return -1;
1543     if (str.ic_len != olen)
1544         syslog(LOG_DEBUG, "strioctl: expected %d bytes, got %d for cmd %x\n",
1545                olen, str.ic_len, cmd);
1546     return 0;
1547 }
1548
1549 /*
1550  * lock - create a lock file for the named lock device
1551  */
1552
1553 #define LOCK_PREFIX     "/var/spool/locks/LK."
1554 static char lock_file[40];      /* name of lock file created */
1555
1556 int
1557 lock(dev)
1558     char *dev;
1559 {
1560     int n, fd, pid;
1561     struct stat sbuf;
1562     char ascii_pid[12];
1563
1564     if (stat(dev, &sbuf) < 0) {
1565         syslog(LOG_ERR, "Can't get device number for %s: %m", dev);
1566         return -1;
1567     }
1568     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
1569         syslog(LOG_ERR, "Can't lock %s: not a character device", dev);
1570         return -1;
1571     }
1572     sprintf(lock_file, "%s%03d.%03d.%03d", LOCK_PREFIX, major(sbuf.st_dev),
1573             major(sbuf.st_rdev), minor(sbuf.st_rdev));
1574
1575     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1576         if (errno == EEXIST
1577             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1578             /* Read the lock file to find out who has the device locked */
1579             n = read(fd, ascii_pid, 11);
1580             if (n <= 0) {
1581                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1582                 close(fd);
1583             } else {
1584                 ascii_pid[n] = 0;
1585                 pid = atoi(ascii_pid);
1586                 if (pid > 0 && kill(pid, 0) == -1 && errno == ESRCH) {
1587                     /* pid no longer exists - remove the lock file */
1588                     if (unlink(lock_file) == 0) {
1589                         close(fd);
1590                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1591                                dev, pid);
1592                         continue;
1593                     } else
1594                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1595                                dev);
1596                 } else
1597                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1598                            dev, pid);
1599             }
1600             close(fd);
1601         } else
1602             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1603         lock_file[0] = 0;
1604         return -1;
1605     }
1606
1607     sprintf(ascii_pid, "%10d\n", getpid());
1608     write(fd, ascii_pid, 11);
1609
1610     close(fd);
1611     return 1;
1612 }
1613
1614 /*
1615  * unlock - remove our lockfile
1616  */
1617 void
1618 unlock()
1619 {
1620     if (lock_file[0]) {
1621         unlink(lock_file);
1622         lock_file[0] = 0;
1623     }
1624 }