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