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