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