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