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