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