Added packet filtering, subnet spec for allowed IP addr; select
[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.9 1996/01/01 23:06:39 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 wait_loop_output(timo)
715     struct timeval *timo;
716 {
717     wait_input(timo);
718 }
719
720 /*
721  * wait_time - wait for a given length of time or until a
722  * signal is received.
723  */
724 wait_time(timo)
725     struct timeval *timo;
726 {
727     int n;
728
729     n = select(0, NULL, NULL, NULL, timo);
730     if (n < 0 && errno != EINTR) {
731         syslog(LOG_ERR, "select: %m");
732         die(1);
733     }
734 }
735
736
737 /*
738  * read_packet - get a PPP packet from the serial device.
739  */
740 int
741 read_packet(buf)
742     u_char *buf;
743 {
744     struct strbuf ctrl, data;
745     int flags, len;
746     unsigned char ctrlbuf[sizeof(union DL_primitives) + 64];
747
748     for (;;) {
749         data.maxlen = PPP_MRU + PPP_HDRLEN;
750         data.buf = (caddr_t) buf;
751         ctrl.maxlen = sizeof(ctrlbuf);
752         ctrl.buf = (caddr_t) ctrlbuf;
753         flags = 0;
754         len = getmsg(pppfd, &ctrl, &data, &flags);
755         if (len < 0) {
756             if (errno = EAGAIN || errno == EINTR)
757                 return -1;
758             syslog(LOG_ERR, "Error reading packet: %m");
759             die(1);
760         }
761
762         if (ctrl.len <= 0)
763             return data.len;
764
765         /*
766          * Got a M_PROTO or M_PCPROTO message.  Interpret it
767          * as a DLPI primitive??
768          */
769         if (debug)
770             syslog(LOG_DEBUG, "got dlpi prim 0x%x, len=%d",
771                    ((union DL_primitives *)ctrlbuf)->dl_primitive, ctrl.len);
772
773     }
774 }
775
776 /*
777  * get_loop_output - get outgoing packets from the ppp device,
778  * and detect when we want to bring the real link up.
779  * Return value is 1 if we need to bring up the link, 0 otherwise.
780  */
781 int
782 get_loop_output()
783 {
784     int len;
785     int rv = 0;
786
787     while ((len = read_packet(inpacket_buf)) > 0) {
788         if (loop_frame(inpacket_buf, len))
789             rv = 1;
790     }
791     return rv;
792 }
793
794 /*
795  * ppp_send_config - configure the transmit characteristics of
796  * the ppp interface.
797  */
798 void
799 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
800     int unit, mtu;
801     u_int32_t asyncmap;
802     int pcomp, accomp;
803 {
804     int cf[2];
805
806     link_mtu = mtu;
807     if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
808         if (hungup && errno == ENXIO)
809             return;
810         syslog(LOG_ERR, "Couldn't set MTU: %m");
811     }
812     if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
813         syslog(LOG_ERR, "Couldn't set transmit ACCM: %m");
814     }
815     cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
816     cf[1] = COMP_PROT | COMP_AC;
817     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
818         syslog(LOG_ERR, "Couldn't set prot/AC compression: %m");
819     }
820 }
821
822 /*
823  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
824  */
825 void
826 ppp_set_xaccm(unit, accm)
827     int unit;
828     ext_accm accm;
829 {
830     if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
831         if (!hungup || errno != ENXIO)
832             syslog(LOG_WARNING, "Couldn't set extended ACCM: %m");
833     }
834 }
835
836 /*
837  * ppp_recv_config - configure the receive-side characteristics of
838  * the ppp interface.
839  */
840 void
841 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
842     int unit, mru;
843     u_int32_t asyncmap;
844     int pcomp, accomp;
845 {
846     int cf[2];
847
848     link_mru = mru;
849     if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
850         if (hungup && errno == ENXIO)
851             return;
852         syslog(LOG_ERR, "Couldn't set MRU: %m");
853     }
854     if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
855         syslog(LOG_ERR, "Couldn't set receive ACCM: %m");
856     }
857     cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
858     cf[1] = DECOMP_PROT | DECOMP_AC;
859     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
860         syslog(LOG_ERR, "Couldn't set prot/AC decompression: %m");
861     }
862 }
863
864 /*
865  * ccp_test - ask kernel whether a given compression method
866  * is acceptable for use.
867  */
868 int
869 ccp_test(unit, opt_ptr, opt_len, for_transmit)
870     int unit, opt_len, for_transmit;
871     u_char *opt_ptr;
872 {
873     if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
874                  opt_ptr, opt_len, 0) >= 0)
875         return 1;
876     return (errno == ENOSR)? 0: -1;
877 }
878
879 /*
880  * ccp_flags_set - inform kernel about the current state of CCP.
881  */
882 void
883 ccp_flags_set(unit, isopen, isup)
884     int unit, isopen, isup;
885 {
886     int cf[2];
887
888     cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
889     cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
890     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
891         if (!hungup || errno != ENXIO)
892             syslog(LOG_ERR, "Couldn't set kernel CCP state: %m");
893     }
894 }
895
896 /*
897  * get_idle_time - return how long the link has been idle.
898  */
899 int
900 get_idle_time(u, ip)
901     int u;
902     struct ppp_idle *ip;
903 {
904     return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
905 }
906
907
908 /*
909  * ccp_fatal_error - returns 1 if decompression was disabled as a
910  * result of an error detected after decompression of a packet,
911  * 0 otherwise.  This is necessary because of patent nonsense.
912  */
913 int
914 ccp_fatal_error(unit)
915     int unit;
916 {
917     int cf[2];
918
919     cf[0] = cf[1] = 0;
920     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
921         if (errno != ENXIO && errno != EINVAL)
922             syslog(LOG_ERR, "Couldn't get compression flags: %m");
923         return 0;
924     }
925     return cf[0] & CCP_FATALERROR;
926 }
927
928 /*
929  * sifvjcomp - config tcp header compression
930  */
931 int
932 sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
933     int u, vjcomp, xcidcomp, xmaxcid;
934 {
935     int cf[2];
936     char maxcid[2];
937
938     if (vjcomp) {
939         maxcid[0] = xcidcomp;
940         maxcid[1] = 15;         /* XXX should be rmaxcid */
941         if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
942             syslog(LOG_ERR, "Couldn't initialize VJ compression: %m");
943         }
944     }
945
946     cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0)  /* XXX this is wrong */
947         + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
948     cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
949     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
950         if (vjcomp)
951             syslog(LOG_ERR, "Couldn't enable VJ compression: %m");
952     }
953
954     return 1;
955 }
956
957 /*
958  * sifup - Config the interface up and enable IP packets to pass.
959  */
960 int
961 sifup(u)
962     int u;
963 {
964     struct ifreq ifr;
965
966     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
967     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
968         syslog(LOG_ERR, "Couldn't mark interface up (get): %m");
969         return 0;
970     }
971     ifr.ifr_flags |= IFF_UP;
972     if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
973         syslog(LOG_ERR, "Couldn't mark interface up (set): %m");
974         return 0;
975     }
976     if_is_up = 1;
977     return 1;
978 }
979
980 /*
981  * sifdown - Config the interface down and disable IP.
982  */
983 int
984 sifdown(u)
985     int u;
986 {
987     struct ifreq ifr;
988
989     if (ipmuxid < 0)
990         return 1;
991     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
992     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
993         syslog(LOG_ERR, "Couldn't mark interface down (get): %m");
994         return 0;
995     }
996     ifr.ifr_flags &= ~IFF_UP;
997     if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
998         syslog(LOG_ERR, "Couldn't mark interface down (set): %m");
999         return 0;
1000     }
1001     if_is_up = 0;
1002     return 1;
1003 }
1004
1005 /*
1006  * sifnpmode - Set the mode for handling packets for a given NP.
1007  */
1008 int
1009 sifnpmode(u, proto, mode)
1010     int u;
1011     int proto;
1012     enum NPmode mode;
1013 {
1014     int npi[2];
1015
1016     npi[0] = proto;
1017     npi[1] = (int) mode;
1018     if (strioctl(pppfd, PPPIO_NPMODE, &npi, 2 * sizeof(int), 0) < 0) {
1019         syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
1020         return 0;
1021     }
1022     return 1;
1023 }
1024
1025 #define INET_ADDR(x)    (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
1026
1027 /*
1028  * sifaddr - Config the interface IP addresses and netmask.
1029  */
1030 int
1031 sifaddr(u, o, h, m)
1032     int u;
1033     u_int32_t o, h, m;
1034 {
1035     struct ifreq ifr;
1036
1037     memset(&ifr, 0, sizeof(ifr));
1038     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1039     ifr.ifr_addr.sa_family = AF_INET;
1040     INET_ADDR(ifr.ifr_addr) = o;
1041     if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
1042         syslog(LOG_ERR, "Couldn't set local IP address: %m");
1043     }
1044     ifr.ifr_dstaddr.sa_family = AF_INET;
1045     INET_ADDR(ifr.ifr_dstaddr) = h;
1046     if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
1047         syslog(LOG_ERR, "Couldn't set remote IP address: %m");
1048     }
1049     ifr.ifr_addr.sa_family = AF_INET;
1050     INET_ADDR(ifr.ifr_addr) = m;
1051     if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) {
1052         syslog(LOG_ERR, "Couldn't set IP netmask: %m");
1053     }
1054     ifr.ifr_metric = link_mtu;
1055     if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
1056         syslog(LOG_ERR, "Couldn't set IP MTU: %m");
1057     }
1058
1059     return 1;
1060 }
1061
1062 /*
1063  * cifaddr - Clear the interface IP addresses, and delete routes
1064  * through the interface if possible.
1065  */
1066 int
1067 cifaddr(u, o, h)
1068     int u;
1069     u_int32_t o, h;
1070 {
1071 #if 0
1072     if (ipmuxid >= 0) {
1073         if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) {
1074             syslog(LOG_ERR, "Can't remove ppp interface unit: %m");
1075             return 0;
1076         }
1077         ipmuxid = -1;
1078     }
1079 #endif
1080     return 1;
1081 }
1082
1083 /*
1084  * sifdefaultroute - assign a default route through the address given.
1085  */
1086 int
1087 sifdefaultroute(u, g)
1088     int u;
1089     u_int32_t g;
1090 {
1091     struct rtentry rt;
1092
1093     rt.rt_dst.sa_family = AF_INET;
1094     INET_ADDR(rt.rt_dst) = 0;
1095     rt.rt_gateway.sa_family = AF_INET;
1096     INET_ADDR(rt.rt_gateway) = g;
1097     rt.rt_flags = RTF_GATEWAY;
1098
1099     if (ioctl(ipfd, SIOCADDRT, &rt) < 0) {
1100         syslog(LOG_ERR, "Can't add default route: %m");
1101         return 0;
1102     }
1103
1104     default_route_gateway = g;
1105     return 1;
1106 }
1107
1108 /*
1109  * cifdefaultroute - delete a default route through the address given.
1110  */
1111 int
1112 cifdefaultroute(u, g)
1113     int u;
1114     u_int32_t g;
1115 {
1116     struct rtentry rt;
1117
1118     rt.rt_dst.sa_family = AF_INET;
1119     INET_ADDR(rt.rt_dst) = 0;
1120     rt.rt_gateway.sa_family = AF_INET;
1121     INET_ADDR(rt.rt_gateway) = g;
1122     rt.rt_flags = RTF_GATEWAY;
1123
1124     if (ioctl(ipfd, SIOCDELRT, &rt) < 0) {
1125         syslog(LOG_ERR, "Can't delete default route: %m");
1126         return 0;
1127     }
1128
1129     default_route_gateway = 0;
1130     return 1;
1131 }
1132
1133 /*
1134  * sifproxyarp - Make a proxy ARP entry for the peer.
1135  */
1136 int
1137 sifproxyarp(unit, hisaddr)
1138     int unit;
1139     u_int32_t hisaddr;
1140 {
1141     struct arpreq arpreq;
1142
1143     memset(&arpreq, 0, sizeof(arpreq));
1144     if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
1145         return 0;
1146
1147     arpreq.arp_pa.sa_family = AF_INET;
1148     INET_ADDR(arpreq.arp_pa) = hisaddr;
1149     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1150     if (ioctl(ipfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
1151         syslog(LOG_ERR, "Couldn't set proxy ARP entry: %m");
1152         return 0;
1153     }
1154
1155     proxy_arp_addr = hisaddr;
1156     return 1;
1157 }
1158
1159 /*
1160  * cifproxyarp - Delete the proxy ARP entry for the peer.
1161  */
1162 int
1163 cifproxyarp(unit, hisaddr)
1164     int unit;
1165     u_int32_t hisaddr;
1166 {
1167     struct arpreq arpreq;
1168
1169     memset(&arpreq, 0, sizeof(arpreq));
1170     arpreq.arp_pa.sa_family = AF_INET;
1171     INET_ADDR(arpreq.arp_pa) = hisaddr;
1172     if (ioctl(ipfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1173         syslog(LOG_ERR, "Couldn't delete proxy ARP entry: %m");
1174         return 0;
1175     }
1176
1177     proxy_arp_addr = 0;
1178     return 1;
1179 }
1180
1181 /*
1182  * get_ether_addr - get the hardware address of an interface on the
1183  * the same subnet as ipaddr.
1184  */
1185 #define MAX_IFS         32
1186
1187 static int
1188 get_ether_addr(ipaddr, hwaddr)
1189     u_int32_t ipaddr;
1190     struct sockaddr *hwaddr;
1191 {
1192     struct ifreq *ifr, *ifend, ifreq;
1193     int nif;
1194     struct ifconf ifc;
1195     u_int32_t ina, mask;
1196
1197     /*
1198      * Scan through the system's network interfaces.
1199      */
1200 #ifdef SIOCGIFNUM
1201     if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
1202 #endif
1203         nif = MAX_IFS;
1204     ifc.ifc_len = nif * sizeof(struct ifreq);
1205     ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
1206     if (ifc.ifc_req == 0)
1207         return 0;
1208     if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
1209         syslog(LOG_WARNING, "Couldn't get system interface list: %m");
1210         return 0;
1211     }
1212     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1213     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1214         if (ifr->ifr_addr.sa_family != AF_INET)
1215             continue;
1216         /*
1217          * Check that the interface is up, and not point-to-point or loopback.
1218          */
1219         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1220         if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
1221             continue;
1222         if ((ifreq.ifr_flags &
1223              (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1224             != (IFF_UP|IFF_BROADCAST))
1225             continue;
1226         /*
1227          * Get its netmask and check that it's on the right subnet.
1228          */
1229         if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
1230             continue;
1231         ina = INET_ADDR(ifr->ifr_addr);
1232         mask = INET_ADDR(ifreq.ifr_addr);
1233         if ((ipaddr & mask) == (ina & mask))
1234             break;
1235     }
1236
1237     if (ifr >= ifend) {
1238         syslog(LOG_WARNING, "No suitable interface found for proxy ARP");
1239         return 0;
1240     }
1241
1242     syslog(LOG_INFO, "found interface %s for proxy ARP", ifr->ifr_name);
1243     if (!get_hw_addr(ifr->ifr_name, hwaddr)) {
1244         syslog(LOG_ERR, "Couldn't get hardware address for %s", ifr->ifr_name);
1245         return 0;
1246     }
1247
1248     return 1;
1249 }
1250
1251 /*
1252  * get_hw_addr - obtain the hardware address for a named interface.
1253  */
1254 static int
1255 get_hw_addr(name, hwaddr)
1256     char *name;
1257     struct sockaddr *hwaddr;
1258 {
1259     char *p, *q;
1260     int unit, iffd, adrlen;
1261     unsigned char *adrp;
1262     char ifdev[24];
1263     struct {
1264         union DL_primitives prim;
1265         char space[64];
1266     } reply;
1267
1268     /*
1269      * We have to open the device and ask it for its hardware address.
1270      * First split apart the device name and unit.
1271      */
1272     strcpy(ifdev, "/dev/");
1273     q = ifdev + 5;              /* strlen("/dev/") */
1274     while (*name != 0 && !isdigit(*name))
1275         *q++ = *name++;
1276     *q = 0;
1277     unit = atoi(name);
1278
1279     /*
1280      * Open the device and do a DLPI attach and phys_addr_req.
1281      */
1282     iffd = open(ifdev, O_RDWR);
1283     if (iffd < 0) {
1284         syslog(LOG_ERR, "Can't open %s: %m", ifdev);
1285         return 0;
1286     }
1287     if (dlpi_attach(iffd, unit) < 0
1288         || dlpi_get_reply(iffd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0
1289         || dlpi_info_req(iffd) < 0
1290         || dlpi_get_reply(iffd, &reply.prim, DL_INFO_ACK, sizeof(reply)) < 0) {
1291         close(iffd);
1292         return 0;
1293     }
1294
1295     adrlen = reply.prim.info_ack.dl_addr_length;
1296     adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset;
1297 #if DL_CURRENT_VERSION >= 2
1298     if (reply.prim.info_ack.dl_sap_length < 0)
1299         adrlen += reply.prim.info_ack.dl_sap_length;
1300     else
1301         adrp += reply.prim.info_ack.dl_sap_length;
1302 #endif
1303     hwaddr->sa_family = AF_UNSPEC;
1304     memcpy(hwaddr->sa_data, adrp, adrlen);
1305
1306     return 1;
1307 }
1308
1309 static int
1310 dlpi_attach(fd, ppa)
1311     int fd, ppa;
1312 {
1313     dl_attach_req_t req;
1314     struct strbuf buf;
1315
1316     req.dl_primitive = DL_ATTACH_REQ;
1317     req.dl_ppa = ppa;
1318     buf.len = sizeof(req);
1319     buf.buf = (void *) &req;
1320     return putmsg(fd, &buf, NULL, RS_HIPRI);
1321 }
1322
1323 static int
1324 dlpi_info_req(fd)
1325     int fd;
1326 {
1327     dl_info_req_t req;
1328     struct strbuf buf;
1329
1330     req.dl_primitive = DL_INFO_REQ;
1331     buf.len = sizeof(req);
1332     buf.buf = (void *) &req;
1333     return putmsg(fd, &buf, NULL, RS_HIPRI);
1334 }
1335
1336 static int
1337 dlpi_get_reply(fd, reply, expected_prim, maxlen)
1338     union DL_primitives *reply;
1339     int fd, expected_prim, maxlen;
1340 {
1341     struct strbuf buf;
1342     int flags, n;
1343     struct pollfd pfd;
1344
1345     /*
1346      * Use poll to wait for a message with a timeout.
1347      */
1348     pfd.fd = fd;
1349     pfd.events = POLLIN | POLLPRI;
1350     do {
1351         n = poll(&pfd, 1, 1000);
1352     } while (n == -1 && errno == EINTR);
1353     if (n <= 0)
1354         return -1;
1355
1356     /*
1357      * Get the reply.
1358      */
1359     buf.maxlen = maxlen;
1360     buf.buf = (void *) reply;
1361     flags = 0;
1362     if (getmsg(fd, &buf, NULL, &flags) < 0)
1363         return -1;
1364
1365     if (buf.len < sizeof(ulong)) {
1366         if (debug)
1367             syslog(LOG_DEBUG, "dlpi response short (len=%d)\n", buf.len);
1368         return -1;
1369     }
1370
1371     if (reply->dl_primitive == expected_prim)
1372         return 0;
1373
1374     if (debug) {
1375         if (reply->dl_primitive == DL_ERROR_ACK) {
1376             syslog(LOG_DEBUG, "dlpi error %d (unix errno %d) for prim %x\n",
1377                    reply->error_ack.dl_errno, reply->error_ack.dl_unix_errno,
1378                    reply->error_ack.dl_error_primitive);
1379         } else {
1380             syslog(LOG_DEBUG, "dlpi unexpected response prim %x\n",
1381                    reply->dl_primitive);
1382         }
1383     }
1384
1385     return -1;
1386 }
1387
1388 /*
1389  * Return user specified netmask, modified by any mask we might determine
1390  * for address `addr' (in network byte order).
1391  * Here we scan through the system's list of interfaces, looking for
1392  * any non-point-to-point interfaces which might appear to be on the same
1393  * network as `addr'.  If we find any, we OR in their netmask to the
1394  * user-specified netmask.
1395  */
1396 u_int32_t
1397 GetMask(addr)
1398     u_int32_t addr;
1399 {
1400     u_int32_t mask, nmask, ina;
1401     struct ifreq *ifr, *ifend, ifreq;
1402     int nif;
1403     struct ifconf ifc;
1404
1405     addr = ntohl(addr);
1406     if (IN_CLASSA(addr))        /* determine network mask for address class */
1407         nmask = IN_CLASSA_NET;
1408     else if (IN_CLASSB(addr))
1409         nmask = IN_CLASSB_NET;
1410     else
1411         nmask = IN_CLASSC_NET;
1412     /* class D nets are disallowed by bad_ip_adrs */
1413     mask = netmask | htonl(nmask);
1414
1415     /*
1416      * Scan through the system's network interfaces.
1417      */
1418 #ifdef SIOCGIFNUM
1419     if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
1420 #endif
1421         nif = MAX_IFS;
1422     ifc.ifc_len = nif * sizeof(struct ifreq);
1423     ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
1424     if (ifc.ifc_req == 0)
1425         return mask;
1426     if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
1427         syslog(LOG_WARNING, "Couldn't get system interface list: %m");
1428         return mask;
1429     }
1430     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1431     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
1432         /*
1433          * Check the interface's internet address.
1434          */
1435         if (ifr->ifr_addr.sa_family != AF_INET)
1436             continue;
1437         ina = INET_ADDR(ifr->ifr_addr);
1438         if ((ntohl(ina) & nmask) != (addr & nmask))
1439             continue;
1440         /*
1441          * Check that the interface is up, and not point-to-point or loopback.
1442          */
1443         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1444         if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
1445             continue;
1446         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1447             != IFF_UP)
1448             continue;
1449         /*
1450          * Get its netmask and OR it into our mask.
1451          */
1452         if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
1453             continue;
1454         mask |= INET_ADDR(ifreq.ifr_addr);
1455     }
1456
1457     return mask;
1458 }
1459
1460 /*
1461  * logwtmp - write an accounting record to the /var/adm/wtmp file.
1462  */
1463 int
1464 logwtmp(line, name, host)
1465     char *line, *name, *host;
1466 {
1467     static struct utmpx utmpx;
1468
1469     if (name[0] != 0) {
1470         /* logging in */
1471         strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user));
1472         strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id));
1473         strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
1474         utmpx.ut_pid = getpid();
1475         utmpx.ut_type = USER_PROCESS;
1476     } else {
1477         utmpx.ut_type = DEAD_PROCESS;
1478     }
1479     gettimeofday(&utmpx.ut_tv, NULL);
1480     updwtmpx("/var/adm/wtmpx", &utmpx);
1481     return 0;
1482 }
1483
1484 /*
1485  * gethostid - return the serial number of this machine.
1486  */
1487 int
1488 gethostid()
1489 {
1490     char buf[32];
1491
1492     if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) < 0) {
1493         syslog(LOG_ERR, "sysinfo: %m");
1494         return 0;
1495     }
1496     return (int) strtoul(buf, NULL, 16);
1497 }
1498
1499 static int
1500 strioctl(fd, cmd, ptr, ilen, olen)
1501     int fd, cmd, ilen, olen;
1502     void *ptr;
1503 {
1504     struct strioctl str;
1505
1506     str.ic_cmd = cmd;
1507     str.ic_timout = 0;
1508     str.ic_len = ilen;
1509     str.ic_dp = ptr;
1510     if (ioctl(fd, I_STR, &str) == -1)
1511         return -1;
1512     if (str.ic_len != olen)
1513         syslog(LOG_DEBUG, "strioctl: expected %d bytes, got %d for cmd %x\n",
1514                olen, str.ic_len, cmd);
1515     return 0;
1516 }
1517
1518 /*
1519  * lock - create a lock file for the named lock device
1520  */
1521
1522 #define LOCK_PREFIX     "/var/spool/locks/LK."
1523 static char lock_file[40];      /* name of lock file created */
1524
1525 int
1526 lock(dev)
1527     char *dev;
1528 {
1529     int n, fd, pid;
1530     struct stat sbuf;
1531     char ascii_pid[12];
1532
1533     if (stat(dev, &sbuf) < 0) {
1534         syslog(LOG_ERR, "Can't get device number for %s: %m", dev);
1535         return -1;
1536     }
1537     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
1538         syslog(LOG_ERR, "Can't lock %s: not a character device", dev);
1539         return -1;
1540     }
1541     sprintf(lock_file, "%s%03d.%03d.%03d", LOCK_PREFIX, major(sbuf.st_dev),
1542             major(sbuf.st_rdev), minor(sbuf.st_rdev));
1543
1544     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1545         if (errno == EEXIST
1546             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1547             /* Read the lock file to find out who has the device locked */
1548             n = read(fd, ascii_pid, 11);
1549             if (n <= 0) {
1550                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1551                 close(fd);
1552             } else {
1553                 ascii_pid[n] = 0;
1554                 pid = atoi(ascii_pid);
1555                 if (pid > 0 && kill(pid, 0) == -1 && errno == ESRCH) {
1556                     /* pid no longer exists - remove the lock file */
1557                     if (unlink(lock_file) == 0) {
1558                         close(fd);
1559                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1560                                dev, pid);
1561                         continue;
1562                     } else
1563                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1564                                dev);
1565                 } else
1566                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1567                            dev, pid);
1568             }
1569             close(fd);
1570         } else
1571             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1572         lock_file[0] = 0;
1573         return -1;
1574     }
1575
1576     sprintf(ascii_pid, "%10d\n", getpid());
1577     write(fd, ascii_pid, 11);
1578
1579     close(fd);
1580     return 1;
1581 }
1582
1583 /*
1584  * unlock - remove our lockfile
1585  */
1586 void
1587 unlock()
1588 {
1589     if (lock_file[0]) {
1590         unlink(lock_file);
1591         lock_file[0] = 0;
1592     }
1593 }