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