Add prototypes; implement sys_cleanup; ccp_test provides more info;
[ppp.git] / pppd / sys-bsd.c
1 /*
2  * sys-bsd.c - System-dependent procedures for setting up
3  * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by Carnegie Mellon University.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20
21 #ifndef lint
22 static char rcsid[] = "$Id: sys-bsd.c,v 1.22 1995/10/27 03:46:27 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <stdio.h>
30 #include <syslog.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <termios.h>
36 #include <sys/ioctl.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/time.h>
40 #include <sys/stat.h>
41
42 #include <net/if.h>
43 #include <net/ppp_defs.h>
44 #include <net/if_ppp.h>
45 #include <net/route.h>
46 #include <net/if_dl.h>
47 #include <netinet/in.h>
48
49 #if RTM_VERSION >= 3
50 #include <netinet/if_ether.h>
51 #endif
52
53 #include "pppd.h"
54
55 static int initdisc = -1;       /* Initial TTY discipline */
56 static int initfdflags = -1;    /* Initial file descriptor flags for fd */
57
58 static int rtm_seq;
59
60 static int restore_term;        /* 1 => we've munged the terminal */
61 static struct termios inittermios; /* Initial TTY termios */
62 static struct winsize wsinfo;   /* Initial window size info */
63
64 static char *lock_file;         /* name of lock file created */
65
66 static int sockfd;              /* socket for doing interface ioctls */
67
68 static int if_is_up;            /* the interface is currently up */
69 static u_int32_t default_route_gateway; /* gateway addr for default route */
70 static u_int32_t proxy_arp_addr;        /* remote addr for proxy arp */
71
72 /* Prototypes for procedures local to this file. */
73 static int dodefaultroute __P((u_int32_t, int));
74 static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *));
75
76
77 /*
78  * sys_init - System-dependent initialization.
79  */
80 void
81 sys_init()
82 {
83     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
84     setlogmask(LOG_UPTO(LOG_INFO));
85     if (debug)
86         setlogmask(LOG_UPTO(LOG_DEBUG));
87
88     /* Get an internet socket for doing socket ioctl's on. */
89     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
90         syslog(LOG_ERR, "Couldn't create IP socket: %m");
91         die(1);
92     }
93 }
94
95 /*
96  * sys_cleanup - restore any system state we modified before exiting:
97  * mark the interface down, delete default route and/or proxy arp entry.
98  * This should call die() because it's called from die().
99  */
100 void
101 sys_cleanup()
102 {
103     struct ifreq ifr;
104
105     if (if_is_up) {
106         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
107         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
108             && ((ifr.ifr_flags & IFF_UP) != 0)) {
109             ifr.ifr_flags &= ~IFF_UP;
110             ioctl(sockfd, SIOCSIFFLAGS, &ifr);
111         }
112     }
113
114     if (default_route_gateway)
115         cifdefaultroute(0, default_route_gateway);
116     if (proxy_arp_addr)
117         cifproxyarp(0, proxy_arp_addr);
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  * (in fact we check whether we can do an ioctl on ppp0).
137  */
138 int
139 ppp_available()
140 {
141     int s, ok;
142     struct ifreq ifr;
143     extern char *no_ppp_msg;
144
145     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
146         return 1;               /* can't tell */
147
148     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
149     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
150     close(s);
151
152     no_ppp_msg = "\
153 This system lacks kernel support for PPP.  To include PPP support\n\
154 in the kernel, please follow the steps detailed in the README.bsd\n\
155 file in the ppp-2.2 distribution.\n";
156     return ok;
157 }
158
159 /*
160  * establish_ppp - Turn the serial port into a ppp interface.
161  */
162 void
163 establish_ppp()
164 {
165     int pppdisc = PPPDISC;
166     int x;
167
168     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
169         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
170         die(1);
171     }
172     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
173         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
174         die(1);
175     }
176
177     /*
178      * Find out which interface we were given.
179      */
180     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
181         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
182         die(1);
183     }
184
185     /*
186      * Enable debug in the driver if requested.
187      */
188     if (kdebugflag) {
189         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
190             syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
191         } else {
192             x |= (kdebugflag & 0xFF) * SC_DEBUG;
193             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
194                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
195         }
196     }
197
198     /*
199      * Set device for non-blocking reads.
200      */
201     if ((initfdflags = fcntl(fd, F_GETFL)) == -1
202         || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
203         syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
204     }
205 }
206
207
208 /*
209  * disestablish_ppp - Restore the serial port to normal operation.
210  * This shouldn't call die() because it's called from die().
211  */
212 void
213 disestablish_ppp()
214 {
215     int x;
216     char *s;
217
218     /* Reset non-blocking mode on the file descriptor. */
219     if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
220         syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
221     initfdflags = -1;
222
223     if (initdisc >= 0) {
224         /*
225          * Check whether the link seems not to be 8-bit clean.
226          */
227         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
228             s = NULL;
229             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
230             case SC_RCV_B7_0:
231                 s = "bit 7 set to 1";
232                 break;
233             case SC_RCV_B7_1:
234                 s = "bit 7 set to 0";
235                 break;
236             case SC_RCV_EVNP:
237                 s = "odd parity";
238                 break;
239             case SC_RCV_ODDP:
240                 s = "even parity";
241                 break;
242             }
243             if (s != NULL) {
244                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
245                 syslog(LOG_WARNING, "All received characters had %s", s);
246             }
247         }
248         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
249             syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
250     }
251 }
252
253
254 /*
255  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
256  * at the requested speed, etc.  If `local' is true, set CLOCAL
257  * regardless of whether the modem option was specified.
258  *
259  * For *BSD, we assume that speed_t values numerically equal bits/second.
260  */
261 void
262 set_up_tty(fd, local)
263     int fd, local;
264 {
265     struct termios tios;
266
267     if (tcgetattr(fd, &tios) < 0) {
268         syslog(LOG_ERR, "tcgetattr: %m");
269         die(1);
270     }
271
272     if (!restore_term) {
273         inittermios = tios;
274         ioctl(fd, TIOCGWINSZ, &wsinfo);
275     }
276
277     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
278     if (crtscts > 0 && !local)
279         tios.c_cflag |= CRTSCTS;
280     else if (crtscts < 0)
281         tios.c_cflag &= ~CRTSCTS;
282
283     tios.c_cflag |= CS8 | CREAD | HUPCL;
284     if (local || !modem)
285         tios.c_cflag |= CLOCAL;
286     tios.c_iflag = IGNBRK | IGNPAR;
287     tios.c_oflag = 0;
288     tios.c_lflag = 0;
289     tios.c_cc[VMIN] = 1;
290     tios.c_cc[VTIME] = 0;
291
292     if (crtscts == -2) {
293         tios.c_iflag |= IXON | IXOFF;
294         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
295         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
296     }
297
298     if (inspeed) {
299         cfsetospeed(&tios, inspeed);
300         cfsetispeed(&tios, inspeed);
301     } else {
302         inspeed = cfgetospeed(&tios);
303         /*
304          * We can't proceed if the serial port speed is 0,
305          * since that implies that the serial port is disabled.
306          */
307         if (inspeed == 0) {
308             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
309                    devnam);
310             die(1);
311         }
312     }
313     baud_rate = inspeed;
314
315     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
316         syslog(LOG_ERR, "tcsetattr: %m");
317         die(1);
318     }
319
320     restore_term = 1;
321 }
322
323 /*
324  * restore_tty - restore the terminal to the saved settings.
325  */
326 void
327 restore_tty()
328 {
329     if (restore_term) {
330         if (!default_device) {
331             /*
332              * Turn off echoing, because otherwise we can get into
333              * a loop with the tty and the modem echoing to each other.
334              * We presume we are the sole user of this tty device, so
335              * when we close it, it will revert to its defaults anyway.
336              */
337             inittermios.c_lflag &= ~(ECHO | ECHONL);
338         }
339         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
340             if (errno != ENXIO)
341                 syslog(LOG_WARNING, "tcsetattr: %m");
342         ioctl(fd, TIOCSWINSZ, &wsinfo);
343         restore_term = 0;
344     }
345 }
346
347 /*
348  * setdtr - control the DTR line on the serial port.
349  * This is called from die(), so it shouldn't call die().
350  */
351 void
352 setdtr(fd, on)
353 int fd, on;
354 {
355     int modembits = TIOCM_DTR;
356
357     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
358 }
359
360
361 /*
362  * output - Output PPP packet.
363  */
364 void
365 output(unit, p, len)
366     int unit;
367     u_char *p;
368     int len;
369 {
370     if (debug)
371         log_packet(p, len, "sent ");
372
373     if (write(fd, p, len) < 0) {
374         if (errno != EIO)
375             syslog(LOG_ERR, "write: %m");
376     }
377 }
378
379
380 /*
381  * wait_input - wait until there is data available on fd,
382  * for the length of time specified by *timo (indefinite
383  * if timo is NULL).
384  */
385 void
386 wait_input(timo)
387     struct timeval *timo;
388 {
389     fd_set ready;
390     int n;
391
392     FD_ZERO(&ready);
393     FD_SET(fd, &ready);
394     n = select(fd+1, &ready, NULL, &ready, timo);
395     if (n < 0 && errno != EINTR) {
396         syslog(LOG_ERR, "select: %m");
397         die(1);
398     }
399 }
400
401
402 /*
403  * read_packet - get a PPP packet from the serial device.
404  */
405 int
406 read_packet(buf)
407     u_char *buf;
408 {
409     int len;
410
411     if ((len = read(fd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
412         if (errno == EWOULDBLOCK || errno == EINTR)
413             return -1;
414         syslog(LOG_ERR, "read(fd): %m");
415         die(1);
416     }
417     return len;
418 }
419
420
421 /*
422  * ppp_send_config - configure the transmit characteristics of
423  * the ppp interface.
424  */
425 void
426 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
427     int unit, mtu;
428     u_int32_t asyncmap;
429     int pcomp, accomp;
430 {
431     u_int x;
432     struct ifreq ifr;
433
434     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
435     ifr.ifr_mtu = mtu;
436     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
437         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
438         quit();
439     }
440
441     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
442         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
443         quit();
444     }
445
446     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
447         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
448         quit();
449     }
450     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
451     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
452     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
453         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
454         quit();
455     }
456 }
457
458
459 /*
460  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
461  */
462 void
463 ppp_set_xaccm(unit, accm)
464     int unit;
465     ext_accm accm;
466 {
467     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
468         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
469 }
470
471
472 /*
473  * ppp_recv_config - configure the receive-side characteristics of
474  * the ppp interface.
475  */
476 void
477 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
478     int unit, mru;
479     u_int32_t asyncmap;
480     int pcomp, accomp;
481 {
482     int x;
483
484     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
485         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
486         quit();
487     }
488     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
489         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
490         quit();
491     }
492     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
493         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
494         quit();
495     }
496     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
497     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
498         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
499         quit();
500     }
501 }
502
503 /*
504  * ccp_test - ask kernel whether a given compression method
505  * is acceptable for use.  Returns 1 if the method and parameters
506  * are OK, 0 if the method is known but the parameters are not OK
507  * (e.g. code size should be reduced), or -1 if the method is unknown.
508  */
509 int
510 ccp_test(unit, opt_ptr, opt_len, for_transmit)
511     int unit, opt_len, for_transmit;
512     u_char *opt_ptr;
513 {
514     struct ppp_option_data data;
515
516     data.ptr = opt_ptr;
517     data.length = opt_len;
518     data.transmit = for_transmit;
519     if (ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
520         return 1;
521     return (errno == ENOBUFS)? 0: -1;
522 }
523
524 /*
525  * ccp_flags_set - inform kernel about the current state of CCP.
526  */
527 void
528 ccp_flags_set(unit, isopen, isup)
529     int unit, isopen, isup;
530 {
531     int x;
532
533     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
534         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
535         return;
536     }
537     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
538     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
539     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
540         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
541 }
542
543 /*
544  * ccp_fatal_error - returns 1 if decompression was disabled as a
545  * result of an error detected after decompression of a packet,
546  * 0 otherwise.  This is necessary because of patent nonsense.
547  */
548 int
549 ccp_fatal_error(unit)
550     int unit;
551 {
552     int x;
553
554     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
555         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
556         return 0;
557     }
558     return x & SC_DC_FERROR;
559 }
560
561 /*
562  * sifvjcomp - config tcp header compression
563  */
564 int
565 sifvjcomp(u, vjcomp, cidcomp, maxcid)
566     int u, vjcomp, cidcomp, maxcid;
567 {
568     u_int x;
569
570     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
571         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
572         return 0;
573     }
574     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
575     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
576     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
577         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
578         return 0;
579     }
580     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
581         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
582         return 0;
583     }
584     return 1;
585 }
586
587 /*
588  * sifup - Config the interface up and enable IP packets to pass.
589  */
590 #ifndef SC_ENABLE_IP
591 #define SC_ENABLE_IP    0x100   /* compat for old versions of kernel code */
592 #endif
593
594 int
595 sifup(u)
596     int u;
597 {
598     struct ifreq ifr;
599     u_int x;
600     struct npioctl npi;
601
602     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
603     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
604         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
605         return 0;
606     }
607     ifr.ifr_flags |= IFF_UP;
608     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
609         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
610         return 0;
611     }
612     if_is_up = 1;
613     npi.protocol = PPP_IP;
614     npi.mode = NPMODE_PASS;
615     if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
616         if (errno != ENOTTY) {
617             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
618             return 0;
619         }
620         /* for backwards compatibility */
621         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
622             syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
623             return 0;
624         }
625         x |= SC_ENABLE_IP;
626         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
627             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
628             return 0;
629         }
630     }
631     return 1;
632 }
633
634 /*
635  * sifdown - Config the interface down and disable IP.
636  */
637 int
638 sifdown(u)
639     int u;
640 {
641     struct ifreq ifr;
642     u_int x;
643     int rv;
644     struct npioctl npi;
645
646     rv = 1;
647     npi.protocol = PPP_IP;
648     npi.mode = NPMODE_ERROR;
649     if (ioctl(fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
650         if (errno != ENOTTY) {
651             syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
652             rv = 0;
653         } else {
654             /* backwards compatibility */
655             if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
656                 syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
657                 rv = 0;
658             } else {
659                 x &= ~SC_ENABLE_IP;
660                 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
661                     syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
662                     rv = 0;
663                 }
664             }
665         }
666     }
667
668     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
669     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
670         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
671         rv = 0;
672     } else {
673         ifr.ifr_flags &= ~IFF_UP;
674         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
675             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
676             rv = 0;
677         } else
678             if_is_up = 0;
679     }
680     return rv;
681 }
682
683 /*
684  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
685  * if it exists.
686  */
687 #define SET_SA_FAMILY(addr, family)             \
688     BZERO((char *) &(addr), sizeof(addr));      \
689     addr.sa_family = (family);                  \
690     addr.sa_len = sizeof(addr);
691
692 /*
693  * sifaddr - Config the interface IP addresses and netmask.
694  */
695 int
696 sifaddr(u, o, h, m)
697     int u;
698     u_int32_t o, h, m;
699 {
700     struct ifaliasreq ifra;
701
702     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
703     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
704     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
705     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
706     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
707     if (m != 0) {
708         SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
709         ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
710     } else
711         BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
712     if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
713         if (errno != EEXIST) {
714             syslog(LOG_ERR, "Couldn't set interface address: %m");
715             return 0;
716         }
717         syslog(LOG_WARNING,
718                "Couldn't set interface address: Address already exists");
719     }
720     return 1;
721 }
722
723 /*
724  * cifaddr - Clear the interface IP addresses, and delete routes
725  * through the interface if possible.
726  */
727 int
728 cifaddr(u, o, h)
729     int u;
730     u_int32_t o, h;
731 {
732     struct ifaliasreq ifra;
733
734     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
735     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
736     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
737     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
738     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
739     BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
740     if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
741         syslog(LOG_WARNING, "Couldn't delete interface address: %m");
742         return 0;
743     }
744     return 1;
745 }
746
747 /*
748  * sifdefaultroute - assign a default route through the address given.
749  */
750 int
751 sifdefaultroute(u, g)
752     int u;
753     u_int32_t g;
754 {
755     return dodefaultroute(g, 's');
756 }
757
758 /*
759  * cifdefaultroute - delete a default route through the address given.
760  */
761 int
762 cifdefaultroute(u, g)
763     int u;
764     u_int32_t g;
765 {
766     return dodefaultroute(g, 'c');
767 }
768
769 /*
770  * dodefaultroute - talk to a routing socket to add/delete a default route.
771  */
772 static int
773 dodefaultroute(g, cmd)
774     u_int32_t g;
775     int cmd;
776 {
777     int routes;
778     struct {
779         struct rt_msghdr        hdr;
780         struct sockaddr_in      dst;
781         struct sockaddr_in      gway;
782         struct sockaddr_in      mask;
783     } rtmsg;
784
785     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
786         syslog(LOG_ERR, "Couldn't %s default route: socket: %m",
787                cmd=='s'? "add": "delete");
788         return 0;
789     }
790
791     memset(&rtmsg, 0, sizeof(rtmsg));
792     rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
793     rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY;
794     rtmsg.hdr.rtm_version = RTM_VERSION;
795     rtmsg.hdr.rtm_seq = ++rtm_seq;
796     rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
797     rtmsg.dst.sin_len = sizeof(rtmsg.dst);
798     rtmsg.dst.sin_family = AF_INET;
799     rtmsg.gway.sin_len = sizeof(rtmsg.gway);
800     rtmsg.gway.sin_family = AF_INET;
801     rtmsg.gway.sin_addr.s_addr = g;
802     rtmsg.mask.sin_len = sizeof(rtmsg.dst);
803     rtmsg.mask.sin_family = AF_INET;
804
805     rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
806     if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
807         syslog(LOG_ERR, "Couldn't %s default route: %m",
808                cmd=='s'? "add": "delete");
809         close(routes);
810         return 0;
811     }
812
813     close(routes);
814     default_route_gateway = (cmd == 's')? g: 0;
815     return 1;
816 }
817
818 #if RTM_VERSION >= 3
819
820 /*
821  * sifproxyarp - Make a proxy ARP entry for the peer.
822  */
823 static struct {
824     struct rt_msghdr            hdr;
825     struct sockaddr_inarp       dst;
826     struct sockaddr_dl          hwa;
827     char                        extra[128];
828 } arpmsg;
829
830 static int arpmsg_valid;
831
832 int
833 sifproxyarp(unit, hisaddr)
834     int unit;
835     u_int32_t hisaddr;
836 {
837     int routes;
838     int l;
839
840     /*
841      * Get the hardware address of an interface on the same subnet
842      * as our local address.
843      */
844     memset(&arpmsg, 0, sizeof(arpmsg));
845     if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
846         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
847         return 0;
848     }
849
850     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
851         syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m");
852         return 0;
853     }
854
855     arpmsg.hdr.rtm_type = RTM_ADD;
856     arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
857     arpmsg.hdr.rtm_version = RTM_VERSION;
858     arpmsg.hdr.rtm_seq = ++rtm_seq;
859     arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
860     arpmsg.hdr.rtm_inits = RTV_EXPIRE;
861     arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
862     arpmsg.dst.sin_family = AF_INET;
863     arpmsg.dst.sin_addr.s_addr = hisaddr;
864     arpmsg.dst.sin_other = SIN_PROXY;
865
866     arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
867         + arpmsg.hwa.sdl_len;
868     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
869         syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
870         close(routes);
871         return 0;
872     }
873
874     close(routes);
875     arpmsg_valid = 1;
876     proxy_arp_addr = hisaddr;
877     return 1;
878 }
879
880 /*
881  * cifproxyarp - Delete the proxy ARP entry for the peer.
882  */
883 int
884 cifproxyarp(unit, hisaddr)
885     int unit;
886     u_int32_t hisaddr;
887 {
888     int routes;
889
890     if (!arpmsg_valid)
891         return 0;
892     arpmsg_valid = 0;
893
894     arpmsg.hdr.rtm_type = RTM_DELETE;
895     arpmsg.hdr.rtm_seq = ++rtm_seq;
896
897     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
898         syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m");
899         return 0;
900     }
901
902     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
903         syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m");
904         close(routes);
905         return 0;
906     }
907
908     close(routes);
909     proxy_arp_addr = 0;
910     return 1;
911 }
912
913 #else   /* RTM_VERSION */
914
915 /*
916  * sifproxyarp - Make a proxy ARP entry for the peer.
917  */
918 int
919 sifproxyarp(unit, hisaddr)
920     int unit;
921     u_int32_t hisaddr;
922 {
923     struct arpreq arpreq;
924     struct {
925         struct sockaddr_dl      sdl;
926         char                    space[128];
927     } dls;
928
929     BZERO(&arpreq, sizeof(arpreq));
930
931     /*
932      * Get the hardware address of an interface on the same subnet
933      * as our local address.
934      */
935     if (!get_ether_addr(hisaddr, &dls.sdl)) {
936         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
937         return 0;
938     }
939
940     arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
941     arpreq.arp_ha.sa_family = AF_UNSPEC;
942     BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
943     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
944     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
945     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
946     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
947         syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
948         return 0;
949     }
950
951     proxy_arp_addr = hisaddr;
952     return 1;
953 }
954
955 /*
956  * cifproxyarp - Delete the proxy ARP entry for the peer.
957  */
958 int
959 cifproxyarp(unit, hisaddr)
960     int unit;
961     u_int32_t hisaddr;
962 {
963     struct arpreq arpreq;
964
965     BZERO(&arpreq, sizeof(arpreq));
966     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
967     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
968     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
969         syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m");
970         return 0;
971     }
972     proxy_arp_addr = 0;
973     return 1;
974 }
975 #endif  /* RTM_VERSION */
976
977
978 /*
979  * get_ether_addr - get the hardware address of an interface on the
980  * the same subnet as ipaddr.
981  */
982 #define MAX_IFS         32
983
984 static int
985 get_ether_addr(ipaddr, hwaddr)
986     u_int32_t ipaddr;
987     struct sockaddr_dl *hwaddr;
988 {
989     struct ifreq *ifr, *ifend, *ifp;
990     u_int32_t ina, mask;
991     struct sockaddr_dl *dla;
992     struct ifreq ifreq;
993     struct ifconf ifc;
994     struct ifreq ifs[MAX_IFS];
995
996     ifc.ifc_len = sizeof(ifs);
997     ifc.ifc_req = ifs;
998     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
999         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
1000         return 0;
1001     }
1002
1003     /*
1004      * Scan through looking for an interface with an Internet
1005      * address on the same subnet as `ipaddr'.
1006      */
1007     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1008     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1009                 ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
1010         if (ifr->ifr_addr.sa_family == AF_INET) {
1011             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1012             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1013             /*
1014              * Check that the interface is up, and not point-to-point
1015              * or loopback.
1016              */
1017             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1018                 continue;
1019             if ((ifreq.ifr_flags &
1020                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1021                  != (IFF_UP|IFF_BROADCAST))
1022                 continue;
1023             /*
1024              * Get its netmask and check that it's on the right subnet.
1025              */
1026             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1027                 continue;
1028             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1029             if ((ipaddr & mask) != (ina & mask))
1030                 continue;
1031
1032             break;
1033         }
1034     }
1035
1036     if (ifr >= ifend)
1037         return 0;
1038     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1039
1040     /*
1041      * Now scan through again looking for a link-level address
1042      * for this interface.
1043      */
1044     ifp = ifr;
1045     for (ifr = ifc.ifc_req; ifr < ifend; ) {
1046         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
1047             && ifr->ifr_addr.sa_family == AF_LINK) {
1048             /*
1049              * Found the link-level address - copy it out
1050              */
1051             dla = (struct sockaddr_dl *) &ifr->ifr_addr;
1052             BCOPY(dla, hwaddr, dla->sdl_len);
1053             return 1;
1054         }
1055         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
1056     }
1057
1058     return 0;
1059 }
1060
1061 /*
1062  * Return user specified netmask, modified by any mask we might determine
1063  * for address `addr' (in network byte order).
1064  * Here we scan through the system's list of interfaces, looking for
1065  * any non-point-to-point interfaces which might appear to be on the same
1066  * network as `addr'.  If we find any, we OR in their netmask to the
1067  * user-specified netmask.
1068  */
1069 u_int32_t
1070 GetMask(addr)
1071     u_int32_t addr;
1072 {
1073     u_int32_t mask, nmask, ina;
1074     struct ifreq *ifr, *ifend, ifreq;
1075     struct ifconf ifc;
1076     struct ifreq ifs[MAX_IFS];
1077
1078     addr = ntohl(addr);
1079     if (IN_CLASSA(addr))        /* determine network mask for address class */
1080         nmask = IN_CLASSA_NET;
1081     else if (IN_CLASSB(addr))
1082         nmask = IN_CLASSB_NET;
1083     else
1084         nmask = IN_CLASSC_NET;
1085     /* class D nets are disallowed by bad_ip_adrs */
1086     mask = netmask | htonl(nmask);
1087
1088     /*
1089      * Scan through the system's network interfaces.
1090      */
1091     ifc.ifc_len = sizeof(ifs);
1092     ifc.ifc_req = ifs;
1093     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1094         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1095         return mask;
1096     }
1097     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1098     for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
1099                 ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
1100         /*
1101          * Check the interface's internet address.
1102          */
1103         if (ifr->ifr_addr.sa_family != AF_INET)
1104             continue;
1105         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1106         if ((ntohl(ina) & nmask) != (addr & nmask))
1107             continue;
1108         /*
1109          * Check that the interface is up, and not point-to-point or loopback.
1110          */
1111         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1112         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1113             continue;
1114         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1115             != IFF_UP)
1116             continue;
1117         /*
1118          * Get its netmask and OR it into our mask.
1119          */
1120         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1121             continue;
1122         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1123     }
1124
1125     return mask;
1126 }
1127
1128 /*
1129  * lock - create a lock file for the named lock device
1130  */
1131 #define LOCK_PREFIX     "/var/spool/lock/LCK.."
1132
1133 int
1134 lock(dev)
1135     char *dev;
1136 {
1137     char hdb_lock_buffer[12];
1138     int fd, pid, n;
1139     char *p;
1140
1141     if ((p = strrchr(dev, '/')) != NULL)
1142         dev = p + 1;
1143     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1144     if (lock_file == NULL)
1145         novm("lock file name");
1146     strcat(strcpy(lock_file, LOCK_PREFIX), dev);
1147
1148     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
1149         if (errno == EEXIST
1150             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
1151             /* Read the lock file to find out who has the device locked */
1152             n = read(fd, hdb_lock_buffer, 11);
1153             if (n > 0) {
1154                 hdb_lock_buffer[n] = 0;
1155                 pid = atoi(hdb_lock_buffer);
1156             }
1157             if (n <= 0) {
1158                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1159                 close(fd);
1160             } else {
1161                 if (kill(pid, 0) == -1 && errno == ESRCH) {
1162                     /* pid no longer exists - remove the lock file */
1163                     if (unlink(lock_file) == 0) {
1164                         close(fd);
1165                         syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1166                                dev, pid);
1167                         continue;
1168                     } else
1169                         syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
1170                                dev);
1171                 } else
1172                     syslog(LOG_NOTICE, "Device %s is locked by pid %d",
1173                            dev, pid);
1174             }
1175             close(fd);
1176         } else
1177             syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1178         free(lock_file);
1179         lock_file = NULL;
1180         return -1;
1181     }
1182
1183     sprintf(hdb_lock_buffer, "%10d\n", getpid());
1184     write(fd, hdb_lock_buffer, 11);
1185
1186     close(fd);
1187     return 0;
1188 }
1189
1190 /*
1191  * unlock - remove our lockfile
1192  */
1193 void
1194 unlock()
1195 {
1196     if (lock_file) {
1197         unlink(lock_file);
1198         free(lock_file);
1199         lock_file = NULL;
1200     }
1201 }