]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-str.c
add `must_exist' parameter to options_from_file
[ppp.git] / pppd / sys-str.c
1 /*
2  * sys-str.c - System-dependent procedures for setting up
3  * PPP interfaces on systems which use the STREAMS ppp interface.
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 /*
22  * TODO:
23  */
24
25 #include <errno.h>
26 #include <syslog.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/time.h>
31 #include <sys/stream.h>
32 #include <sys/stropts.h>
33
34 #include <net/if.h>
35 #include <net/route.h>
36 #include <net/if_arp.h>
37 #include <netinet/in.h>
38
39 #include "pppd.h"
40 #include "ppp.h"
41 #include "ppp_str.h"
42
43 #ifndef ifr_mtu
44 #define ifr_mtu         ifr_metric
45 #endif
46
47 #define MAXMODULES      10      /* max number of module names to save */
48 static struct   modlist {
49     char        modname[FMNAMESZ+1];
50 } str_modules[MAXMODULES];
51 static int      str_module_count = 0;
52
53 extern int hungup;
54
55 /*
56  * establish_ppp - Turn the serial port into a ppp interface.
57  */
58 void
59 establish_ppp()
60 {
61     /* go through and save the name of all the modules, then pop em */
62     for (;;) { 
63         if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
64             ioctl(fd, I_POP, 0) < 0)
65             break;
66         MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
67                    str_modules[str_module_count].modname));
68         str_module_count++;
69     }
70
71     MAINDEBUG((LOG_INFO, "about to push modules..."));
72
73     /* now push the async/fcs module */
74     if (ioctl(fd, I_PUSH, "pppasync") < 0) {
75         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
76         die(1);
77     }
78     /* finally, push the ppp_if module that actually handles the */
79     /* network interface */ 
80     if (ioctl(fd, I_PUSH, "pppif") < 0) {
81         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
82         die(1);
83     }
84     if (ioctl(fd, I_SETSIG, S_INPUT) < 0) {
85         syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
86         die(1);
87     }
88     /* read mode, message non-discard mode */
89     if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
90         syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
91         die(1);
92     }
93     /* Flush any waiting messages, or we'll never get SIGPOLL */
94     if (ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
95         syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
96         die(1);
97     }
98     /*
99      * Find out which interface we were given.
100      * (ppp_if handles this ioctl)
101      */
102     if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
103         syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
104         die(1);
105     }
106
107     /* if debug, set debug flags in driver */
108     {
109         int flags = debug ? 0x3 : 0;
110         if (ioctl(fd, SIOCSIFDEBUG, &flags) < 0) {
111             syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
112         }
113     }
114
115     MAINDEBUG((LOG_INFO, "done pushing modules, ifunit %d", ifunit));
116 }
117
118 /*
119  * disestablish_ppp - Restore the serial port to normal operation.
120  * It attempts to reconstruct the stream with the previously popped
121  * modules.  This shouldn't call die() because it's called from die().
122  */
123 void
124 disestablish_ppp()
125 {
126     /*EMPTY*/
127
128     if (hungup) {
129         /* we can't push or pop modules after the stream has hung up */
130         str_module_count = 0;
131         return;
132     }
133
134     while (ioctl(fd, I_POP, 0) == 0)    /* pop any we pushed */
135         ;
136   
137     for (; str_module_count > 0; str_module_count--) {
138         if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
139             syslog(LOG_ERR, "str_restore: couldn't push module %s: %m",
140                    str_modules[str_module_count-1].modname);
141         } else {
142             MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
143                        str_modules[str_module_count-1].modname));
144         }
145     }
146 }
147
148
149 /*
150  * output - Output PPP packet.
151  */
152 void
153 output(unit, p, len)
154     int unit;
155     u_char *p;
156     int len;
157 {
158     struct strbuf       str;
159
160     if (unit != 0)
161         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
162
163     str.len = len;
164     str.buf = (caddr_t) p;
165     if(putmsg(fd, NULL, &str, 0) < 0) {
166         syslog(LOG_ERR, "putmsg: %m");
167         die(1);
168     }
169 }
170
171
172 /*
173  * read_packet - get a PPP packet from the serial device.
174  */
175 int
176 read_packet(buf)
177     u_char *buf;
178 {
179     struct strbuf str;
180     int len, i;
181
182     str.maxlen = MTU+DLLHEADERLEN;
183     str.buf = (caddr_t) buf;
184     i = 0;
185     len = getmsg(fd, NULL, &str, &i);
186     if (len < 0) {
187         if (errno == EAGAIN || errno == EWOULDBLOCK) {
188             return -1;
189         }
190         syslog(LOG_ERR, "getmsg(fd) %m");
191         die(1);
192     }
193     if (len) 
194         MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
195
196     if (str.len < 0) {
197         MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
198         return -1;
199     }
200
201     return str.len;
202 }
203
204
205 /*
206  * ppp_send_config - configure the transmit characteristics of
207  * the ppp interface.
208  */
209 void
210 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
211     int unit, mtu;
212     u_long asyncmap;
213     int pcomp, accomp;
214 {
215     char c;
216     struct ifreq ifr;
217
218     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
219     ifr.ifr_mtu = mtu;
220     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
221         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
222         quit();
223     }
224
225     if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
226         syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
227         quit();
228     }
229
230     c = pcomp;
231     if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
232         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
233         quit();
234     }
235
236     c = accomp;
237     if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
238         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
239         quit();
240     }
241 }
242
243 /*
244  * ppp_recv_config - configure the receive-side characteristics of
245  * the ppp interface.  At present this just sets the MRU.
246  */
247 void
248 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
249     int unit, mru;
250     u_long asyncmap;
251     int pcomp, accomp;
252 {
253     char c;
254
255     if (ioctl(fd, SIOCSIFMRU, &mru) < 0) {
256         syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
257     }
258
259 #ifdef notyet
260     if(ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
261         syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
262     }
263
264     c = accomp;
265     if(ioctl(fd, SIOCSIFRCOMPAC, &c) < 0) {
266         syslog(LOG_ERR, "ioctl(SIOCSIFRCOMPAC): %m");
267         quit();
268     }
269 #endif  /* notyet */
270 }
271
272 /*
273  * sifvjcomp - config tcp header compression
274  */
275 int
276 sifvjcomp(u, vjcomp, cidcomp)
277 {
278     char x = vjcomp;
279
280     if(ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
281         syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
282         return 0;
283     }
284     return 1;
285 }
286
287 /*
288  * sifup - Config the interface up.
289  */
290 int
291 sifup(u)
292 {
293     struct ifreq ifr;
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     return 1;
306 }
307
308 /*
309  * sifdown - Config the interface down.
310  */
311 int
312 sifdown(u)
313 {
314     struct ifreq ifr;
315     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
316     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
317         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
318         return 0;
319     }
320     ifr.ifr_flags &= ~IFF_UP;
321     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
322         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
323         return 0;
324     }
325     return 1;
326 }
327
328 /*
329  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
330  */
331 #define SET_SA_FAMILY(addr, family)             \
332     BZERO((char *) &(addr), sizeof(addr));      \
333     addr.sa_family = (family);
334
335 /*
336  * sifaddr - Config the interface IP addresses and netmask.
337  */
338 int
339 sifaddr(u, o, h, m)
340 {
341     int ret;
342     struct ifreq ifr;
343
344     ret = 1;
345     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
346     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
347     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
348     if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
349         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
350         ret = 0;
351     }
352     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
353     if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
354         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
355         ret = 0;
356     }
357     if (m != 0) {
358         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
359         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
360         if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
361             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
362             ret = 0;
363         }
364     }
365     return ret;
366 }
367
368 /*
369  * cifaddr - Clear the interface IP addresses, and delete routes
370  * through the interface if possible.
371  */
372 int
373 cifaddr(u, o, h)
374 {
375     struct rtentry rt;
376
377     SET_SA_FAMILY(rt.rt_dst, AF_INET);
378     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
379     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
380     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
381     rt.rt_flags = RTF_HOST;
382     if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
383         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
384         return 0;
385     }
386     return 1;
387 }
388
389 /*
390  * sifdefaultroute - assign a default route through the address given.
391  */
392 int
393 sifdefaultroute(u, g)
394 {
395     struct rtentry rt;
396
397     SET_SA_FAMILY(rt.rt_dst, AF_INET);
398     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
399     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
400     rt.rt_flags = RTF_GATEWAY;
401     if (ioctl(s, SIOCADDRT, &rt) < 0) {
402         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
403         return 0;
404     }
405     return 1;
406 }
407
408 /*
409  * cifdefaultroute - delete a default route through the address given.
410  */
411 int
412 cifdefaultroute(u, g)
413 {
414     struct rtentry rt;
415
416     SET_SA_FAMILY(rt.rt_dst, AF_INET);
417     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
418     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
419     rt.rt_flags = RTF_GATEWAY;
420     if (ioctl(s, SIOCDELRT, &rt) < 0) {
421         syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
422         return 0;
423     }
424     return 1;
425 }
426
427 /*
428  * sifproxyarp - Make a proxy ARP entry for the peer.
429  */
430 int
431 sifproxyarp(unit, hisaddr)
432     int unit;
433     u_long hisaddr;
434 {
435     struct arpreq arpreq;
436
437     BZERO(&arpreq, sizeof(arpreq));
438
439     /*
440      * Get the hardware address of an interface on the same subnet
441      * as our local address.
442      */
443     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
444         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
445         return 0;
446     }
447
448     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
449     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
450     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
451     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
452         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
453         return 0;
454     }
455
456     return 1;
457 }
458
459 /*
460  * cifproxyarp - Delete the proxy ARP entry for the peer.
461  */
462 int
463 cifproxyarp(unit, hisaddr)
464     int unit;
465     u_long hisaddr;
466 {
467     struct arpreq arpreq;
468
469     BZERO(&arpreq, sizeof(arpreq));
470     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
471     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
472     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
473         syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
474         return 0;
475     }
476     return 1;
477 }
478
479 /*
480  * get_ether_addr - get the hardware address of an interface on the
481  * the same subnet as ipaddr.  Code borrowed from myetheraddr.c
482  * in the cslip-2.6 distribution, which is subject to the following
483  * copyright notice:
484  *
485  * Copyright (c) 1990, 1992 The Regents of the University of California.
486  * All rights reserved.
487  *
488  * Redistribution and use in source and binary forms, with or without
489  * modification, are permitted provided that: (1) source code distributions
490  * retain the above copyright notice and this paragraph in its entirety, (2)
491  * distributions including binary code include the above copyright notice and
492  * this paragraph in its entirety in the documentation or other materials
493  * provided with the distribution, and (3) all advertising materials mentioning
494  * features or use of this software display the following acknowledgement:
495  * ``This product includes software developed by the University of California,
496  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
497  * the University nor the names of its contributors may be used to endorse
498  * or promote products derived from this software without specific prior
499  * written permission.
500  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
501  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
502  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
503  */
504
505 #include <fcntl.h>
506 #include <nlist.h>
507 #include <kvm.h>
508 #include <arpa/inet.h>
509
510 /* XXX SunOS 4.1 defines this and 3.5 doesn't... */
511 #ifdef _nlist_h
512 #define SUNOS4
513 #endif
514
515 #ifdef SUNOS4
516 #include <netinet/in_var.h>
517 #endif
518 #include <netinet/if_ether.h>
519
520 /* Cast a struct sockaddr to a structaddr_in */
521 #define SATOSIN(sa) ((struct sockaddr_in *)(sa))
522
523 /* Determine if "bits" is set in "flag" */
524 #define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
525
526 static struct nlist nl[] = {
527 #define N_IFNET 0
528         { "_ifnet" },
529         0
530 };
531
532 static void kread();
533
534 int
535 get_ether_addr(ipaddr, hwaddr)
536     u_long ipaddr;
537     struct sockaddr *hwaddr;
538 {
539     register kvm_t *kd;
540     register struct ifnet *ifp;
541     register struct arpcom *ac;
542     struct arpcom arpcom;
543     struct in_addr *inp;
544 #ifdef SUNOS4
545     register struct ifaddr *ifa;
546     register struct in_ifaddr *in;
547     union {
548         struct ifaddr ifa;
549         struct in_ifaddr in;
550     } ifaddr;
551 #endif
552     u_long addr, mask;
553
554     /* Open kernel memory for reading */
555     kd = kvm_open(0, 0, 0, O_RDONLY, NULL);
556     if (kd == 0) {
557         syslog(LOG_ERR, "kvm_open: %m");
558         return 0;
559     }
560
561     /* Fetch namelist */
562     if (kvm_nlist(kd, nl) != 0) {
563         syslog(LOG_ERR, "kvm_nlist failed");
564         return 0;
565     }
566
567     ac = &arpcom;
568     ifp = &arpcom.ac_if;
569 #ifdef SUNOS4
570     ifa = &ifaddr.ifa;
571     in = &ifaddr.in;
572 #endif
573
574     if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
575         != sizeof(addr)) {
576         syslog(LOG_ERR, "error reading ifnet addr");
577         return 0;
578     }
579     for ( ; addr; addr = (u_long)ifp->if_next) {
580         if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
581             syslog(LOG_ERR, "error reading ifnet");
582             return 0;
583         }
584
585         /* Only look at configured, broadcast interfaces */
586         if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
587             continue;
588 #ifdef SUNOS4
589         /* This probably can't happen... */
590         if (ifp->if_addrlist == 0)
591             continue;
592 #endif
593
594         /* Get interface ip address */
595 #ifdef SUNOS4
596         if (kvm_read(kd, (u_long)ifp->if_addrlist, (char *)&ifaddr,
597                      sizeof(ifaddr)) != sizeof(ifaddr)) {
598             syslog(LOG_ERR, "error reading ifaddr");
599             return 0;
600         }
601         inp = &SATOSIN(&ifa->ifa_addr)->sin_addr;
602 #else
603         inp = &SATOSIN(&ifp->if_addr)->sin_addr;
604 #endif
605
606         /* Check if this interface on the right subnet */
607 #ifdef SUNOS4
608         mask = in->ia_subnetmask;
609 #else
610         mask = ifp->if_subnetmask;
611 #endif
612         if ((ipaddr & mask) != (inp->s_addr & mask))
613             continue;
614
615         /* Copy out the local ethernet address */
616         hwaddr->sa_family = AF_UNSPEC;
617         BCOPY((caddr_t) &arpcom.ac_enaddr, hwaddr->sa_data,
618               sizeof(arpcom.ac_enaddr));
619         return 1;               /* success! */
620     }
621
622     /* couldn't find one */
623     return 0;
624 }