cb105f5ac0b3e873c17e65304a659a29da0e3fd8
[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.2 1993/12/14 05:41:11 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 #include "pppd.h"
43 #include "ppp.h"
44
45 static int initdisc;            /* Initial TTY discipline */
46
47
48 /*
49  * establish_ppp - Turn the serial port into a ppp interface.
50  */
51 void
52 establish_ppp()
53 {
54     int pppdisc = PPPDISC;
55
56     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
57         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
58         die(1);
59     }
60     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
61         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
62         die(1);
63     }
64
65     /*
66      * Find out which interface we were given.
67      */
68     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
69         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
70         die(1);
71     }
72 }
73
74
75 /*
76  * disestablish_ppp - Restore the serial port to normal operation.
77  * This shouldn't call die() because it's called from die().
78  */
79 void
80 disestablish_ppp()
81 {
82     if (ioctl(fd, TIOCSETD, &initdisc) < 0)
83         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
84 }
85
86
87 /*
88  * output - Output PPP packet.
89  */
90 void
91 output(unit, p, len)
92     int unit;
93     u_char *p;
94     int len;
95 {
96     if (unit != 0)
97         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
98
99     if (write(fd, p, len) < 0) {
100         syslog(LOG_ERR, "write: %m");
101         die(1);
102     }
103 }
104
105
106 /*
107  * read_packet - get a PPP packet from the serial device.
108  */
109 int
110 read_packet(buf)
111     u_char *buf;
112 {
113     int len;
114
115     if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
116         if (errno == EWOULDBLOCK) {
117             MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
118             return -1;
119         }
120         syslog(LOG_ERR, "read(fd): %m");
121         die(1);
122     }
123     return len;
124 }
125
126
127 /*
128  * ppp_send_config - configure the transmit characteristics of
129  * the ppp interface.
130  */
131 void
132 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
133     int unit, mtu;
134     u_long asyncmap;
135     int pcomp, accomp;
136 {
137     u_int x;
138     struct ifreq ifr;
139
140     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
141     ifr.ifr_mtu = mtu;
142     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
143         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
144         quit();
145     }
146
147     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
148         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
149         quit();
150     }
151
152     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
153         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
154         quit();
155     }
156     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
157     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
158     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
159         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
160         quit();
161     }
162 }
163
164 /*
165  * ppp_recv_config - configure the receive-side characteristics of
166  * the ppp interface.  At present this does nothing.
167  */
168 void
169 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
170     int unit, mru;
171     u_long asyncmap;
172     int pcomp, accomp;
173 {
174 #ifdef notyet
175     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
176         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
177         quit();
178     }
179
180     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
181         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
182         quit();
183     }
184     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
185     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
186         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
187         quit();
188     }
189 #endif  /* notyet */
190 }
191
192 /*
193  * sifvjcomp - config tcp header compression
194  */
195 int
196 sifvjcomp(u, vjcomp, cidcomp)
197 {
198     u_int x;
199
200     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
201         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
202         return 0;
203     }
204     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
205     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
206     if(ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
207         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
208         return 0;
209     }
210     return 1;
211 }
212
213 /*
214  * sifup - Config the interface up.
215  */
216 int
217 sifup(u)
218 {
219     struct ifreq ifr;
220     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
221     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
222         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
223         return 0;
224     }
225     ifr.ifr_flags |= IFF_UP;
226     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
227         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
228         return 0;
229     }
230     return 1;
231 }
232
233 /*
234  * sifdown - Config the interface down.
235  */
236 int
237 sifdown(u)
238 {
239     struct ifreq ifr;
240     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
241     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
242         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
243         return 0;
244     }
245     ifr.ifr_flags &= ~IFF_UP;
246     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
247         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
248         return 0;
249     }
250     return 1;
251 }
252
253 /*
254  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
255  * if it exists.
256  */
257 #define SET_SA_FAMILY(addr, family)             \
258     BZERO((char *) &(addr), sizeof(addr));      \
259     addr.sa_family = (family);                  \
260     addr.sa_len = sizeof(addr);
261
262 /*
263  * sifaddr - Config the interface IP addresses and netmask.
264  */
265 int
266 sifaddr(u, o, h, m)
267 {
268     struct ifaliasreq ifra;
269
270     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
271     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
272     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
273     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
274     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
275     if (m != 0) {
276         SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
277         ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
278     } else
279         BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
280     if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
281         if (errno != EEXIST) {
282             syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
283             return 0;
284         }
285         syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
286     }
287     return 1;
288 }
289
290 /*
291  * cifaddr - Clear the interface IP addresses, and delete routes
292  * through the interface if possible.
293  */
294 int
295 cifaddr(u, o, h)
296 {
297     struct ifaliasreq ifra;
298
299     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
300     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
301     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
302     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
303     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
304     BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
305     if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
306         syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
307         return 0;
308     }
309     return 1;
310 }
311
312 /*
313  * sifdefaultroute - assign a default route through the address given.
314  */
315 int
316 sifdefaultroute(u, g)
317 {
318     struct ortentry rt;
319
320     SET_SA_FAMILY(rt.rt_dst, AF_INET);
321     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
322     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
323     rt.rt_flags = RTF_GATEWAY;
324     if (ioctl(s, SIOCADDRT, &rt) < 0) {
325         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
326         return 0;
327     }
328     return 1;
329 }
330
331 /*
332  * cifdefaultroute - delete a default route through the address given.
333  */
334 int
335 cifdefaultroute(u, g)
336 {
337     struct ortentry rt;
338
339     SET_SA_FAMILY(rt.rt_dst, AF_INET);
340     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
341     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
342     rt.rt_flags = RTF_GATEWAY;
343     if (ioctl(s, SIOCDELRT, &rt) < 0)
344         syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
345 }
346
347 /*
348  * sifproxyarp - Make a proxy ARP entry for the peer.
349  */
350 int
351 sifproxyarp(unit, hisaddr)
352     int unit;
353     u_long hisaddr;
354 {
355     struct arpreq arpreq;
356
357     BZERO(&arpreq, sizeof(arpreq));
358
359     /*
360      * Get the hardware address of an interface on the same subnet
361      * as our local address.
362      */
363     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
364         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
365         return 0;
366     }
367
368     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
369     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
370     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
371     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
372         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
373         return 0;
374     }
375
376     return 1;
377 }
378
379 /*
380  * cifproxyarp - Delete the proxy ARP entry for the peer.
381  */
382 int
383 cifproxyarp(unit, hisaddr)
384     int unit;
385     u_long hisaddr;
386 {
387     struct arpreq arpreq;
388
389     BZERO(&arpreq, sizeof(arpreq));
390     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
391     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
392     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
393         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
394         return 0;
395     }
396     return 1;
397 }
398
399 /*
400  * get_ether_addr - get the hardware address of an interface on the
401  * the same subnet as ipaddr.
402  */
403 #define MAX_IFS         32
404
405 int
406 get_ether_addr(ipaddr, hwaddr)
407     u_long ipaddr;
408     struct sockaddr *hwaddr;
409 {
410     struct ifreq *ifr, *ifend, *ifp;
411     u_long ina, mask;
412     struct sockaddr_dl *dla;
413     struct ifreq ifreq;
414     struct ifconf ifc;
415     struct ifreq ifs[MAX_IFS];
416
417     ifc.ifc_len = sizeof(ifs);
418     ifc.ifc_req = ifs;
419     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
420         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
421         return 0;
422     }
423
424     /*
425      * Scan through looking for an interface with an Internet
426      * address on the same subnet as `ipaddr'.
427      */
428     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
429     for (ifr = ifc.ifc_req; ifr < ifend; ) {
430         if (ifr->ifr_addr.sa_family == AF_INET) {
431             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
432             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
433             /*
434              * Check that the interface is up, and not point-to-point
435              * or loopback.
436              */
437             if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
438                 continue;
439             if ((ifreq.ifr_flags &
440                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
441                  != (IFF_UP|IFF_BROADCAST))
442                 continue;
443             /*
444              * Get its netmask and check that it's on the right subnet.
445              */
446             if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
447                 continue;
448             mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
449             if ((ipaddr & mask) != (ina & mask))
450                 continue;
451
452             break;
453         }
454         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
455     }
456
457     if (ifr >= ifend)
458         return 0;
459     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
460
461     /*
462      * Now scan through again looking for a link-level address
463      * for this interface.
464      */
465     ifp = ifr;
466     for (ifr = ifc.ifc_req; ifr < ifend; ) {
467         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
468             && ifr->ifr_addr.sa_family == AF_LINK) {
469             /*
470              * Found the link-level address - copy it out
471              */
472             dla = (struct sockaddr_dl *)&ifr->ifr_addr;
473             hwaddr->sa_len = sizeof(struct sockaddr);
474             hwaddr->sa_family = AF_UNSPEC;
475             BCOPY(LLADDR(dla), hwaddr->sa_data, dla->sdl_alen);
476             return 1;
477         }
478         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
479     }
480
481     return 0;
482 }
483
484 /*
485  * ppp_available - check whether the system has any ppp interfaces
486  * (in fact we check whether we can do an ioctl on ppp0).
487  */
488
489 int
490 ppp_available()
491 {
492     int s, ok;
493     struct ifreq ifr;
494
495     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
496         return 1;               /* can't tell - maybe we're not root */
497
498     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
499     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
500     close(s);
501
502     return ok;
503 }