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