]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-linux.c
remove interface route on exit; mods to use SIOC[AD]IFADDR
[ppp.git] / pppd / sys-linux.c
1 /*
2  * sys-linux.c - System-dependent procedures for setting up
3  * PPP interfaces on Linux systems
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 <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <sys/errno.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <syslog.h>
34 #include <string.h>
35 #include <time.h>
36 #include <memory.h>
37 #include <utmp.h>
38 #include <mntent.h>
39 #include <signal.h>
40 #include <fcntl.h>
41 #include <ctype.h>
42
43 #include <net/if.h>
44 #include <net/ppp_defs.h>
45 #include <net/if_arp.h>
46 #include <net/if_ppp.h>
47 #include <net/route.h>
48 #include <linux/if_ether.h>
49 #include <netinet/in.h>
50
51 #include "pppd.h"
52 #include "fsm.h"
53 #include "ipcp.h"
54
55 static int initdisc = -1;       /* Initial TTY discipline */
56 static int initfdflags = -1;    /* Initial file descriptor flags for fd */
57 static int prev_kdebugflag     = 0;
58 static int has_default_route   = 0;
59 static int has_proxy_arp       = 0;
60 static int driver_version      = 0;
61 static int driver_modification = 0;
62 static int driver_patch        = 0;
63 static int restore_term        = 0;     /* 1 => we've munged the terminal */
64 static struct termios inittermios;      /* Initial TTY termios */
65
66 static int sockfd;              /* socket for doing interface ioctls */
67
68 static int      if_is_up;       /* Interface has been marked up */
69 static u_int32_t ipaddrs[2];    /* Local and remote addrs we've set */
70 static u_int32_t default_route_gateway; /* Gateway for default route added */
71 static u_int32_t proxy_arp_addr;        /* Addr for proxy arp entry added */
72
73 static char *lock_file;
74
75 #define MAX_IFS         100
76
77 #define FLAGS_GOOD (IFF_UP          | IFF_BROADCAST)
78 #define FLAGS_MASK (IFF_UP          | IFF_BROADCAST | \
79                     IFF_POINTOPOINT | IFF_LOOPBACK  | IFF_NOARP)
80
81 /* Prototypes for procedures local to this file. */
82 static int get_flags (void);
83 static void set_flags (int flags);
84 static int translate_speed (int bps);
85 static int baud_rate_of (int speed);
86 static char *path_to_route (void);
87 static void close_route_table (void);
88 static int open_route_table (void);
89 static int read_route_table (struct rtentry *rt);
90 static int defaultroute_exists (void);
91 static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr);
92 static void decode_version (char *buf, int *version, int *mod, int *patch);
93
94
95 /*
96  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
97  * if it exists.
98  */
99
100 #define SET_SA_FAMILY(addr, family)                     \
101     memset ((char *) &(addr), '\0', sizeof(addr));      \
102     addr.sa_family = (family);
103
104 /*
105  * Determine if the PPP connection should still be present.
106  */
107
108 extern int hungup;
109 #define still_ppp() (hungup == 0)
110
111 /*
112  * Functions to read and set the flags value in the device driver
113  */
114
115 static int get_flags (void)
116   {    
117     int flags;
118
119     if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &flags) < 0)
120       {
121         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
122         quit();
123       }
124
125     MAINDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
126     return flags;
127   }
128
129 static void set_flags (int flags)
130   {    
131     MAINDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
132
133     if (ioctl(ttyfd, PPPIOCSFLAGS, (caddr_t) &flags) < 0)
134       {
135         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS, %x): %m", flags);
136         quit();
137       }
138   }
139
140 /*
141  * sys_init - System-dependent initialization.
142  */
143
144 void sys_init(void)
145   {
146     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
147     setlogmask(LOG_UPTO(LOG_INFO));
148     if (debug)
149       {
150         setlogmask(LOG_UPTO(LOG_DEBUG));
151       }
152     
153     /* Get an internet socket for doing socket ioctls. */
154     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
155     if (sockfd < 0)
156       {
157         syslog(LOG_ERR, "Couldn't create IP socket: %m");
158         die(1);
159       }
160   }
161
162 /*
163  * sys_cleanup - restore any system state we modified before exiting:
164  * mark the interface down, delete default route and/or proxy arp entry.
165  * This should call die() because it's called from die().
166  */
167 void sys_cleanup()
168 {
169     struct ifreq ifr;
170
171     if (if_is_up)
172         sifdown(0);
173     if (ipaddrs[0])
174         cifaddr(0, ipaddrs[0], ipaddrs[1]);
175     /* XXX maybe we need to delete the route through the interface */
176     if (has_default_route)
177         cifdefaultroute(0, default_route_gateway);
178     if (has_proxy_arp)
179         cifproxyarp(0, proxy_arp_addr);
180 }
181
182 /*
183  * note_debug_level - note a change in the debug level.
184  */
185
186 void note_debug_level (void)
187   {
188     if (debug)
189       {
190         MAINDEBUG ((LOG_INFO, "Debug turned ON, Level %d", debug));
191         setlogmask(LOG_UPTO(LOG_DEBUG));
192       }
193     else
194       {
195         setlogmask(LOG_UPTO(LOG_WARNING));
196       }
197   }
198
199 /*
200  * set_kdebugflag - Define the debugging level for the kernel
201  */
202
203 int set_kdebugflag (int requested_level)
204   {
205     if (ioctl(ttyfd, PPPIOCGDEBUG, &prev_kdebugflag) < 0)
206       {
207         syslog(LOG_ERR, "ioctl(PPPIOCGDEBUG): %m");
208         return (0);
209       }
210     
211     if (prev_kdebugflag != requested_level)
212       {
213         if (ioctl(ttyfd, PPPIOCSDEBUG, &requested_level) < 0)
214           {
215             syslog (LOG_ERR, "ioctl(PPPIOCSDEBUG): %m");
216             return (0);
217           }
218         MAINDEBUG ((LOG_INFO, "set kernel debugging level to %d",
219                     requested_level));
220       }
221     return (1);
222   }
223
224 /*
225  * establish_ppp - Turn the serial port into a ppp interface.
226  */
227
228 void establish_ppp (int fd)
229   {
230     int pppdisc = N_PPP;
231     int sig     = SIGIO;
232
233     if (ioctl(fd, TIOCEXCL, 0) < 0)
234       {
235         syslog (LOG_WARNING, "ioctl(TIOCEXCL): %m");
236       }
237     
238     if (ioctl(fd, TIOCGETD, &initdisc) < 0)
239       {
240         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
241         die (1);
242       }
243     
244     if (ioctl(fd, TIOCSETD, &pppdisc) < 0)
245       {
246         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
247         die (1);
248       }
249     
250     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0)
251       {
252         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
253         die (1);
254       }
255     
256     set_kdebugflag (kdebugflag);
257
258     set_flags (get_flags() & ~(SC_RCV_B7_0 | SC_RCV_B7_1 |
259                                SC_RCV_EVNP | SC_RCV_ODDP));
260
261     MAINDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
262             driver_version, driver_modification, driver_patch));
263
264     /*
265      * Set device for non-blocking reads.
266      */
267     if ((initfdflags = fcntl(fd, F_GETFL)) == -1
268         || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
269       {
270         syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
271       }
272   }
273
274 /*
275  * disestablish_ppp - Restore the serial port to normal operation.
276  * This shouldn't call die() because it's called from die().
277  */
278
279 void disestablish_ppp(int fd)
280   {
281     int x;
282     char *s;
283
284     /* Reset non-blocking mode on the file descriptor. */
285     if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
286         syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
287     initfdflags = -1;
288
289     if (still_ppp() && initdisc >= 0)
290       {
291         set_kdebugflag (prev_kdebugflag);
292         
293         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
294           {
295             syslog(LOG_WARNING, "ioctl(TIOCSETD): %m");
296           }
297         
298         if (ioctl(fd, TIOCNXCL, 0) < 0)
299           {
300             syslog (LOG_WARNING, "ioctl(TIOCNXCL): %m");
301           }
302       }
303     initdisc = -1;
304   }
305
306 /*
307  * clean_check - Fetch the flags for the device and generate
308  * appropriate error messages.
309  */
310 void clean_check(void)
311   {
312     if (still_ppp() && initdisc >= 0)
313       {
314         if (ioctl(ttyfd, PPPIOCGFLAGS, (caddr_t) &x) == 0)
315           {
316             s = NULL;
317             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP))
318               {
319               case SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP:
320                 s = "nothing was received";
321                 break;
322                 
323               case SC_RCV_B7_0:
324               case SC_RCV_B7_0 | SC_RCV_EVNP:
325               case SC_RCV_B7_0 | SC_RCV_ODDP:
326               case SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP:
327                 s = "all had bit 7 set to 1";
328                 break;
329                 
330               case SC_RCV_B7_1:
331               case SC_RCV_B7_1 | SC_RCV_EVNP:
332               case SC_RCV_B7_1 | SC_RCV_ODDP:
333               case SC_RCV_B7_1 | SC_RCV_ODDP | SC_RCV_EVNP:
334                 s = "all had bit 7 set to 0";
335                 break;
336                 
337               case SC_RCV_EVNP:
338                 s = "all had odd parity";
339                 break;
340                 
341               case SC_RCV_ODDP:
342                 s = "all had even parity";
343                 break;
344               }
345             
346             if (s != NULL)
347               {
348                 syslog(LOG_WARNING, "Receive serial link is not"
349                        " 8-bit clean:");
350                 syslog(LOG_WARNING, "Problem: %s", s);
351               }
352           }
353       }
354   }
355         
356
357 /*
358  * List of valid speeds.
359  */
360
361 struct speed {
362     int speed_int, speed_val;
363 } speeds[] = {
364 #ifdef B50
365     { 50, B50 },
366 #endif
367 #ifdef B75
368     { 75, B75 },
369 #endif
370 #ifdef B110
371     { 110, B110 },
372 #endif
373 #ifdef B134
374     { 134, B134 },
375 #endif
376 #ifdef B150
377     { 150, B150 },
378 #endif
379 #ifdef B200
380     { 200, B200 },
381 #endif
382 #ifdef B300
383     { 300, B300 },
384 #endif
385 #ifdef B600
386     { 600, B600 },
387 #endif
388 #ifdef B1200
389     { 1200, B1200 },
390 #endif
391 #ifdef B1800
392     { 1800, B1800 },
393 #endif
394 #ifdef B2000
395     { 2000, B2000 },
396 #endif
397 #ifdef B2400
398     { 2400, B2400 },
399 #endif
400 #ifdef B3600
401     { 3600, B3600 },
402 #endif
403 #ifdef B4800
404     { 4800, B4800 },
405 #endif
406 #ifdef B7200
407     { 7200, B7200 },
408 #endif
409 #ifdef B9600
410     { 9600, B9600 },
411 #endif
412 #ifdef B19200
413     { 19200, B19200 },
414 #endif
415 #ifdef B38400
416     { 38400, B38400 },
417 #endif
418 #ifdef EXTA
419     { 19200, EXTA },
420 #endif
421 #ifdef EXTB
422     { 38400, EXTB },
423 #endif
424 #ifdef B57600
425     { 57600, B57600 },
426 #endif
427 #ifdef B115200
428     { 115200, B115200 },
429 #endif
430     { 0, 0 }
431 };
432
433 /*
434  * Translate from bits/second to a speed_t.
435  */
436
437 static int translate_speed (int bps)
438   {
439     struct speed *speedp;
440
441     if (bps != 0)
442       {
443         for (speedp = speeds; speedp->speed_int; speedp++)
444           {
445             if (bps == speedp->speed_int)
446               {
447                 return speedp->speed_val;
448               }
449           }
450         syslog(LOG_WARNING, "speed %d not supported", bps);
451       }
452     return 0;
453   }
454
455 /*
456  * Translate from a speed_t to bits/second.
457  */
458
459 static int baud_rate_of (int speed)
460   {
461     struct speed *speedp;
462     
463     if (speed != 0)
464       {
465         for (speedp = speeds; speedp->speed_int; speedp++)
466           {
467             if (speed == speedp->speed_val)
468               {
469                 return speedp->speed_int;
470               }
471           }
472       }
473     return 0;
474   }
475
476 /*
477  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
478  * at the requested speed, etc.  If `local' is true, set CLOCAL
479  * regardless of whether the modem option was specified.
480  */
481
482 void set_up_tty (int fd, int local)
483   {
484     int speed, x;
485     struct termios tios;
486     
487     if (tcgetattr(fd, &tios) < 0)
488       {
489         syslog(LOG_ERR, "tcgetattr: %m");
490         die(1);
491       }
492     
493     if (!restore_term)
494       {
495         inittermios = tios;
496       }
497     
498     tios.c_cflag     &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
499     tios.c_cflag     |= CS8 | CREAD | HUPCL;
500
501     tios.c_iflag      = IGNBRK | IGNPAR;
502     tios.c_oflag      = 0;
503     tios.c_lflag      = 0;
504     tios.c_cc[VMIN]   = 1;
505     tios.c_cc[VTIME]  = 0;
506     
507     if (local || !modem)
508       {
509         tios.c_cflag ^= (CLOCAL | HUPCL);
510       }
511
512     switch (crtscts)
513       {
514     case 1:
515         tios.c_cflag |= CRTSCTS;
516         break;
517
518     case -2:
519         tios.c_iflag     |= IXON | IXOFF;
520         tios.c_cc[VSTOP]  = 0x13;       /* DC3 = XOFF = ^S */
521         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
522         break;
523
524     case -1:
525         tios.c_cflag &= ~CRTSCTS;
526         break;
527
528     default:
529         break;
530       }
531     
532     speed = translate_speed(inspeed);
533     if (speed)
534       {
535         cfsetospeed (&tios, speed);
536         cfsetispeed (&tios, speed);
537       }
538 /*
539  * We can't proceed if the serial port speed is B0,
540  * since that implies that the serial port is disabled.
541  */
542     else
543       {
544         speed = cfgetospeed(&tios);
545         if (speed == B0)
546           {
547             syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate",
548                    devnam);
549             die (1);
550           }
551       }
552
553     if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
554       {
555         syslog(LOG_ERR, "tcsetattr: %m");
556         die(1);
557       }
558     
559     baud_rate    = baud_rate_of(speed);
560     restore_term = TRUE;
561   }
562
563 /*
564  * setdtr - control the DTR line on the serial port.
565  * This is called from die(), so it shouldn't call die().
566  */
567
568 void setdtr (int fd, int on)
569   {
570     int modembits = TIOCM_DTR;
571
572     ioctl(fd, (on ? TIOCMBIS : TIOCMBIC), &modembits);
573   }
574
575 /*
576  * restore_tty - restore the terminal to the saved settings.
577  */
578
579 void restore_tty (int fd)
580   {
581     if (restore_term)
582       {
583         restore_term = 0;
584 /*
585  * Turn off echoing, because otherwise we can get into
586  * a loop with the tty and the modem echoing to each other.
587  * We presume we are the sole user of this tty device, so
588  * when we close it, it will revert to its defaults anyway.
589  */
590         if (!default_device)
591           {
592             inittermios.c_lflag &= ~(ECHO | ECHONL);
593           }
594         
595         if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
596           {
597             if (errno != EIO)
598               {
599                 syslog(LOG_WARNING, "tcsetattr: %m");
600               }
601           }
602       }
603   }
604
605 /*
606  * output - Output PPP packet.
607  */
608
609 void output (int unit, unsigned char *p, int len)
610   {
611     if (debug)
612       {
613         log_packet(p, len, "sent ");
614       }
615     
616     if (write(ttyfd, p, len) < 0)
617       {
618         if (errno == EWOULDBLOCK || errno == ENOBUFS
619             || errno == ENXIO || errno == EIO)
620           {
621             syslog(LOG_WARNING, "write: warning: %m");
622           } 
623         else
624           {
625             syslog(LOG_ERR, "write: %m");
626             die(1);
627           }
628       }
629   }
630
631 /*
632  * wait_input - wait until there is data available on ttyfd,
633  * for the length of time specified by *timo (indefinite
634  * if timo is NULL).
635  */
636
637 void wait_input (struct timeval *timo)
638   {
639     fd_set ready;
640     int n;
641     
642     FD_ZERO(&ready);
643     FD_SET(ttyfd, &ready);
644
645     n = select(ttyfd+1, &ready, NULL, &ready, timo);
646     if (n < 0 && errno != EINTR)
647       {
648         syslog(LOG_ERR, "select: %m");
649         die(1);
650       }
651   }
652
653 /*
654  * read_packet - get a PPP packet from the serial device.
655  */
656
657 int read_packet (unsigned char *buf)
658   {
659     int len;
660   
661     len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN);
662     if (len < 0)
663       {
664         if (errno == EWOULDBLOCK)
665           {
666             return -1;
667           }
668         syslog(LOG_ERR, "read: %m");
669         die(1);
670       }
671     return len;
672   }
673
674 /*
675  * ppp_send_config - configure the transmit characteristics of
676  * the ppp interface.
677  */
678
679 void ppp_send_config (int unit,int mtu,u_int32_t asyncmap,int pcomp,int accomp)
680   {
681     u_int x;
682     struct ifreq ifr;
683   
684     MAINDEBUG ((LOG_DEBUG, "send_config: mtu = %d\n", mtu));
685 /*
686  * Ensure that the link is still up.
687  */
688     if (still_ppp())
689       {
690 /*
691  * Set the MTU and other parameters for the ppp device
692  */
693         memset (&ifr, '\0', sizeof (ifr));
694         strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
695         ifr.ifr_mtu = mtu;
696         
697         if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
698           {
699             syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
700             quit();
701           }
702         
703         MAINDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
704         if (ioctl(ttyfd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0)
705           {
706             syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
707             quit();
708           }
709     
710         x = get_flags();
711         x = pcomp  ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
712         x = accomp ? x | SC_COMP_AC   : x & ~SC_COMP_AC;
713         set_flags(x);
714       }
715   }
716
717 /*
718  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
719  */
720
721 void ppp_set_xaccm (int unit, ext_accm accm)
722   {
723     MAINDEBUG ((LOG_DEBUG, "set_xaccm: %08lx %08lx %08lx %08lx\n",
724                 accm[0], accm[1], accm[2], accm[3]));
725
726     if (ioctl(ttyfd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
727       {
728         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
729       }
730   }
731
732 /*
733  * ppp_recv_config - configure the receive-side characteristics of
734  * the ppp interface.
735  */
736
737 void ppp_recv_config (int unit,int mru,u_int32_t asyncmap,int pcomp,int accomp)
738   {
739     u_int x;
740
741     MAINDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
742 /*
743  * If we were called because the link has gone down then there is nothing
744  * which may be done. Just return without incident.
745  */
746     if (!still_ppp())
747       {
748         return;
749       }
750 /*
751  * Set the receiver parameters
752  */
753     if (ioctl(ttyfd, PPPIOCSMRU, (caddr_t) &mru) < 0)
754       {
755         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
756       }
757
758     MAINDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
759     if (ioctl(ttyfd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0)
760       {
761         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
762         quit();
763       }
764
765     x = get_flags();
766     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
767     set_flags (x);
768   }
769
770 /*
771  * ccp_test - ask kernel whether a given compression method
772  * is acceptable for use.
773  */
774
775 int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
776   {
777     struct ppp_option_data data;
778
779     memset (&data, '\0', sizeof (data));
780     data.ptr      = opt_ptr;
781     data.length   = opt_len;
782     data.transmit = for_transmit;
783
784     if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
785       {
786         return 1;
787       }
788
789     return (errno == ENOBUFS)? 0: -1;
790   }
791
792 /*
793  * ccp_flags_set - inform kernel about the current state of CCP.
794  */
795
796 void ccp_flags_set (int unit, int isopen, int isup)
797   {
798     if (still_ppp())
799       {
800         int x = get_flags();
801         x = isopen? x | SC_CCP_OPEN : x &~ SC_CCP_OPEN;
802         x = isup?   x | SC_CCP_UP   : x &~ SC_CCP_UP;
803         set_flags (x);
804       }
805   }
806
807 /*
808  * ccp_fatal_error - returns 1 if decompression was disabled as a
809  * result of an error detected after decompression of a packet,
810  * 0 otherwise.  This is necessary because of patent nonsense.
811  */
812
813 int ccp_fatal_error (int unit)
814   {
815     int x = get_flags();
816
817     return x & SC_DC_FERROR;
818   }
819
820 /*
821  * sifvjcomp - config tcp header compression
822  */
823
824 int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
825   {
826     u_int x = get_flags();
827
828     if (vjcomp)
829       {
830         if (ioctl (ttyfd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0)
831           {
832             syslog (LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
833             vjcomp = 0;
834           }
835       }
836
837     x = vjcomp  ? x | SC_COMP_TCP     : x &~ SC_COMP_TCP;
838     x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
839     set_flags (x);
840
841     return 1;
842   }
843
844 /*
845  * sifup - Config the interface up and enable IP packets to pass.
846  */
847
848 int sifup (int u)
849   {
850     struct ifreq ifr;
851
852     memset (&ifr, '\0', sizeof (ifr));
853     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
854     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0)
855       {
856         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
857         return 0;
858       }
859
860     ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
861     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0)
862       {
863         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
864         return 0;
865       }
866     if_is_up = 1;
867     return 1;
868   }
869
870 /*
871  * sifdown - Config the interface down and disable IP.
872  */
873
874 int sifdown (int u)
875   {
876     struct ifreq ifr;
877
878     memset (&ifr, '\0', sizeof (ifr));
879     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
880     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0)
881       {
882         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
883         return 0;
884       }
885
886     ifr.ifr_flags &= ~IFF_UP;
887     ifr.ifr_flags |= IFF_POINTOPOINT;
888     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0)
889       {
890         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
891         return 0;
892       }
893     if_is_up = 0;
894     return 1;
895   }
896
897 /*
898  * sifaddr - Config the interface IP addresses and netmask.
899  */
900
901 int sifaddr (int unit, int our_adr, int his_adr, int net_mask)
902   {
903     struct ifreq   ifr; 
904     struct rtentry rt;
905     
906     memset (&ifr, '\0', sizeof (ifr));
907     memset (&rt,  '\0', sizeof (rt));
908     
909     SET_SA_FAMILY (ifr.ifr_addr,    AF_INET); 
910     SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET); 
911     SET_SA_FAMILY (ifr.ifr_netmask, AF_INET); 
912
913     strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
914 /*
915  *  Set our IP address
916  */
917     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = our_adr;
918     if (ioctl(sockfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
919       {
920         if (errno != EEXIST)
921           {
922             syslog (LOG_ERR, "ioctl(SIOCAIFADDR): %m");
923           }
924         else
925           {
926             syslog (LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
927           }
928         return (0);
929       } 
930 /*
931  *  Set the gateway address
932  */
933     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = his_adr;
934     if (ioctl(sockfd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0)
935       {
936         syslog (LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m"); 
937         return (0);
938       } 
939 /*
940  *  Set the netmask
941  */
942     if (net_mask != 0)
943       {
944         ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = net_mask;
945         if (ioctl(sockfd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0)
946           {
947             syslog (LOG_ERR, "ioctl(SIOCSIFNETMASK): %m"); 
948             return (0);
949           } 
950       }
951 /*
952  *  Add the device route
953  */
954     SET_SA_FAMILY (rt.rt_dst,     AF_INET);
955     SET_SA_FAMILY (rt.rt_gateway, AF_INET);
956     rt.rt_dev = ifname;  /* MJC */
957
958     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0L;
959     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr     = his_adr;
960     rt.rt_flags = RTF_UP | RTF_HOST;
961
962     if (ioctl(sockfd, SIOCADDRT, &rt) < 0)
963       {
964         syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m");
965         return (0);
966       }
967
968     ipaddrs[0] = our_adr;
969     ipaddrs[1] = his_adr;
970     return 1;
971   }
972
973 /*
974  * cifaddr - Clear the interface IP addresses, and delete routes
975  * through the interface if possible.
976  */
977
978 int cifaddr (int unit, int our_adr, int his_adr)
979   {
980     struct rtentry rt;
981
982     ipaddrs[0] = 0;
983 /*
984  *  Delete the route through the device
985  */
986     memset (&rt, '\0', sizeof (rt));
987
988     SET_SA_FAMILY (rt.rt_dst,     AF_INET);
989     SET_SA_FAMILY (rt.rt_gateway, AF_INET);
990     rt.rt_dev = ifname;  /* MJC */
991
992     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
993     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr     = his_adr;
994     rt.rt_flags = RTF_UP | RTF_HOST;
995
996     if (ioctl(sockfd, SIOCDELRT, &rt) < 0 && errno != ESRCH)
997       {
998         if (still_ppp())
999           {
1000             syslog (LOG_ERR, "ioctl(SIOCDELRT) device route: %m");
1001             return (0);
1002           }
1003       }
1004     return 1;
1005   }
1006
1007 /*
1008  * path_to_route - determine the path to the proc file system data
1009  */
1010
1011 FILE *route_fd = (FILE *) 0;
1012 static char route_buffer [512];
1013
1014 static char *path_to_route (void);
1015 static int open_route_table (void);
1016 static void close_route_table (void);
1017 static int read_route_table (struct rtentry *rt);
1018 static int defaultroute_exists (void);
1019
1020 /*
1021  * path_to_route - find the path to the route tables in the proc file system
1022  */
1023
1024 static char *path_to_route (void)
1025   {
1026     struct mntent *mntent;
1027     FILE *fp;
1028
1029     fp = fopen (MOUNTED, "r");
1030     if (fp != 0)
1031       {
1032         mntent = getmntent (fp);
1033         while (mntent != (struct mntent *) 0)
1034           {
1035             if (strcmp (mntent->mnt_type, MNTTYPE_IGNORE) != 0)
1036               {
1037                 if (strcmp (mntent->mnt_type, "proc") == 0)
1038                   {
1039                     strncpy (route_buffer, mntent->mnt_dir,
1040                              sizeof (route_buffer)-10);
1041                     route_buffer [sizeof (route_buffer)-10] = '\0';
1042                     strcat (route_buffer, "/net/route");
1043                     
1044                     fclose (fp);
1045                     return (route_buffer);
1046                   }
1047               }
1048             mntent = getmntent (fp);
1049           }
1050         fclose (fp);
1051       }
1052
1053     syslog (LOG_ERR, "proc file system not mounted");
1054     return 0;
1055   }
1056
1057 /*
1058  * close_route_table - close the interface to the route table
1059  */
1060
1061 static void close_route_table (void)
1062   {
1063     if (route_fd != (FILE *) 0)
1064       {
1065         fclose (route_fd);
1066         route_fd = (FILE *) 0;
1067       }
1068   }
1069
1070 /*
1071  * open_route_table - open the interface to the route table
1072  */
1073
1074 static int open_route_table (void)
1075   {
1076     char *path;
1077
1078     close_route_table();
1079
1080     path = path_to_route();
1081     if (path == NULL)
1082       {
1083         return 0;
1084       }
1085
1086     route_fd = fopen (path, "r");
1087     if (route_fd == (FILE *) 0)
1088       {
1089         syslog (LOG_ERR, "can not open %s: %m", path);
1090         return 0;
1091       }
1092     return 1;
1093   }
1094
1095 /*
1096  * read_route_table - read the next entry from the route table
1097  */
1098
1099 static int read_route_table (struct rtentry *rt)
1100   {
1101     static char delims[] = " \t\n";
1102     char *dev_ptr, *ptr, *dst_ptr, *gw_ptr, *flag_ptr;
1103         
1104     memset (rt, '\0', sizeof (struct rtentry));
1105
1106     for (;;)
1107       {
1108         if (fgets (route_buffer, sizeof (route_buffer), route_fd) ==
1109             (char *) 0)
1110           {
1111             return 0;
1112           }
1113
1114         dev_ptr  = strtok (route_buffer, delims); /* interface name */
1115         dst_ptr  = strtok (NULL,         delims); /* destination address */
1116         gw_ptr   = strtok (NULL,         delims); /* gateway */
1117         flag_ptr = strtok (NULL,         delims); /* flags */
1118     
1119         if (flag_ptr == (char *) 0) /* assume that we failed, somewhere. */
1120           {
1121             return 0;
1122           }
1123         
1124         /* Discard that stupid header line which should never
1125          * have been there in the first place !! */
1126         if (isxdigit (*dst_ptr) && isxdigit (*gw_ptr) && isxdigit (*flag_ptr))
1127           {
1128             break;
1129           }
1130       }
1131
1132     ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr =
1133       strtoul (dst_ptr, NULL, 16);
1134
1135     ((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr =
1136       strtoul (gw_ptr, NULL, 16);
1137
1138     rt->rt_flags = (short) strtoul (flag_ptr, NULL, 16);
1139     rt->rt_dev   = dev_ptr;
1140
1141     return 1;
1142   }
1143
1144 /*
1145  * defaultroute_exists - determine if there is a default route
1146  */
1147
1148 static int defaultroute_exists (void)
1149   {
1150     struct rtentry rt;
1151     int    result = 0;
1152
1153     if (!open_route_table())
1154       {
1155         return 0;
1156       }
1157
1158     while (read_route_table(&rt) != 0)
1159       {
1160         if ((rt.rt_flags & RTF_UP) == 0)
1161           {
1162             continue;
1163           }
1164
1165         if (((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr == 0L)
1166           {
1167             syslog (LOG_ERR,
1168                     "ppp not replacing existing default route to %s[%s]",
1169                     rt.rt_dev,
1170                     inet_ntoa (((struct sockaddr_in *) &rt.rt_gateway)->
1171                                sin_addr.s_addr));
1172             result = 1;
1173             break;
1174           }
1175       }
1176
1177     close_route_table();
1178     return result;
1179   }
1180
1181 /*
1182  * sifdefaultroute - assign a default route through the address given.
1183  */
1184
1185 int sifdefaultroute (int unit, int gateway)
1186   {
1187     struct rtentry rt;
1188
1189     if (has_default_route == 0)
1190       {
1191         if (defaultroute_exists())
1192           {
1193             return 0;
1194           }
1195
1196         memset (&rt, '\0', sizeof (rt));
1197         SET_SA_FAMILY (rt.rt_dst,     AF_INET);
1198         SET_SA_FAMILY (rt.rt_gateway, AF_INET);
1199         ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway;
1200     
1201         rt.rt_flags = RTF_UP | RTF_GATEWAY;
1202         if (ioctl(sockfd, SIOCADDRT, &rt) < 0)
1203           {
1204             syslog (LOG_ERR, "default route ioctl(SIOCADDRT): %m");
1205             return 0;
1206           }
1207       }
1208     has_default_route = 1;
1209     default_route_gateway = g;
1210     return 1;
1211   }
1212
1213 /*
1214  * cifdefaultroute - delete a default route through the address given.
1215  */
1216
1217 int cifdefaultroute (int unit, int gateway)
1218   {
1219     struct rtentry rt;
1220
1221     if (has_default_route)
1222       {
1223         memset (&rt, '\0', sizeof (rt));
1224         SET_SA_FAMILY (rt.rt_dst,     AF_INET);
1225         SET_SA_FAMILY (rt.rt_gateway, AF_INET);
1226         ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway;
1227     
1228         rt.rt_flags = RTF_UP | RTF_GATEWAY;
1229         if (ioctl(sockfd, SIOCDELRT, &rt) < 0 && errno != ESRCH)
1230           {
1231             if (still_ppp())
1232               {
1233                 syslog (LOG_ERR, "default route ioctl(SIOCDELRT): %m");
1234                 return 0;
1235               }
1236           }
1237       }
1238     has_default_route = 0;
1239     return 1;
1240   }
1241
1242 /*
1243  * sifproxyarp - Make a proxy ARP entry for the peer.
1244  */
1245
1246 int sifproxyarp (int unit, u_int32_t his_adr)
1247   {
1248     struct arpreq arpreq;
1249
1250     if (has_proxy_arp == 0)
1251       {
1252         memset (&arpreq, '\0', sizeof(arpreq));
1253 /*
1254  * Get the hardware address of an interface on the same subnet
1255  * as our local address.
1256  */
1257         if (!get_ether_addr(his_adr, &arpreq.arp_ha))
1258           {
1259             syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
1260             return 0;
1261           }
1262     
1263         SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1264         ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
1265         arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1266         
1267         if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0)
1268           {
1269             syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
1270             return 0;
1271           }
1272       }
1273
1274     proxy_arp_addr = hisaddr;
1275     has_proxy_arp = 1;
1276     return 1;
1277   }
1278
1279 /*
1280  * cifproxyarp - Delete the proxy ARP entry for the peer.
1281  */
1282
1283 int cifproxyarp (int unit, u_int32_t his_adr)
1284   {
1285     struct arpreq arpreq;
1286
1287     if (has_proxy_arp == 1)
1288       {
1289         memset (&arpreq, '\0', sizeof(arpreq));
1290         SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1291     
1292         ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
1293         if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0)
1294           {
1295             syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
1296             return 0;
1297           }
1298       }
1299     has_proxy_arp = 0;
1300     return 1;
1301   }
1302      
1303 /*
1304  * get_ether_addr - get the hardware address of an interface on the
1305  * the same subnet as ipaddr.
1306  */
1307
1308 static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr)
1309   {
1310     struct ifreq *ifr, *ifend, *ifp;
1311     int i;
1312     u_int32_t ina, mask;
1313     struct sockaddr_dl *dla;
1314     struct ifreq ifreq;
1315     struct ifconf ifc;
1316     struct ifreq ifs[MAX_IFS];
1317     
1318     ifc.ifc_len = sizeof(ifs);
1319     ifc.ifc_req = ifs;
1320     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
1321       {
1322         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
1323         return 0;
1324       }
1325
1326     MAINDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
1327                 ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
1328 /*
1329  * Scan through looking for an interface with an Internet
1330  * address on the same subnet as `ipaddr'.
1331  */
1332     ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
1333     for (ifr = ifc.ifc_req; ifr < ifend; ifr++)
1334       {
1335         if (ifr->ifr_addr.sa_family == AF_INET)
1336           {
1337             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1338             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1339             MAINDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
1340                         ifreq.ifr_name));
1341 /*
1342  * Check that the interface is up, and not point-to-point
1343  * nor loopback.
1344  */
1345             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1346               {
1347                 continue;
1348               }
1349
1350             if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
1351               {
1352                 continue;
1353               }
1354 /*
1355  * Get its netmask and check that it's on the right subnet.
1356  */
1357             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1358               {
1359                 continue;
1360               }
1361
1362             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1363             MAINDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
1364                         ip_ntoa(ina), ntohl(mask)));
1365
1366             if (((ipaddr ^ ina) & mask) != 0)
1367               {
1368                 continue;
1369               }
1370             break;
1371           }
1372       }
1373     
1374     if (ifr >= ifend)
1375       {
1376         return 0;
1377       }
1378
1379     syslog(LOG_INFO, "found interface %s for proxy arp", ifreq.ifr_name);
1380 /*
1381  * Now get the hardware address.
1382  */
1383     memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
1384     if (ioctl (sockfd, SIOCGIFHWADDR, &ifreq) < 0)
1385       {
1386         syslog(LOG_ERR, "SIOCGIFHWADDR(%s): %m", ifreq.ifr_name);
1387         return 0;
1388       }
1389
1390     memcpy (hwaddr,
1391             &ifreq.ifr_hwaddr,
1392             sizeof (struct sockaddr));
1393
1394     MAINDEBUG ((LOG_DEBUG,
1395            "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1396                 (int) ((unsigned char *) &hwaddr->sa_data)[0],
1397                 (int) ((unsigned char *) &hwaddr->sa_data)[1],
1398                 (int) ((unsigned char *) &hwaddr->sa_data)[2],
1399                 (int) ((unsigned char *) &hwaddr->sa_data)[3],
1400                 (int) ((unsigned char *) &hwaddr->sa_data)[4],
1401                 (int) ((unsigned char *) &hwaddr->sa_data)[5],
1402                 (int) ((unsigned char *) &hwaddr->sa_data)[6],
1403                 (int) ((unsigned char *) &hwaddr->sa_data)[7]));
1404     return 1;
1405   }
1406
1407 /*
1408  * Return user specified netmask, modified by any mask we might determine
1409  * for address `addr' (in network byte order).
1410  * Here we scan through the system's list of interfaces, looking for
1411  * any non-point-to-point interfaces which might appear to be on the same
1412  * network as `addr'.  If we find any, we OR in their netmask to the
1413  * user-specified netmask.
1414  */
1415
1416 u_int32_t GetMask (u_int32_t addr)
1417   {
1418     u_int32_t mask, nmask, ina;
1419     struct ifreq *ifr, *ifend, ifreq;
1420     struct ifconf ifc;
1421     struct ifreq ifs[MAX_IFS];
1422
1423     addr = ntohl(addr);
1424     
1425     if (IN_CLASSA(addr))        /* determine network mask for address class */
1426       {
1427         nmask = IN_CLASSA_NET;
1428       }
1429     else
1430       {
1431         if (IN_CLASSB(addr))
1432           {
1433             nmask = IN_CLASSB_NET;
1434           }
1435         else
1436           {
1437             nmask = IN_CLASSC_NET;
1438           }
1439       }
1440     
1441     /* class D nets are disallowed by bad_ip_adrs */
1442     mask = netmask | htonl(nmask);
1443 /*
1444  * Scan through the system's network interfaces.
1445  */
1446     ifc.ifc_len = sizeof(ifs);
1447     ifc.ifc_req = ifs;
1448     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
1449       {
1450         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1451         return mask;
1452       }
1453     
1454     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1455     for (ifr = ifc.ifc_req; ifr < ifend; ifr++)
1456       {
1457 /*
1458  * Check the interface's internet address.
1459  */
1460         if (ifr->ifr_addr.sa_family != AF_INET)
1461           {
1462             continue;
1463           }
1464         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1465         if (((ntohl(ina) ^ addr) & nmask) != 0)
1466           {
1467             continue;
1468           }
1469 /*
1470  * Check that the interface is up, and not point-to-point nor loopback.
1471  */
1472         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1473         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1474           {
1475             continue;
1476           }
1477         
1478         if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
1479           {
1480             continue;
1481           }
1482 /*
1483  * Get its netmask and OR it into our mask.
1484  */
1485         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1486           {
1487             continue;
1488           }
1489         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1490         break;
1491       }
1492     return mask;
1493   }
1494
1495 /*
1496  * Internal routine to decode the version.modification.patch level
1497  */
1498
1499 static void decode_version (char *buf, int *version,
1500                             int *modification, int *patch)
1501   {
1502     *version      = (int) strtoul (buf, &buf, 10);
1503     *modification = 0;
1504     *patch        = 0;
1505     
1506     if (*buf == '.')
1507       {
1508         ++buf;
1509         *modification = (int) strtoul (buf, &buf, 10);
1510         if (*buf == '.')
1511           {
1512             ++buf;
1513             *patch = (int) strtoul (buf, &buf, 10);
1514           }
1515       }
1516     
1517     if (*buf != '\0')
1518       {
1519         *version      =
1520         *modification =
1521         *patch        = 0;
1522       }
1523   }
1524
1525 /*
1526  * Procedure to determine if the PPP line dicipline is registered.
1527  */
1528
1529 int
1530 ppp_registered(void)
1531   {
1532     int local_fd;
1533     int ppp_disc  = N_PPP;
1534     int init_disc = -1;
1535     int initfdflags;
1536
1537     local_fd = open(devnam, O_NONBLOCK | O_RDWR, 0);
1538     if (local_fd < 0)
1539       {
1540         syslog(LOG_ERR, "Failed to open %s: %m", devnam);
1541         return 0;
1542       }
1543
1544     initfdflags = fcntl(local_fd, F_GETFL);
1545     if (initfdflags == -1)
1546       {
1547         syslog(LOG_ERR, "Couldn't get device fd flags: %m");
1548         close (local_fd);
1549         return 0;
1550       }
1551
1552     initfdflags &= ~O_NONBLOCK;
1553     fcntl(local_fd, F_SETFL, initfdflags);
1554 /*
1555  * Read the initial line dicipline and try to put the device into the
1556  * PPP dicipline.
1557  */
1558     if (ioctl(local_fd, TIOCGETD, &init_disc) < 0)
1559       {
1560         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
1561         close (local_fd);
1562         return 0;
1563       }
1564     
1565     if (ioctl(local_fd, TIOCSETD, &ppp_disc) < 0)
1566       {
1567         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
1568         close (local_fd);
1569         return 0;
1570       }
1571     
1572     if (ioctl(local_fd, TIOCSETD, &init_disc) < 0)
1573       {
1574         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
1575         close (local_fd);
1576         return 0;
1577       }
1578     
1579     close (local_fd);
1580     return 1;
1581   }
1582
1583 /*
1584  * ppp_available - check whether the system has any ppp interfaces
1585  * (in fact we check whether we can do an ioctl on ppp0).
1586  */
1587
1588 int ppp_available(void)
1589   {
1590     int s, ok;
1591     struct ifreq ifr;
1592     char   abBuffer [1024];
1593     int    size;
1594     int    my_version, my_modification, my_patch;
1595 /*
1596  * Open a socket for doing the ioctl operations.
1597  */    
1598     s = socket(AF_INET, SOCK_DGRAM, 0);
1599     if (s < 0)
1600       {
1601         return 0;
1602       }
1603     
1604     strncpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
1605     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
1606 /*
1607  * If the device did not exist then attempt to create one by putting the
1608  * current tty into the PPP discipline. If this works then obtain the
1609  * flags for the device again.
1610  */
1611     if (!ok)
1612       {
1613         if (ppp_registered())
1614           {
1615             strncpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
1616             ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
1617           }
1618       }
1619 /*
1620  * Ensure that the hardware address is for PPP and not something else
1621  */
1622     if (ok)
1623       {
1624         ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
1625       }
1626
1627     if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
1628       {
1629         ok = 0;
1630       }
1631
1632     if (!ok)
1633       {
1634         return 0;
1635       }
1636 /*
1637  *  This is the PPP device. Validate the version of the driver at this
1638  *  point to ensure that this program will work with the driver.
1639  */
1640     ifr.ifr_data = abBuffer;
1641     size = ioctl (s, SIOCGPPPVER, (caddr_t) &ifr);
1642     ok   = size >= 0;
1643
1644     if (ok)
1645       {
1646         decode_version (abBuffer,
1647                         &driver_version,
1648                         &driver_modification,
1649                         &driver_patch);
1650       }
1651     
1652     if (!ok)
1653       {
1654         driver_version      =
1655         driver_modification =
1656         driver_patch        = 0;
1657       }
1658 /*
1659  * Validate the version of the driver against the version that we used.
1660  */
1661     decode_version (PPP_VERSION,
1662                     &my_version,
1663                     &my_modification,
1664                     &my_patch);
1665
1666     /* The version numbers must match */
1667     if (driver_version != my_version)
1668       {
1669         ok = 0;
1670       }
1671       
1672     /* The modification levels must be legal */
1673     if (driver_modification < my_modification)
1674       {
1675         ok = 0;
1676       }
1677
1678     if (!ok)
1679       {
1680         fprintf(stderr, "Sorry - PPP driver version %d.%d.%d is out of date\n",
1681                 driver_version, driver_modification, driver_patch);
1682         close (s);
1683         exit (1);
1684       }
1685     
1686     close(s);
1687     return ok;
1688   }
1689
1690 /*
1691  * Update the wtmp file with the appropriate user name and tty device.
1692  */
1693
1694 int logwtmp (char *line, char *name, char *host)
1695   {
1696     struct utmp ut;
1697     int    mode;
1698 /*
1699  * Control the 'mesg' function based upon the state of the logon
1700  * operation.
1701  */
1702     mode = (*name != '\0') ? 0600 : 0622;
1703     if (chmod (devnam, mode) < 0)
1704       {
1705         syslog (LOG_ERR, "chmod(\"%s\", 0%o): %m", devnam, mode);
1706       }
1707 /*
1708  * Update the signon database for users.
1709  */
1710     memset (&ut, 0, sizeof (ut));
1711     (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
1712     (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
1713     (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
1714     (void)time(&ut.ut_time);
1715         
1716     pututline (&ut);            /* Write the line to the proper place */
1717     endutent();                 /* Indicate operation is complete */
1718   }
1719
1720 /*
1721  * Code for locking/unlocking the serial device.
1722  * This code is derived from chat.c.
1723  */
1724
1725 #define LOCK_PREFIX     "/var/lock/LCK.."
1726
1727 /*
1728  * lock - create a lock file for the named device
1729  */
1730
1731 int lock (char *dev)
1732   {
1733     char hdb_lock_buffer[12];
1734     int fd, pid, n;
1735     char *p;
1736
1737     p = strrchr(dev, '/');
1738     if (p != NULL)
1739       {
1740         dev = ++p;
1741       }
1742
1743     lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
1744     if (lock_file == NULL)
1745       {
1746         novm("lock file name");
1747       }
1748
1749     strcpy (lock_file, LOCK_PREFIX);
1750     strcat (lock_file, dev);
1751 /*
1752  * Attempt to create the lock file at this point.
1753  */
1754     while (1)
1755       {
1756         fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644);
1757         if (fd >= 0)
1758           {
1759             sprintf(hdb_lock_buffer, "%010d\n", getpid());
1760             write(fd, hdb_lock_buffer, 11);
1761             close(fd);
1762             return 0;
1763           }
1764 /*
1765  * If the file exists then check to see if the pid is stale
1766  */
1767         if (errno == EEXIST)
1768           {
1769             fd = open(lock_file, O_RDONLY, 0);
1770             if (fd < 0)
1771               {
1772                 if (errno == ENOENT) /* This is just a timing problem. */
1773                   {
1774                     continue;
1775                   }
1776                 break;
1777               }
1778
1779             /* Read the lock file to find out who has the device locked */
1780             n = read (fd, hdb_lock_buffer, 11);
1781             close (fd);
1782             if (n < 0)
1783               {
1784                 syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
1785                 break;
1786               }
1787
1788             /* See the process still exists. */
1789             if (n > 0)
1790               {
1791                 hdb_lock_buffer[n] = '\0';
1792                 sscanf (hdb_lock_buffer, " %d", &pid);
1793                 if (kill(pid, 0) == -1 && errno == ESRCH)
1794                   {
1795                     n = 0;
1796                   }
1797               }
1798
1799             /* If the process does not exist then try to remove the lock */
1800             if (n == 0 && unlink (lock_file) == 0)
1801               {
1802                 syslog (LOG_NOTICE, "Removed stale lock on %s (pid %d)",
1803                         dev, pid);
1804                 continue;
1805               }
1806
1807             syslog (LOG_NOTICE, "Device %s is locked by pid %d", dev, pid);
1808             break;
1809           }
1810
1811         syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
1812         break;
1813       }
1814
1815     free(lock_file);
1816     lock_file = NULL;
1817     return -1;
1818 }
1819
1820 /*
1821  * unlock - remove our lockfile
1822  */
1823
1824 void unlock(void)
1825   {
1826     if (lock_file)
1827       {
1828         unlink(lock_file);
1829         free(lock_file);
1830         lock_file = NULL;
1831       }
1832   }