change default route operations to use a routing socket;
[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.7 1994/05/30 06:10:07 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  * read_packet - get a PPP packet from the serial device.
158  */
159 int
160 read_packet(buf)
161     u_char *buf;
162 {
163     int len;
164
165     if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
166         if (errno == EWOULDBLOCK) {
167             MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
168             return -1;
169         }
170         syslog(LOG_ERR, "read(fd): %m");
171         die(1);
172     }
173     return len;
174 }
175
176
177 /*
178  * ppp_send_config - configure the transmit characteristics of
179  * the ppp interface.
180  */
181 void
182 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
183     int unit, mtu;
184     u_long asyncmap;
185     int pcomp, accomp;
186 {
187     u_int x;
188     struct ifreq ifr;
189
190     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
191     ifr.ifr_mtu = mtu;
192     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
193         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
194         quit();
195     }
196
197     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
198         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
199         quit();
200     }
201
202     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
203         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
204         quit();
205     }
206     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
207     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
208     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
209         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
210         quit();
211     }
212 }
213
214
215 /*
216  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
217  */
218 void
219 ppp_set_xaccm(unit, accm)
220     int unit;
221     ext_accm accm;
222 {
223     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
224         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
225 }
226
227
228 /*
229  * ppp_recv_config - configure the receive-side characteristics of
230  * the ppp interface.
231  */
232 void
233 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
234     int unit, mru;
235     u_long asyncmap;
236     int pcomp, accomp;
237 {
238     int x;
239
240     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
241         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
242         quit();
243     }
244     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
245         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
246         quit();
247     }
248     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
249         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
250         quit();
251     }
252     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
253     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
254         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
255         quit();
256     }
257 }
258
259 /*
260  * sifvjcomp - config tcp header compression
261  */
262 int
263 sifvjcomp(u, vjcomp, cidcomp, maxcid)
264     int u, vjcomp, cidcomp, maxcid;
265 {
266     u_int x;
267
268     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
269         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
270         return 0;
271     }
272     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
273     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
274     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
275         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
276         return 0;
277     }
278     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
279         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
280         return 0;
281     }
282     return 1;
283 }
284
285 /*
286  * sifup - Config the interface up and enable IP packets to pass.
287  */
288 int
289 sifup(u)
290     int u;
291 {
292     struct ifreq ifr;
293     u_int x;
294
295     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
296     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
297         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
298         return 0;
299     }
300     ifr.ifr_flags |= IFF_UP;
301     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
302         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
303         return 0;
304     }
305     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
306         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
307         return 0;
308     }
309     x |= SC_ENABLE_IP;
310     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
311         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
312         return 0;
313     }
314     return 1;
315 }
316
317 /*
318  * sifdown - Config the interface down and disable IP.
319  */
320 int
321 sifdown(u)
322     int u;
323 {
324     struct ifreq ifr;
325     u_int x;
326     int rv;
327
328     rv = 1;
329     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
330         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
331         rv = 0;
332     } else {
333         x &= ~SC_ENABLE_IP;
334         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
335             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
336             rv = 0;
337         }
338     }
339     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
340     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
341         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
342         rv = 0;
343     } else {
344         ifr.ifr_flags &= ~IFF_UP;
345         if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
346             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
347             rv = 0;
348         }
349     }
350     return rv;
351 }
352
353 /*
354  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
355  * if it exists.
356  */
357 #define SET_SA_FAMILY(addr, family)             \
358     BZERO((char *) &(addr), sizeof(addr));      \
359     addr.sa_family = (family);                  \
360     addr.sa_len = sizeof(addr);
361
362 /*
363  * sifaddr - Config the interface IP addresses and netmask.
364  */
365 int
366 sifaddr(u, o, h, m)
367     int u;
368     u_long o, h, m;
369 {
370     struct ifaliasreq ifra;
371
372     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
373     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
374     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
375     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
376     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
377     if (m != 0) {
378         SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
379         ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
380     } else
381         BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
382     if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
383         if (errno != EEXIST) {
384             syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
385             return 0;
386         }
387         syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
388     }
389     return 1;
390 }
391
392 /*
393  * cifaddr - Clear the interface IP addresses, and delete routes
394  * through the interface if possible.
395  */
396 int
397 cifaddr(u, o, h)
398     int u;
399     u_long o, h;
400 {
401     struct ifaliasreq ifra;
402
403     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
404     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
405     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
406     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
407     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
408     BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
409     if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
410         syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
411         return 0;
412     }
413     return 1;
414 }
415
416
417 /*
418  * sifdefaultroute - assign a default route through the address given.
419  */
420 int
421 sifdefaultroute(u, g)
422     int u;
423     u_long g;
424 {
425     return dodefaultroute(g, 's');
426 }
427
428 /*
429  * cifdefaultroute - delete a default route through the address given.
430  */
431 int
432 cifdefaultroute(u, g)
433     int u;
434     u_long g;
435 {
436     return dodefaultroute(g, 'c');
437 }
438
439 /*
440  * dodefaultroute - talk to a routing socket to add/delete a default route.
441  */
442 int
443 dodefaultroute(g, cmd)
444     u_long g;
445     int cmd;
446 {
447     int routes;
448     struct {
449         struct rt_msghdr        hdr;
450         struct sockaddr_in      dst;
451         struct sockaddr_in      gway;
452         struct sockaddr_in      mask;
453     } rtmsg;
454
455     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
456         syslog(LOG_ERR, "%cifdefaultroute: opening routing socket: %m", cmd);
457         return 0;
458     }
459
460     memset(&rtmsg, 0, sizeof(rtmsg));
461     rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
462     rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY;
463     rtmsg.hdr.rtm_version = RTM_VERSION;
464     rtmsg.hdr.rtm_seq = ++rtm_seq;
465     rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
466     rtmsg.dst.sin_len = sizeof(rtmsg.dst);
467     rtmsg.dst.sin_family = AF_INET;
468     rtmsg.gway.sin_len = sizeof(rtmsg.gway);
469     rtmsg.gway.sin_family = AF_INET;
470     rtmsg.gway.sin_addr.s_addr = g;
471     rtmsg.mask.sin_len = sizeof(rtmsg.dst);
472     rtmsg.mask.sin_family = AF_INET;
473
474     rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
475     if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
476         syslog(LOG_ERR, "%s default route: %m", cmd=='s'? "add": "delete");
477         close(routes);
478         return 0;
479     }
480
481     close(routes);
482     return 1;
483 }
484
485 #if RTM_VERSION >= 3
486
487 /*
488  * sifproxyarp - Make a proxy ARP entry for the peer.
489  */
490 static struct {
491     struct rt_msghdr            hdr;
492     struct sockaddr_inarp       dst;
493     struct sockaddr_dl          hwa;
494     char                        extra[128];
495 } arpmsg;
496
497 static int arpmsg_valid;
498
499 int
500 sifproxyarp(unit, hisaddr)
501     int unit;
502     u_long hisaddr;
503 {
504     int routes;
505     int l;
506
507     /*
508      * Get the hardware address of an interface on the same subnet
509      * as our local address.
510      */
511     memset(&arpmsg, 0, sizeof(arpmsg));
512     if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
513         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
514         return 0;
515     }
516
517     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
518         syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
519         return 0;
520     }
521
522     arpmsg.hdr.rtm_type = RTM_ADD;
523     arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
524     arpmsg.hdr.rtm_version = RTM_VERSION;
525     arpmsg.hdr.rtm_seq = ++rtm_seq;
526     arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
527     arpmsg.hdr.rtm_inits = RTV_EXPIRE;
528     arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
529     arpmsg.dst.sin_family = AF_INET;
530     arpmsg.dst.sin_addr.s_addr = hisaddr;
531     arpmsg.dst.sin_other = SIN_PROXY;
532
533     arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
534         + arpmsg.hwa.sdl_len;
535     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
536         syslog(LOG_ERR, "add proxy arp entry: %m");
537         close(routes);
538         return 0;
539     }
540
541     close(routes);
542     arpmsg_valid = 1;
543     return 1;
544 }
545
546 /*
547  * cifproxyarp - Delete the proxy ARP entry for the peer.
548  */
549 int
550 cifproxyarp(unit, hisaddr)
551     int unit;
552     u_long hisaddr;
553 {
554     int routes;
555
556     if (!arpmsg_valid)
557         return 0;
558     arpmsg_valid = 0;
559
560     arpmsg.hdr.rtm_type = RTM_DELETE;
561     arpmsg.hdr.rtm_seq = ++rtm_seq;
562
563     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
564         syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
565         return 0;
566     }
567
568     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
569         syslog(LOG_ERR, "delete proxy arp entry: %m");
570         close(routes);
571         return 0;
572     }
573
574     close(routes);
575     return 1;
576 }
577
578 #else   /* RTM_VERSION */
579
580 /*
581  * sifproxyarp - Make a proxy ARP entry for the peer.
582  */
583 int
584 sifproxyarp(unit, hisaddr)
585     int unit;
586     u_long hisaddr;
587 {
588     struct arpreq arpreq;
589     struct {
590         struct sockaddr_dl      sdl;
591         char                    space[128];
592     } dls;
593
594     BZERO(&arpreq, sizeof(arpreq));
595
596     /*
597      * Get the hardware address of an interface on the same subnet
598      * as our local address.
599      */
600     if (!get_ether_addr(hisaddr, &dls.sdl)) {
601         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
602         return 0;
603     }
604
605     arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
606     arpreq.arp_ha.sa_family = AF_UNSPEC;
607     BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
608     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
609     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
610     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
611     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
612         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
613         return 0;
614     }
615
616     return 1;
617 }
618
619 /*
620  * cifproxyarp - Delete the proxy ARP entry for the peer.
621  */
622 int
623 cifproxyarp(unit, hisaddr)
624     int unit;
625     u_long hisaddr;
626 {
627     struct arpreq arpreq;
628
629     BZERO(&arpreq, sizeof(arpreq));
630     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
631     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
632     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
633         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
634         return 0;
635     }
636     return 1;
637 }
638 #endif  /* RTM_VERSION */
639
640
641 /*
642  * get_ether_addr - get the hardware address of an interface on the
643  * the same subnet as ipaddr.
644  */
645 #define MAX_IFS         32
646
647 int
648 get_ether_addr(ipaddr, hwaddr)
649     u_long ipaddr;
650     struct sockaddr_dl *hwaddr;
651 {
652     struct ifreq *ifr, *ifend, *ifp;
653     u_long ina, mask;
654     struct sockaddr_dl *dla;
655     struct ifreq ifreq;
656     struct ifconf ifc;
657     struct ifreq ifs[MAX_IFS];
658
659     ifc.ifc_len = sizeof(ifs);
660     ifc.ifc_req = ifs;
661     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
662         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
663         return 0;
664     }
665
666     /*
667      * Scan through looking for an interface with an Internet
668      * address on the same subnet as `ipaddr'.
669      */
670     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
671     for (ifr = ifc.ifc_req; ifr < ifend; ) {
672         if (ifr->ifr_addr.sa_family == AF_INET) {
673             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
674             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
675             /*
676              * Check that the interface is up, and not point-to-point
677              * or loopback.
678              */
679             if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
680                 continue;
681             if ((ifreq.ifr_flags &
682                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
683                  != (IFF_UP|IFF_BROADCAST))
684                 continue;
685             /*
686              * Get its netmask and check that it's on the right subnet.
687              */
688             if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
689                 continue;
690             mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
691             if ((ipaddr & mask) != (ina & mask))
692                 continue;
693
694             break;
695         }
696         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
697     }
698
699     if (ifr >= ifend)
700         return 0;
701     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
702
703     /*
704      * Now scan through again looking for a link-level address
705      * for this interface.
706      */
707     ifp = ifr;
708     for (ifr = ifc.ifc_req; ifr < ifend; ) {
709         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
710             && ifr->ifr_addr.sa_family == AF_LINK) {
711             /*
712              * Found the link-level address - copy it out
713              */
714             dla = (struct sockaddr_dl *) &ifr->ifr_addr;
715             BCOPY(dla, hwaddr, dla->sdl_len);
716             return 1;
717         }
718         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
719     }
720
721     return 0;
722 }
723
724
725 /*
726  * ppp_available - check whether the system has any ppp interfaces
727  * (in fact we check whether we can do an ioctl on ppp0).
728  */
729 int
730 ppp_available()
731 {
732     int s, ok;
733     struct ifreq ifr;
734
735     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
736         return 1;               /* can't tell - maybe we're not root */
737
738     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
739     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
740     close(s);
741
742     return ok;
743 }