xref: /openbsd/usr.sbin/pppd/sys-bsd.c (revision 097a140d)
1 /*	$OpenBSD: sys-bsd.c,v 1.30 2020/12/29 19:45:28 benno Exp $	*/
2 
3 /*
4  * sys-bsd.c - System-dependent procedures for setting up
5  * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
6  *
7  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. The name "Carnegie Mellon University" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For permission or any legal
24  *    details, please contact
25  *      Office of Technology Transfer
26  *      Carnegie Mellon University
27  *      5000 Forbes Avenue
28  *      Pittsburgh, PA  15213-3890
29  *      (412) 268-4387, fax: (412) 268-7395
30  *      tech-transfer@andrew.cmu.edu
31  *
32  * 4. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by Computing Services
35  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36  *
37  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44  *
45  * Copyright (c) 1989-2002 Paul Mackerras. All rights reserved.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  *
51  * 1. Redistributions of source code must retain the above copyright
52  *    notice, this list of conditions and the following disclaimer.
53  *
54  * 2. Redistributions in binary form must reproduce the above copyright
55  *    notice, this list of conditions and the following disclaimer in
56  *    the documentation and/or other materials provided with the
57  *    distribution.
58  *
59  * 3. The name(s) of the authors of this software must not be used to
60  *    endorse or promote products derived from this software without
61  *    prior written permission.
62  *
63  * 4. Redistributions of any form whatsoever must retain the following
64  *    acknowledgment:
65  *    "This product includes software developed by Paul Mackerras
66  *     <paulus@samba.org>".
67  *
68  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
69  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
70  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
71  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
72  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
73  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
74  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
75  */
76 
77 /*
78  * TODO:
79  */
80 
81 #include <stdio.h>
82 #include <syslog.h>
83 #include <string.h>
84 #include <stdlib.h>
85 #include <unistd.h>
86 #include <err.h>
87 #include <errno.h>
88 #include <fcntl.h>
89 #include <termios.h>
90 #include <signal.h>
91 #include <util.h>
92 #include <sys/ioctl.h>
93 #include <sys/types.h>
94 #include <sys/socket.h>
95 #include <sys/time.h>
96 #include <sys/stat.h>
97 #include <ifaddrs.h>
98 
99 #ifdef PPP_FILTER
100 #include <net/bpf.h>
101 #endif
102 #include <net/if.h>
103 #include <net/ppp_defs.h>
104 #include <net/if_ppp.h>
105 #include <net/route.h>
106 #include <net/if_dl.h>
107 #include <netinet/in.h>
108 
109 #if RTM_VERSION >= 3
110 #include <sys/param.h>
111 #if defined(NetBSD) && (NetBSD >= 199703)
112 #include <netinet/if_inarp.h>
113 #else	/* NetBSD 1.2D or later */
114 #if defined(__FreeBSD__) || defined(__OpenBSD__)
115 #include <netinet/if_ether.h>
116 #else
117 #include <net/if_ether.h>
118 #endif
119 #endif
120 #endif
121 
122 #include "pppd.h"
123 #include "fsm.h"
124 #include "ipcp.h"
125 
126 #define ok_error(num) ((num)==EIO)
127 
128 static int initdisc = -1;	/* Initial TTY discipline for ppp_fd */
129 static int initfdflags = -1;	/* Initial file descriptor flags for ppp_fd */
130 static int ppp_fd = -1;		/* fd which is set to PPP discipline */
131 static int rtm_seq;
132 
133 static int restore_term;	/* 1 => we've munged the terminal */
134 static struct termios inittermios; /* Initial TTY termios */
135 static struct winsize wsinfo;	/* Initial window size info */
136 
137 static char *lock_file;		/* name of lock file created */
138 
139 static int loop_slave = -1;
140 static int loop_master;
141 static char loop_name[20];
142 
143 static unsigned char inbuf[512]; /* buffer for chars read from loopback */
144 
145 static int sockfd;		/* socket for doing interface ioctls */
146 
147 static int if_is_up;		/* the interface is currently up */
148 static u_int32_t ifaddrs[2];	/* local and remote addresses we set */
149 static u_int32_t default_route_gateway;	/* gateway addr for default route */
150 static u_int32_t proxy_arp_addr;	/* remote addr for proxy arp */
151 
152 /* Prototypes for procedures local to this file. */
153 static int dodefaultroute(u_int32_t, int);
154 static int get_ether_addr(u_int32_t, struct sockaddr_dl *);
155 
156 
157 /*
158  * sys_init - System-dependent initialization.
159  */
160 void
161 sys_init()
162 {
163     /* Get an internet socket for doing socket ioctl's on. */
164     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
165 	syslog(LOG_ERR, "Couldn't create IP socket: %m");
166 	die(1);
167     }
168 }
169 
170 /*
171  * sys_cleanup - restore any system state we modified before exiting:
172  * mark the interface down, delete default route and/or proxy arp entry.
173  * This should call die() because it's called from die().
174  */
175 void
176 sys_cleanup()
177 {
178     struct ifreq ifr;
179 
180     if (if_is_up) {
181 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
182 	if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0
183 	    && ((ifr.ifr_flags & IFF_UP) != 0)) {
184 	    ifr.ifr_flags &= ~IFF_UP;
185 	    ioctl(sockfd, SIOCSIFFLAGS, &ifr);
186 	}
187     }
188     if (ifaddrs[0] != 0)
189 	cifaddr(0, ifaddrs[0], ifaddrs[1]);
190     if (default_route_gateway)
191 	cifdefaultroute(0, 0, default_route_gateway);
192     if (proxy_arp_addr)
193 	cifproxyarp(0, proxy_arp_addr);
194 }
195 
196 /*
197  * sys_close - Clean up in a child process before execing.
198  */
199 void
200 sys_close()
201 {
202     close(sockfd);
203     if (loop_slave >= 0) {
204 	close(loop_slave);
205 	close(loop_master);
206     }
207 }
208 
209 /*
210  * sys_check_options - check the options that the user specified
211  */
212 void
213 sys_check_options()
214 {
215 }
216 
217 /*
218  * ppp_available - check whether the system has any ppp interfaces
219  * (in fact we check whether we can do an ioctl on ppp0).
220  */
221 int
222 ppp_available()
223 {
224     int s, ok;
225     struct ifreq ifr;
226     extern char *no_ppp_msg;
227 
228     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
229 	return 1;		/* can't tell */
230 
231     strlcpy(ifr.ifr_name, "ppp0", sizeof(ifr.ifr_name));
232     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) == 0;
233     close(s);
234 
235     no_ppp_msg = "\
236 PPP device not available. Make sure the device is created with\n\
237 ifconfig and that the kernel supports PPP. See ifconfig(8) and ppp(4).";
238     return ok;
239 }
240 
241 /*
242  * establish_ppp - Turn the serial port into a ppp interface.
243  */
244 void
245 establish_ppp(fd)
246     int fd;
247 {
248     int pppdisc = PPPDISC;
249     int x;
250 
251     if (demand) {
252 	/*
253 	 * Demand mode - prime the old ppp device to relinquish the unit.
254 	 */
255 	if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) == -1) {
256 	    syslog(LOG_ERR, "ioctl(transfer ppp unit): %m");
257 	    die(1);
258 	}
259     }
260 
261     /*
262      * Save the old line discipline of fd, and set it to PPP.
263      */
264     if (ioctl(fd, TIOCGETD, &initdisc) == -1) {
265 	syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
266 	die(1);
267     }
268     if (ioctl(fd, TIOCSETD, &pppdisc) == -1) {
269 	syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
270 	die(1);
271     }
272 
273     if (!demand) {
274 	/*
275 	 * Find out which interface we were given.
276 	 */
277 	if (ioctl(fd, PPPIOCGUNIT, &ifunit) == -1) {
278 	    syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
279 	    die(1);
280 	}
281     } else {
282 	/*
283 	 * Check that we got the same unit again.
284 	 */
285 	if (ioctl(fd, PPPIOCGUNIT, &x) == -1) {
286 	    syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
287 	    die(1);
288 	}
289 	if (x != ifunit) {
290 	    syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d",
291 		   ifunit, x);
292 	    die(1);
293 	}
294 	x = TTYDISC;
295 	ioctl(loop_slave, TIOCSETD, &x);
296     }
297 
298     ppp_fd = fd;
299 
300     /*
301      * Enable debug in the driver if requested.
302      */
303     if (kdebugflag) {
304 	if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == -1) {
305 	    syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
306 	} else {
307 	    x |= (kdebugflag & 0xFF) * SC_DEBUG;
308 	    if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) == -1)
309 		syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
310 	}
311     }
312 
313     /*
314      * Set device for non-blocking reads.
315      */
316     if ((initfdflags = fcntl(fd, F_GETFL)) == -1
317 	|| fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
318 	syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
319     }
320 }
321 
322 /*
323  * restore_loop - reattach the ppp unit to the loopback.
324  */
325 void
326 restore_loop()
327 {
328     int x;
329 
330     /*
331      * Transfer the ppp interface back to the loopback.
332      */
333     if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) == -1) {
334 	syslog(LOG_ERR, "ioctl(transfer ppp unit): %m");
335 	die(1);
336     }
337     x = PPPDISC;
338     if (ioctl(loop_slave, TIOCSETD, &x) == -1) {
339 	syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
340 	die(1);
341     }
342 
343     /*
344      * Check that we got the same unit again.
345      */
346     if (ioctl(loop_slave, PPPIOCGUNIT, &x) == -1) {
347 	syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
348 	die(1);
349     }
350     if (x != ifunit) {
351 	syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d",
352 	       ifunit, x);
353 	die(1);
354     }
355     ppp_fd = loop_slave;
356 }
357 
358 /*
359  * disestablish_ppp - Restore the serial port to normal operation.
360  * This shouldn't call die() because it's called from die().
361  */
362 void
363 disestablish_ppp(fd)
364     int fd;
365 {
366     /* Reset non-blocking mode on fd. */
367     if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) == -1)
368 	syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
369     initfdflags = -1;
370 
371     /* Restore old line discipline. */
372     if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) == -1)
373 	syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
374     initdisc = -1;
375 
376     if (fd == ppp_fd)
377 	ppp_fd = -1;
378 }
379 
380 /*
381  * Check whether the link seems not to be 8-bit clean.
382  */
383 void
384 clean_check()
385 {
386     int x;
387     char *s;
388 
389     if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
390 	s = NULL;
391 	switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
392 	case SC_RCV_B7_0:
393 	    s = "bit 7 set to 1";
394 	    break;
395 	case SC_RCV_B7_1:
396 	    s = "bit 7 set to 0";
397 	    break;
398 	case SC_RCV_EVNP:
399 	    s = "odd parity";
400 	    break;
401 	case SC_RCV_ODDP:
402 	    s = "even parity";
403 	    break;
404 	}
405 	if (s != NULL) {
406 	    syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
407 	    syslog(LOG_WARNING, "All received characters had %s", s);
408 	}
409     }
410 }
411 
412 /*
413  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
414  * at the requested speed, etc.  If `local' is true, set CLOCAL
415  * regardless of whether the modem option was specified.
416  *
417  * For *BSD, we assume that speed_t values numerically equal bits/second.
418  */
419 void
420 set_up_tty(fd, local)
421     int fd, local;
422 {
423     struct termios tios;
424 
425     if (tcgetattr(fd, &tios) == -1) {
426 	syslog(LOG_ERR, "tcgetattr: %m");
427 	die(1);
428     }
429 
430     if (!restore_term) {
431 	inittermios = tios;
432 	ioctl(fd, TIOCGWINSZ, &wsinfo);
433     }
434 
435     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
436     if (crtscts > 0 && modem)
437 	tios.c_cflag |= CRTSCTS;
438     else if (crtscts < 0)
439 	tios.c_cflag &= ~CRTSCTS;
440 
441     tios.c_cflag |= CS8 | CREAD | HUPCL;
442     if (local || !modem)
443 	tios.c_cflag |= CLOCAL;
444     tios.c_iflag = IGNBRK | IGNPAR;
445     tios.c_oflag = 0;
446     tios.c_lflag = 0;
447     tios.c_cc[VMIN] = 1;
448     tios.c_cc[VTIME] = 0;
449 
450     if (crtscts == -2) {
451 	tios.c_iflag |= IXON | IXOFF;
452 	tios.c_cc[VSTOP] = 0x13;	/* DC3 = XOFF = ^S */
453 	tios.c_cc[VSTART] = 0x11;	/* DC1 = XON  = ^Q */
454     }
455 
456     if (inspeed) {
457 	cfsetospeed(&tios, inspeed);
458 	cfsetispeed(&tios, inspeed);
459     } else {
460 	inspeed = cfgetospeed(&tios);
461 	/*
462 	 * We can't proceed if the serial port speed is 0,
463 	 * since that implies that the serial port is disabled.
464 	 */
465 	if (inspeed == 0) {
466 	    syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
467 		   devnam);
468 	    die(1);
469 	}
470     }
471     baud_rate = inspeed;
472 
473     if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) {
474 	syslog(LOG_ERR, "tcsetattr: %m");
475 	die(1);
476     }
477 
478     restore_term = 1;
479 }
480 
481 /*
482  * restore_tty - restore the terminal to the saved settings.
483  */
484 void
485 restore_tty(fd)
486     int fd;
487 {
488     if (restore_term) {
489 	if (!default_device) {
490 	    /*
491 	     * Turn off echoing, because otherwise we can get into
492 	     * a loop with the tty and the modem echoing to each other.
493 	     * We presume we are the sole user of this tty device, so
494 	     * when we close it, it will revert to its defaults anyway.
495 	     */
496 	    inittermios.c_lflag &= ~(ECHO | ECHONL);
497 	}
498 	if (tcsetattr(fd, TCSAFLUSH, &inittermios) == -1)
499 	    if (errno != ENXIO)
500 		syslog(LOG_WARNING, "tcsetattr: %m");
501 	ioctl(fd, TIOCSWINSZ, &wsinfo);
502 	restore_term = 0;
503     }
504 }
505 
506 /*
507  * setdtr - control the DTR line on the serial port.
508  * This is called from die(), so it shouldn't call die().
509  */
510 void
511 setdtr(fd, on)
512 int fd, on;
513 {
514     int modembits = TIOCM_DTR;
515 
516     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
517 }
518 
519 
520 /*
521  * open_ppp_loopback - open the device we use for getting
522  * packets in demand mode, and connect it to a ppp interface.
523  * Here we use a pty.
524  */
525 void
526 open_ppp_loopback()
527 {
528     int flags;
529     struct termios tios;
530     int pppdisc = PPPDISC;
531 
532     if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) == -1) {
533 	syslog(LOG_ERR, "No free pty for loopback");
534 	die(1);
535     }
536     SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
537 
538     if (tcgetattr(loop_slave, &tios) == 0) {
539 	tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
540 	tios.c_cflag |= CS8 | CREAD;
541 	tios.c_iflag = IGNPAR;
542 	tios.c_oflag = 0;
543 	tios.c_lflag = 0;
544 	if (tcsetattr(loop_slave, TCSAFLUSH, &tios) == -1)
545 	    syslog(LOG_WARNING, "couldn't set attributes on loopback: %m");
546     }
547 
548     if ((flags = fcntl(loop_master, F_GETFL)) != -1)
549 	if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
550 	    syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m");
551 
552     ppp_fd = loop_slave;
553     if (ioctl(ppp_fd, TIOCSETD, &pppdisc) == -1) {
554 	syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
555 	die(1);
556     }
557 
558     /*
559      * Find out which interface we were given.
560      */
561     if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) == -1) {
562 	syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
563 	die(1);
564     }
565 
566     /*
567      * Enable debug in the driver if requested.
568      */
569     if (kdebugflag) {
570 	if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &flags) == -1) {
571 	    syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
572 	} else {
573 	    flags |= (kdebugflag & 0xFF) * SC_DEBUG;
574 	    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &flags) == -1)
575 		syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
576 	}
577     }
578 
579 }
580 
581 
582 /*
583  * output - Output PPP packet.
584  */
585 void
586 output(unit, p, len)
587     int unit;
588     u_char *p;
589     int len;
590 {
591     if (debug)
592 	log_packet(p, len, "sent ", LOG_DEBUG);
593 
594     if (write(ttyfd, p, len) == -1) {
595 	if (errno != EIO)
596 	    syslog(LOG_ERR, "write: %m");
597     }
598 }
599 
600 
601 /*
602  * wait_input - wait until there is data available on ttyfd,
603  * for the length of time specified by *timo (indefinite
604  * if timo is NULL).
605  */
606 void
607 wait_input(timo)
608     struct timeval *timo;
609 {
610     fd_set *fdsp = NULL;
611     int fdsn;
612     int n;
613 
614     fdsn = howmany(ttyfd+1, NFDBITS) * sizeof(fd_mask);
615     if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
616 	err(1, "malloc");
617     memset(fdsp, 0, fdsn);
618     FD_SET(ttyfd, fdsp);
619 
620     n = select(ttyfd+1, fdsp, NULL, fdsp, timo);
621     if (n == -1 && errno != EINTR) {
622 	syslog(LOG_ERR, "select: %m");
623 	free(fdsp);
624 	die(1);
625     }
626     free(fdsp);
627 }
628 
629 
630 /*
631  * wait_loop_output - wait until there is data available on the
632  * loopback, for the length of time specified by *timo (indefinite
633  * if timo is NULL).
634  */
635 void
636 wait_loop_output(timo)
637     struct timeval *timo;
638 {
639     fd_set *fdsp = NULL;
640     int fdsn;
641     int n;
642 
643     fdsn = howmany(loop_master+1, NFDBITS) * sizeof(fd_mask);
644     if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
645 	err(1, "malloc");
646     memset(fdsp, 0, fdsn);
647     FD_SET(loop_master, fdsp);
648 
649     n = select(loop_master + 1, fdsp, NULL, fdsp, timo);
650     if (n == -1 && errno != EINTR) {
651 	syslog(LOG_ERR, "select: %m");
652 	free(fdsp);
653 	die(1);
654     }
655     free(fdsp);
656 }
657 
658 
659 /*
660  * wait_time - wait for a given length of time or until a
661  * signal is received.
662  */
663 void
664 wait_time(timo)
665     struct timeval *timo;
666 {
667     int n;
668 
669     n = select(0, NULL, NULL, NULL, timo);
670     if (n == -1 && errno != EINTR) {
671 	syslog(LOG_ERR, "select: %m");
672 	die(1);
673     }
674 }
675 
676 
677 /*
678  * read_packet - get a PPP packet from the serial device.
679  */
680 int
681 read_packet(buf)
682     u_char *buf;
683 {
684     int len;
685 
686     if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) == -1) {
687 	if (errno == EWOULDBLOCK || errno == EINTR)
688 	    return -1;
689 	syslog(LOG_ERR, "read: %m");
690 	die(1);
691     }
692     return len;
693 }
694 
695 
696 /*
697  * get_loop_output - read characters from the loopback, form them
698  * into frames, and detect when we want to bring the real link up.
699  * Return value is 1 if we need to bring up the link, 0 otherwise.
700  */
701 int
702 get_loop_output()
703 {
704     int rv = 0;
705     int n;
706 
707     while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) {
708 	if (loop_chars(inbuf, n))
709 	    rv = 1;
710     }
711 
712     if (n == 0) {
713 	syslog(LOG_ERR, "eof on loopback");
714 	die(1);
715     } else if (errno != EWOULDBLOCK){
716 	syslog(LOG_ERR, "read from loopback: %m");
717 	die(1);
718     }
719 
720     return rv;
721 }
722 
723 
724 /*
725  * ppp_send_config - configure the transmit characteristics of
726  * the ppp interface.
727  */
728 void
729 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
730     int unit, mtu;
731     u_int32_t asyncmap;
732     int pcomp, accomp;
733 {
734     u_int x;
735     struct ifreq ifr;
736 
737     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
738     ifr.ifr_mtu = mtu;
739     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) == -1) {
740 	syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
741 	quit();
742     }
743 
744     if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) == -1) {
745 	syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
746 	quit();
747     }
748 
749     if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == -1) {
750 	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
751 	quit();
752     }
753     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
754     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
755     if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) == -1) {
756 	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
757 	quit();
758     }
759 }
760 
761 
762 /*
763  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
764  */
765 void
766 ppp_set_xaccm(unit, accm)
767     int unit;
768     ext_accm accm;
769 {
770     if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) == -1 && errno != ENOTTY)
771 	syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
772 }
773 
774 
775 /*
776  * ppp_recv_config - configure the receive-side characteristics of
777  * the ppp interface.
778  */
779 void
780 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
781     int unit, mru;
782     u_int32_t asyncmap;
783     int pcomp, accomp;
784 {
785     int x;
786 
787     if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) == -1) {
788 	syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
789 	quit();
790     }
791     if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) == -1) {
792 	syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
793 	quit();
794     }
795     if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == -1) {
796 	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
797 	quit();
798     }
799     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
800     if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) == -1) {
801 	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
802 	quit();
803     }
804 }
805 
806 /*
807  * ccp_test - ask kernel whether a given compression method
808  * is acceptable for use.  Returns 1 if the method and parameters
809  * are OK, 0 if the method is known but the parameters are not OK
810  * (e.g. code size should be reduced), or -1 if the method is unknown.
811  */
812 int
813 ccp_test(unit, opt_ptr, opt_len, for_transmit)
814     int unit, opt_len, for_transmit;
815     u_char *opt_ptr;
816 {
817     struct ppp_option_data data;
818 
819     data.ptr = opt_ptr;
820     data.length = opt_len;
821     data.transmit = for_transmit;
822     if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
823 	return 1;
824     return (errno == ENOBUFS)? 0: -1;
825 }
826 
827 /*
828  * ccp_flags_set - inform kernel about the current state of CCP.
829  */
830 void
831 ccp_flags_set(unit, isopen, isup)
832     int unit, isopen, isup;
833 {
834     int x;
835 
836     if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == -1) {
837 	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
838 	return;
839     }
840     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
841     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
842     if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) == -1)
843 	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
844 }
845 
846 /*
847  * ccp_fatal_error - returns 1 if decompression was disabled as a
848  * result of an error detected after decompression of a packet,
849  * 0 otherwise.  This is necessary because of patent nonsense.
850  */
851 int
852 ccp_fatal_error(unit)
853     int unit;
854 {
855     int x;
856 
857     if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == -1) {
858 	syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
859 	return 0;
860     }
861     return x & SC_DC_FERROR;
862 }
863 
864 /*
865  * get_idle_time - return how long the link has been idle.
866  */
867 int
868 get_idle_time(u, ip)
869     int u;
870     struct ppp_idle *ip;
871 {
872     return ioctl(ppp_fd, PPPIOCGIDLE, ip) >= 0;
873 }
874 
875 
876 #ifdef PPP_FILTER
877 /*
878  * set_filters - transfer the pass and active filters to the kernel.
879  */
880 int
881 set_filters(pass, active)
882     struct bpf_program *pass, *active;
883 {
884     int ret = 1;
885 
886     if (pass->bf_len > 0) {
887 	if (ioctl(ppp_fd, PPPIOCSPASS, pass) == -1) {
888 	    syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m");
889 	    ret = 0;
890 	}
891     }
892     if (active->bf_len > 0) {
893 	if (ioctl(ppp_fd, PPPIOCSACTIVE, active) == -1) {
894 	    syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m");
895 	    ret = 0;
896 	}
897     }
898     return ret;
899 }
900 #endif
901 
902 /*
903  * sifvjcomp - config tcp header compression
904  */
905 int
906 sifvjcomp(u, vjcomp, cidcomp, maxcid)
907     int u, vjcomp, cidcomp, maxcid;
908 {
909     u_int x;
910 
911     if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == -1) {
912 	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
913 	return 0;
914     }
915     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
916     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
917     if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) == -1) {
918 	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
919 	return 0;
920     }
921     if (vjcomp && ioctl(ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) == -1) {
922 	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
923 	return 0;
924     }
925     return 1;
926 }
927 
928 /*
929  * sifup - Config the interface up and enable IP packets to pass.
930  */
931 int
932 sifup(u)
933     int u;
934 {
935     struct ifreq ifr;
936 
937     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
938     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) == -1) {
939 	syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
940 	return 0;
941     }
942     ifr.ifr_flags |= IFF_UP;
943     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) == -1) {
944 	syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
945 	return 0;
946     }
947     if_is_up = 1;
948     return 1;
949 }
950 
951 /*
952  * sifnpmode - Set the mode for handling packets for a given NP.
953  */
954 int
955 sifnpmode(u, proto, mode)
956     int u;
957     int proto;
958     enum NPmode mode;
959 {
960     struct npioctl npi;
961 
962     npi.protocol = proto;
963     npi.mode = mode;
964     if (ioctl(ppp_fd, PPPIOCSNPMODE, &npi) == -1) {
965 	syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
966 	return 0;
967     }
968     return 1;
969 }
970 
971 /*
972  * sifdown - Config the interface down and disable IP.
973  */
974 int
975 sifdown(u)
976     int u;
977 {
978     struct ifreq ifr;
979     int rv;
980     struct npioctl npi;
981 
982     rv = 1;
983     npi.protocol = PPP_IP;
984     npi.mode = NPMODE_ERROR;
985     ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi);
986     /* ignore errors, because ppp_fd might have been closed by now. */
987 
988     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
989     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) == -1) {
990 	syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
991 	rv = 0;
992     } else {
993 	ifr.ifr_flags &= ~IFF_UP;
994 	if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) == -1) {
995 	    syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
996 	    rv = 0;
997 	} else
998 	    if_is_up = 0;
999     }
1000     return rv;
1001 }
1002 
1003 /*
1004  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
1005  * if it exists.
1006  */
1007 #define SET_SA_FAMILY(addr, family)		\
1008     BZERO((char *) &(addr), sizeof(addr));	\
1009     addr.sa_family = (family); 			\
1010     addr.sa_len = sizeof(addr);
1011 
1012 /*
1013  * sifaddr - Config the interface IP addresses and netmask.
1014  */
1015 int
1016 sifaddr(u, o, h, m)
1017     int u;
1018     u_int32_t o, h, m;
1019 {
1020     struct ifaliasreq ifra;
1021     struct ifreq ifr;
1022     char s1[64], s2[64];
1023 
1024     strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
1025     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
1026     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
1027     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
1028     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
1029     if (m != 0) {
1030 	SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
1031 	((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
1032     } else
1033 	BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
1034     BZERO(&ifr, sizeof(ifr));
1035     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1036     if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) == -1) {
1037 	if (errno != EADDRNOTAVAIL)
1038 	    syslog(LOG_WARNING, "Couldn't remove interface address: %m");
1039     }
1040     if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) == -1) {
1041 	if (errno != EEXIST) {
1042 	    syslog(LOG_ERR, "Couldn't set interface address: %m");
1043 	    return 0;
1044 	}
1045 	strlcpy(s1, ip_ntoa(o), sizeof(s1));
1046 	strlcpy(s2, ip_ntoa(h), sizeof(s2));
1047 	syslog(LOG_WARNING,
1048 	       "Couldn't set interface address: "
1049 	       "Address %s or destination %s already exists", s1, s2);
1050     }
1051     ifaddrs[0] = o;
1052     ifaddrs[1] = h;
1053     return 1;
1054 }
1055 
1056 /*
1057  * cifaddr - Clear the interface IP addresses, and delete routes
1058  * through the interface if possible.
1059  */
1060 int
1061 cifaddr(u, o, h)
1062     int u;
1063     u_int32_t o, h;
1064 {
1065     struct ifaliasreq ifra;
1066 
1067     ifaddrs[0] = 0;
1068     strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
1069     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
1070     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
1071     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
1072     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
1073     BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
1074     if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) == -1) {
1075 	if (errno != EADDRNOTAVAIL)
1076 	    syslog(LOG_WARNING, "Couldn't delete interface address: %m");
1077 	return 0;
1078     }
1079     return 1;
1080 }
1081 
1082 /*
1083  * sifdefaultroute - assign a default route through the address given.
1084  */
1085 int
1086 sifdefaultroute(u, l, g)
1087     int u;
1088     u_int32_t l, g;
1089 {
1090     return dodefaultroute(g, 's');
1091 }
1092 
1093 /*
1094  * cifdefaultroute - delete a default route through the address given.
1095  */
1096 int
1097 cifdefaultroute(u, l, g)
1098     int u;
1099     u_int32_t l, g;
1100 {
1101     return dodefaultroute(g, 'c');
1102 }
1103 
1104 /*
1105  * dodefaultroute - talk to a routing socket to add/delete a default route.
1106  */
1107 static int
1108 dodefaultroute(g, cmd)
1109     u_int32_t g;
1110     int cmd;
1111 {
1112     int routes;
1113     struct {
1114 	struct rt_msghdr	hdr;
1115 	struct sockaddr_in	dst;
1116 	struct sockaddr_in	gway;
1117 	struct sockaddr_in	mask;
1118     } rtmsg;
1119 
1120     if ((routes = socket(AF_ROUTE, SOCK_RAW, AF_INET)) == -1) {
1121 	syslog(LOG_ERR, "Couldn't %s default route: socket: %m",
1122 	       cmd=='s'? "add": "delete");
1123 	return 0;
1124     }
1125 
1126     memset(&rtmsg, 0, sizeof(rtmsg));
1127     rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
1128     rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY;
1129     rtmsg.hdr.rtm_version = RTM_VERSION;
1130     rtmsg.hdr.rtm_seq = ++rtm_seq;
1131     rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
1132     rtmsg.dst.sin_len = sizeof(rtmsg.dst);
1133     rtmsg.dst.sin_family = AF_INET;
1134     rtmsg.gway.sin_len = sizeof(rtmsg.gway);
1135     rtmsg.gway.sin_family = AF_INET;
1136     rtmsg.gway.sin_addr.s_addr = g;
1137     rtmsg.mask.sin_len = sizeof(rtmsg.dst);
1138     rtmsg.mask.sin_family = AF_INET;
1139 
1140     rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
1141     if (write(routes, &rtmsg, sizeof(rtmsg)) == -1) {
1142 	syslog(LOG_ERR, "Couldn't %s default route: %m",
1143 	       cmd=='s'? "add": "delete");
1144 	close(routes);
1145 	return 0;
1146     }
1147 
1148     close(routes);
1149     default_route_gateway = (cmd == 's')? g: 0;
1150     return 1;
1151 }
1152 
1153 #if RTM_VERSION >= 3
1154 
1155 /*
1156  * sifproxyarp - Make a proxy ARP entry for the peer.
1157  */
1158 static struct {
1159     struct rt_msghdr		hdr;
1160     struct sockaddr_inarp	dst;
1161     struct sockaddr_dl		hwa;
1162     char			extra[128];
1163 } arpmsg;
1164 
1165 static int arpmsg_valid;
1166 
1167 int
1168 sifproxyarp(unit, hisaddr)
1169     int unit;
1170     u_int32_t hisaddr;
1171 {
1172     int routes;
1173 
1174     /*
1175      * Get the hardware address of an interface on the same subnet
1176      * as our local address.
1177      */
1178     memset(&arpmsg, 0, sizeof(arpmsg));
1179     if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
1180 	syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
1181 	return 0;
1182     }
1183 
1184     if ((routes = socket(AF_ROUTE, SOCK_RAW, AF_INET)) == -1) {
1185 	syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m");
1186 	return 0;
1187     }
1188 
1189     arpmsg.hdr.rtm_type = RTM_ADD;
1190     arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
1191     arpmsg.hdr.rtm_version = RTM_VERSION;
1192     arpmsg.hdr.rtm_seq = ++rtm_seq;
1193     arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
1194     arpmsg.hdr.rtm_inits = RTV_EXPIRE;
1195     arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
1196     arpmsg.dst.sin_family = AF_INET;
1197     arpmsg.dst.sin_addr.s_addr = hisaddr;
1198     arpmsg.dst.sin_other = SIN_PROXY;
1199 
1200     arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
1201 	+ arpmsg.hwa.sdl_len;
1202     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) == -1) {
1203 	syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
1204 	close(routes);
1205 	return 0;
1206     }
1207 
1208     close(routes);
1209     arpmsg_valid = 1;
1210     proxy_arp_addr = hisaddr;
1211     return 1;
1212 }
1213 
1214 /*
1215  * cifproxyarp - Delete the proxy ARP entry for the peer.
1216  */
1217 int
1218 cifproxyarp(unit, hisaddr)
1219     int unit;
1220     u_int32_t hisaddr;
1221 {
1222     int routes;
1223 
1224     if (!arpmsg_valid)
1225 	return 0;
1226     arpmsg_valid = 0;
1227 
1228     arpmsg.hdr.rtm_type = RTM_DELETE;
1229     arpmsg.hdr.rtm_seq = ++rtm_seq;
1230 
1231     if ((routes = socket(AF_ROUTE, SOCK_RAW, AF_INET)) == -1) {
1232 	syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m");
1233 	return 0;
1234     }
1235 
1236     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) == -1) {
1237 	syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m");
1238 	close(routes);
1239 	return 0;
1240     }
1241 
1242     close(routes);
1243     proxy_arp_addr = 0;
1244     return 1;
1245 }
1246 
1247 #else	/* RTM_VERSION */
1248 
1249 /*
1250  * sifproxyarp - Make a proxy ARP entry for the peer.
1251  */
1252 int
1253 sifproxyarp(unit, hisaddr)
1254     int unit;
1255     u_int32_t hisaddr;
1256 {
1257     struct arpreq arpreq;
1258     struct {
1259 	struct sockaddr_dl	sdl;
1260 	char			space[128];
1261     } dls;
1262 
1263     BZERO(&arpreq, sizeof(arpreq));
1264 
1265     /*
1266      * Get the hardware address of an interface on the same subnet
1267      * as our local address.
1268      */
1269     if (!get_ether_addr(hisaddr, &dls.sdl)) {
1270 	syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
1271 	return 0;
1272     }
1273 
1274     arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
1275     arpreq.arp_ha.sa_family = AF_UNSPEC;
1276     BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
1277     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1278     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1279     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1280     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) == -1) {
1281 	syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
1282 	return 0;
1283     }
1284 
1285     proxy_arp_addr = hisaddr;
1286     return 1;
1287 }
1288 
1289 /*
1290  * cifproxyarp - Delete the proxy ARP entry for the peer.
1291  */
1292 int
1293 cifproxyarp(unit, hisaddr)
1294     int unit;
1295     u_int32_t hisaddr;
1296 {
1297     struct arpreq arpreq;
1298 
1299     BZERO(&arpreq, sizeof(arpreq));
1300     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1301     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1302     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) == -1) {
1303 	syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m");
1304 	return 0;
1305     }
1306     proxy_arp_addr = 0;
1307     return 1;
1308 }
1309 #endif	/* RTM_VERSION */
1310 
1311 
1312 /*
1313  * get_ether_addr - get the hardware address of an interface on the
1314  * the same subnet as ipaddr.
1315  */
1316 #define MAX_IFS		32
1317 
1318 static int
1319 get_ether_addr(ipaddr, hwaddr)
1320     u_int32_t ipaddr;
1321     struct sockaddr_dl *hwaddr;
1322 {
1323     u_int32_t ina, mask;
1324     struct sockaddr_dl *dla;
1325     struct ifaddrs *ifap, *ifa, *ifp;
1326 
1327     if (getifaddrs(&ifap) != 0) {
1328 	syslog(LOG_ERR, "getifaddrs: %m");
1329 	return 0;
1330     }
1331 
1332     /*
1333      * Scan through looking for an interface with an Internet
1334      * address on the same subnet as `ipaddr'.
1335      */
1336     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1337 	if (ifa->ifa_addr == NULL)
1338 		continue;
1339 	if (ifa->ifa_addr->sa_family == AF_INET) {
1340 	    ina = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1341 	    /*
1342 	     * Check that the interface is up, and not point-to-point
1343 	     * or loopback.
1344 	     */
1345 	    if ((ifa->ifa_flags &
1346 		 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1347 		 != (IFF_UP|IFF_BROADCAST))
1348 		continue;
1349 	    /*
1350 	     * Get its netmask and check that it's on the right subnet.
1351 	     */
1352 	    mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
1353 	    if ((ipaddr & mask) != (ina & mask))
1354 		continue;
1355 
1356 	    break;
1357 	}
1358     }
1359 
1360     if (ifa == NULL) {
1361 	freeifaddrs(ifap);
1362 	return 0;
1363     }
1364     syslog(LOG_INFO, "found interface %s for proxy arp", ifa->ifa_name);
1365 
1366     /*
1367      * Now scan through again looking for a link-level address
1368      * for this interface.
1369      */
1370     ifp = ifa;
1371     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1372 	if (ifa->ifa_addr == NULL)
1373 		continue;
1374 	if (strcmp(ifp->ifa_name, ifa->ifa_name) == 0
1375 	    && ifa->ifa_addr->sa_family == AF_LINK) {
1376 	    /*
1377 	     * Found the link-level address - copy it out
1378 	     */
1379 	    dla = (struct sockaddr_dl *)ifa->ifa_addr;
1380 	    BCOPY(dla, hwaddr, dla->sdl_len);
1381 	    return 1;
1382 	}
1383     }
1384 
1385     freeifaddrs(ifap);
1386     return 0;
1387 }
1388 
1389 /*
1390  * Return user specified netmask, modified by any mask we might determine
1391  * for address `addr' (in network byte order).
1392  * Here we scan through the system's list of interfaces, looking for
1393  * any non-point-to-point interfaces which might appear to be on the same
1394  * network as `addr'.  If we find any, we OR in their netmask to the
1395  * user-specified netmask.
1396  */
1397 u_int32_t
1398 GetMask(addr)
1399     u_int32_t addr;
1400 {
1401     u_int32_t mask, nmask, ina;
1402     struct ifaddrs *ifap, *ifa;
1403 
1404     addr = ntohl(addr);
1405     if (IN_CLASSA(addr))	/* determine network mask for address class */
1406 	nmask = IN_CLASSA_NET;
1407     else if (IN_CLASSB(addr))
1408 	nmask = IN_CLASSB_NET;
1409     else
1410 	nmask = IN_CLASSC_NET;
1411     /* class D nets are disallowed by bad_ip_adrs */
1412     mask = netmask | htonl(nmask);
1413 
1414     /*
1415      * Scan through the system's network interfaces.
1416      */
1417     if (getifaddrs(&ifap) != 0) {
1418 	syslog(LOG_WARNING, "getifaddrs: %m");
1419 	return mask;
1420     }
1421     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1422 	/*
1423 	 * Check the interface's internet address.
1424 	 */
1425 	if (ifa->ifa_addr == NULL ||
1426 	    ifa->ifa_addr->sa_family != AF_INET)
1427 		continue;
1428 	ina = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1429 	if ((ntohl(ina) & nmask) != (addr & nmask))
1430 	    continue;
1431 	/*
1432 	 * Check that the interface is up, and not point-to-point or loopback.
1433 	 */
1434 	if ((ifa->ifa_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1435 	    != IFF_UP)
1436 	    continue;
1437 	/*
1438 	 * Get its netmask and OR it into our mask.
1439 	 */
1440 	mask |= ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
1441     }
1442 
1443     freeifaddrs(ifap);
1444     return mask;
1445 }
1446 
1447 /*
1448  * lock - create a lock file for the named lock device
1449  */
1450 #define	LOCK_PREFIX	"/var/spool/lock/LCK.."
1451 
1452 int
1453 lock(dev)
1454     char *dev;
1455 {
1456     char hdb_lock_buffer[12];
1457     int fd, n;
1458     pid_t pid;
1459     char *p;
1460 
1461     if ((p = strrchr(dev, '/')) != NULL)
1462 	dev = p + 1;
1463     if (asprintf(&lock_file, "%s%s", LOCK_PREFIX, dev) == -1)
1464 	novm("lock file name");
1465 
1466     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) == -1) {
1467 	if (errno == EEXIST
1468 	    && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1469 	    /* Read the lock file to find out who has the device locked */
1470 	    n = read(fd, hdb_lock_buffer, 11);
1471 	    if (n <= 0) {
1472 		syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1473 		close(fd);
1474 	    } else {
1475 		hdb_lock_buffer[n] = 0;
1476 		pid = atoi(hdb_lock_buffer);
1477 		if (kill(pid, 0) == -1 && errno == ESRCH) {
1478 		    /* pid no longer exists - remove the lock file */
1479 		    if (unlink(lock_file) == 0) {
1480 			close(fd);
1481 			syslog(LOG_NOTICE, "Removed stale lock on %s (pid %ld)",
1482 			       dev, (long)pid);
1483 			continue;
1484 		    } else
1485 			syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1486 			       dev);
1487 		} else
1488 		    syslog(LOG_NOTICE, "Device %s is locked by pid %ld",
1489 			   dev, (long)pid);
1490 	    }
1491 	    close(fd);
1492 	} else
1493 	    syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1494 	free(lock_file);
1495 	lock_file = NULL;
1496 	return -1;
1497     }
1498 
1499     snprintf(hdb_lock_buffer, sizeof hdb_lock_buffer, "%10ld\n", (long)getpid());
1500     write(fd, hdb_lock_buffer, 11);
1501 
1502     close(fd);
1503     return 0;
1504 }
1505 
1506 /*
1507  * unlock - remove our lockfile
1508  */
1509 void
1510 unlock()
1511 {
1512     if (lock_file) {
1513 	unlink(lock_file);
1514 	free(lock_file);
1515 	lock_file = NULL;
1516     }
1517 }
1518