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