f07a3b7351b7fa8462f8d2700d3c77ff4018b56d
[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.9 1994/08/22 00:41:00 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <syslog.h>
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/time.h>
34 #include <sys/errno.h>
35
36 #include <net/if.h>
37 #include <net/if_ppp.h>
38 #include <net/route.h>
39 #include <net/if_dl.h>
40 #include <netinet/in.h>
41
42 #if RTM_VERSION >= 3
43 #include <netinet/if_ether.h>
44 #endif
45
46 #include "pppd.h"
47 #include "ppp.h"
48
49 static int initdisc = -1;               /* Initial TTY discipline */
50 extern int kdebugflag;
51 static int rtm_seq;
52
53 /*
54  * establish_ppp - Turn the serial port into a ppp interface.
55  */
56 void
57 establish_ppp()
58 {
59     int pppdisc = PPPDISC;
60     int x;
61
62     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
63         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
64         die(1);
65     }
66     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
67         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
68         die(1);
69     }
70
71     /*
72      * Find out which interface we were given.
73      */
74     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
75         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
76         die(1);
77     }
78
79     /*
80      * Enable debug in the driver if requested.
81      */
82     if (kdebugflag) {
83         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
84             syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
85         } else {
86             x |= (kdebugflag & 0xFF) * SC_DEBUG;
87             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
88                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
89         }
90     }
91 }
92
93
94 /*
95  * disestablish_ppp - Restore the serial port to normal operation.
96  * This shouldn't call die() because it's called from die().
97  */
98 void
99 disestablish_ppp()
100 {
101     int x;
102     char *s;
103
104     if (initdisc >= 0) {
105         /*
106          * Check whether the link seems not to be 8-bit clean.
107          */
108         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
109             s = NULL;
110             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
111             case SC_RCV_B7_0:
112                 s = "bit 7 set to 1";
113                 break;
114             case SC_RCV_B7_1:
115                 s = "bit 7 set to 0";
116                 break;
117             case SC_RCV_EVNP:
118                 s = "odd parity";
119                 break;
120             case SC_RCV_ODDP:
121                 s = "even parity";
122                 break;
123             }
124             if (s != NULL) {
125                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
126                 syslog(LOG_WARNING, "All received characters had %s", s);
127             }
128         }
129         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
130             syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
131     }
132 }
133
134
135 /*
136  * output - Output PPP packet.
137  */
138 void
139 output(unit, p, len)
140     int unit;
141     u_char *p;
142     int len;
143 {
144     if (unit != 0)
145         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
146     if (debug)
147         log_packet(p, len, "sent ");
148
149     if (write(fd, p, len) < 0) {
150         syslog(LOG_ERR, "write: %m");
151         die(1);
152     }
153 }
154
155
156 /*
157  * wait_input - wait until there is data available on fd,
158  * for the length of time specified by *timo (indefinite
159  * if timo is NULL).
160  */
161 wait_input(timo)
162     struct timeval *timo;
163 {
164     fd_set ready;
165     int n;
166
167     FD_ZERO(&ready);
168     FD_SET(fd, &ready);
169     n = select(fd+1, &ready, NULL, &ready, timo);
170     if (n < 0 && errno != EINTR) {
171         syslog(LOG_ERR, "select: %m");
172         die(1);
173     }
174 }
175
176
177 /*
178  * read_packet - get a PPP packet from the serial device.
179  */
180 int
181 read_packet(buf)
182     u_char *buf;
183 {
184     int len;
185
186     if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
187         if (errno == EWOULDBLOCK) {
188             MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
189             return -1;
190         }
191         syslog(LOG_ERR, "read(fd): %m");
192         die(1);
193     }
194     return len;
195 }
196
197
198 /*
199  * ppp_send_config - configure the transmit characteristics of
200  * the ppp interface.
201  */
202 void
203 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
204     int unit, mtu;
205     u_long asyncmap;
206     int pcomp, accomp;
207 {
208     u_int x;
209     struct ifreq ifr;
210
211     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
212     ifr.ifr_mtu = mtu;
213     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
214         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
215         quit();
216     }
217
218     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
219         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
220         quit();
221     }
222
223     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
224         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
225         quit();
226     }
227     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
228     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
229     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
230         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
231         quit();
232     }
233 }
234
235
236 /*
237  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
238  */
239 void
240 ppp_set_xaccm(unit, accm)
241     int unit;
242     ext_accm accm;
243 {
244     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
245         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
246 }
247
248
249 /*
250  * ppp_recv_config - configure the receive-side characteristics of
251  * the ppp interface.
252  */
253 void
254 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
255     int unit, mru;
256     u_long asyncmap;
257     int pcomp, accomp;
258 {
259     int x;
260
261     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
262         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
263         quit();
264     }
265     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
266         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
267         quit();
268     }
269     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
270         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
271         quit();
272     }
273     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
274     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
275         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
276         quit();
277     }
278 }
279
280 /*
281  * ccp_test - ask kernel whether a given compression method
282  * is acceptable for use.
283  */
284 ccp_test(unit, opt_ptr, opt_len, for_transmit)
285     int unit, opt_len, for_transmit;
286     u_char *opt_ptr;
287 {
288     struct ppp_comp_data data;
289
290     data.ptr = opt_ptr;
291     data.length = opt_len;
292     data.transmit = for_transmit;
293     return ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0;
294 }
295
296 /*
297  * ccp_flags_set - inform kernel about the current state of CCP.
298  */
299 void
300 ccp_flags_set(unit, isopen, isup)
301     int unit, isopen, isup;
302 {
303     int x;
304
305     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
306         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
307         return;
308     }
309     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
310     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
311     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
312         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
313 }
314
315 /*
316  * sifvjcomp - config tcp header compression
317  */
318 int
319 sifvjcomp(u, vjcomp, cidcomp, maxcid)
320     int u, vjcomp, cidcomp, maxcid;
321 {
322     u_int x;
323
324     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
325         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
326         return 0;
327     }
328     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
329     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
330     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
331         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
332         return 0;
333     }
334     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
335         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
336         return 0;
337     }
338     return 1;
339 }
340
341 /*
342  * sifup - Config the interface up and enable IP packets to pass.
343  */
344 int
345 sifup(u)
346     int u;
347 {
348     struct ifreq ifr;
349     u_int x;
350
351     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
352     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
353         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
354         return 0;
355     }
356     ifr.ifr_flags |= IFF_UP;
357     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
358         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
359         return 0;
360     }
361     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
362         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
363         return 0;
364     }
365     x |= SC_ENABLE_IP;
366     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
367         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
368         return 0;
369     }
370     return 1;
371 }
372
373 /*
374  * sifdown - Config the interface down and disable IP.
375  */
376 int
377 sifdown(u)
378     int u;
379 {
380     struct ifreq ifr;
381     u_int x;
382     int rv;
383
384     rv = 1;
385     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
386         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
387         rv = 0;
388     } else {
389         x &= ~SC_ENABLE_IP;
390         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
391             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
392             rv = 0;
393         }
394     }
395     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
396     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
397         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
398         rv = 0;
399     } else {
400         ifr.ifr_flags &= ~IFF_UP;
401         if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
402             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
403             rv = 0;
404         }
405     }
406     return rv;
407 }
408
409 /*
410  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
411  * if it exists.
412  */
413 #define SET_SA_FAMILY(addr, family)             \
414     BZERO((char *) &(addr), sizeof(addr));      \
415     addr.sa_family = (family);                  \
416     addr.sa_len = sizeof(addr);
417
418 /*
419  * sifaddr - Config the interface IP addresses and netmask.
420  */
421 int
422 sifaddr(u, o, h, m)
423     int u;
424     u_long o, h, m;
425 {
426     struct ifaliasreq ifra;
427
428     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
429     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
430     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
431     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
432     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
433     if (m != 0) {
434         SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
435         ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
436     } else
437         BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
438     if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
439         if (errno != EEXIST) {
440             syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
441             return 0;
442         }
443         syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
444     }
445     return 1;
446 }
447
448 /*
449  * cifaddr - Clear the interface IP addresses, and delete routes
450  * through the interface if possible.
451  */
452 int
453 cifaddr(u, o, h)
454     int u;
455     u_long o, h;
456 {
457     struct ifaliasreq ifra;
458
459     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
460     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
461     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
462     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
463     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
464     BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
465     if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
466         syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
467         return 0;
468     }
469     return 1;
470 }
471
472 /*
473  * sifdefaultroute - assign a default route through the address given.
474  */
475 int
476 sifdefaultroute(u, g)
477     int u;
478     u_long g;
479 {
480     return dodefaultroute(g, 's');
481 }
482
483 /*
484  * cifdefaultroute - delete a default route through the address given.
485  */
486 int
487 cifdefaultroute(u, g)
488     int u;
489     u_long g;
490 {
491     return dodefaultroute(g, 'c');
492 }
493
494 /*
495  * dodefaultroute - talk to a routing socket to add/delete a default route.
496  */
497 int
498 dodefaultroute(g, cmd)
499     u_long g;
500     int cmd;
501 {
502     int routes;
503     struct {
504         struct rt_msghdr        hdr;
505         struct sockaddr_in      dst;
506         struct sockaddr_in      gway;
507         struct sockaddr_in      mask;
508     } rtmsg;
509
510     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
511         syslog(LOG_ERR, "%cifdefaultroute: opening routing socket: %m", cmd);
512         return 0;
513     }
514
515     memset(&rtmsg, 0, sizeof(rtmsg));
516     rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
517     rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY;
518     rtmsg.hdr.rtm_version = RTM_VERSION;
519     rtmsg.hdr.rtm_seq = ++rtm_seq;
520     rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
521     rtmsg.dst.sin_len = sizeof(rtmsg.dst);
522     rtmsg.dst.sin_family = AF_INET;
523     rtmsg.gway.sin_len = sizeof(rtmsg.gway);
524     rtmsg.gway.sin_family = AF_INET;
525     rtmsg.gway.sin_addr.s_addr = g;
526     rtmsg.mask.sin_len = sizeof(rtmsg.dst);
527     rtmsg.mask.sin_family = AF_INET;
528
529     rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
530     if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
531         syslog(LOG_ERR, "%s default route: %m", cmd=='s'? "add": "delete");
532         close(routes);
533         return 0;
534     }
535
536     close(routes);
537     return 1;
538 }
539
540 #if RTM_VERSION >= 3
541
542 /*
543  * sifproxyarp - Make a proxy ARP entry for the peer.
544  */
545 static struct {
546     struct rt_msghdr            hdr;
547     struct sockaddr_inarp       dst;
548     struct sockaddr_dl          hwa;
549     char                        extra[128];
550 } arpmsg;
551
552 static int arpmsg_valid;
553
554 int
555 sifproxyarp(unit, hisaddr)
556     int unit;
557     u_long hisaddr;
558 {
559     int routes;
560     int l;
561
562     /*
563      * Get the hardware address of an interface on the same subnet
564      * as our local address.
565      */
566     memset(&arpmsg, 0, sizeof(arpmsg));
567     if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
568         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
569         return 0;
570     }
571
572     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
573         syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
574         return 0;
575     }
576
577     arpmsg.hdr.rtm_type = RTM_ADD;
578     arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
579     arpmsg.hdr.rtm_version = RTM_VERSION;
580     arpmsg.hdr.rtm_seq = ++rtm_seq;
581     arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
582     arpmsg.hdr.rtm_inits = RTV_EXPIRE;
583     arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
584     arpmsg.dst.sin_family = AF_INET;
585     arpmsg.dst.sin_addr.s_addr = hisaddr;
586     arpmsg.dst.sin_other = SIN_PROXY;
587
588     arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
589         + arpmsg.hwa.sdl_len;
590     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
591         syslog(LOG_ERR, "add proxy arp entry: %m");
592         close(routes);
593         return 0;
594     }
595
596     close(routes);
597     arpmsg_valid = 1;
598     return 1;
599 }
600
601 /*
602  * cifproxyarp - Delete the proxy ARP entry for the peer.
603  */
604 int
605 cifproxyarp(unit, hisaddr)
606     int unit;
607     u_long hisaddr;
608 {
609     int routes;
610
611     if (!arpmsg_valid)
612         return 0;
613     arpmsg_valid = 0;
614
615     arpmsg.hdr.rtm_type = RTM_DELETE;
616     arpmsg.hdr.rtm_seq = ++rtm_seq;
617
618     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
619         syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
620         return 0;
621     }
622
623     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
624         syslog(LOG_ERR, "delete proxy arp entry: %m");
625         close(routes);
626         return 0;
627     }
628
629     close(routes);
630     return 1;
631 }
632
633 #else   /* RTM_VERSION */
634
635 /*
636  * sifproxyarp - Make a proxy ARP entry for the peer.
637  */
638 int
639 sifproxyarp(unit, hisaddr)
640     int unit;
641     u_long hisaddr;
642 {
643     struct arpreq arpreq;
644     struct {
645         struct sockaddr_dl      sdl;
646         char                    space[128];
647     } dls;
648
649     BZERO(&arpreq, sizeof(arpreq));
650
651     /*
652      * Get the hardware address of an interface on the same subnet
653      * as our local address.
654      */
655     if (!get_ether_addr(hisaddr, &dls.sdl)) {
656         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
657         return 0;
658     }
659
660     arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
661     arpreq.arp_ha.sa_family = AF_UNSPEC;
662     BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
663     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
664     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
665     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
666     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
667         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
668         return 0;
669     }
670
671     return 1;
672 }
673
674 /*
675  * cifproxyarp - Delete the proxy ARP entry for the peer.
676  */
677 int
678 cifproxyarp(unit, hisaddr)
679     int unit;
680     u_long hisaddr;
681 {
682     struct arpreq arpreq;
683
684     BZERO(&arpreq, sizeof(arpreq));
685     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
686     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
687     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
688         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
689         return 0;
690     }
691     return 1;
692 }
693 #endif  /* RTM_VERSION */
694
695
696 /*
697  * get_ether_addr - get the hardware address of an interface on the
698  * the same subnet as ipaddr.
699  */
700 #define MAX_IFS         32
701
702 int
703 get_ether_addr(ipaddr, hwaddr)
704     u_long ipaddr;
705     struct sockaddr_dl *hwaddr;
706 {
707     struct ifreq *ifr, *ifend, *ifp;
708     u_long ina, mask;
709     struct sockaddr_dl *dla;
710     struct ifreq ifreq;
711     struct ifconf ifc;
712     struct ifreq ifs[MAX_IFS];
713
714     ifc.ifc_len = sizeof(ifs);
715     ifc.ifc_req = ifs;
716     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
717         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
718         return 0;
719     }
720
721     /*
722      * Scan through looking for an interface with an Internet
723      * address on the same subnet as `ipaddr'.
724      */
725     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
726     for (ifr = ifc.ifc_req; ifr < ifend; ) {
727         if (ifr->ifr_addr.sa_family == AF_INET) {
728             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
729             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
730             /*
731              * Check that the interface is up, and not point-to-point
732              * or loopback.
733              */
734             if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
735                 continue;
736             if ((ifreq.ifr_flags &
737                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
738                  != (IFF_UP|IFF_BROADCAST))
739                 continue;
740             /*
741              * Get its netmask and check that it's on the right subnet.
742              */
743             if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
744                 continue;
745             mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
746             if ((ipaddr & mask) != (ina & mask))
747                 continue;
748
749             break;
750         }
751         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
752     }
753
754     if (ifr >= ifend)
755         return 0;
756     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
757
758     /*
759      * Now scan through again looking for a link-level address
760      * for this interface.
761      */
762     ifp = ifr;
763     for (ifr = ifc.ifc_req; ifr < ifend; ) {
764         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
765             && ifr->ifr_addr.sa_family == AF_LINK) {
766             /*
767              * Found the link-level address - copy it out
768              */
769             dla = (struct sockaddr_dl *) &ifr->ifr_addr;
770             BCOPY(dla, hwaddr, dla->sdl_len);
771             return 1;
772         }
773         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
774     }
775
776     return 0;
777 }
778
779
780 /*
781  * ppp_available - check whether the system has any ppp interfaces
782  * (in fact we check whether we can do an ioctl on ppp0).
783  */
784 int
785 ppp_available()
786 {
787     int s, ok;
788     struct ifreq ifr;
789
790     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
791         return 1;               /* can't tell - maybe we're not root */
792
793     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
794     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
795     close(s);
796
797     return ok;
798 }