www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / userapps / opensource / ppp / pppoecd / 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 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/time.h>
25 #include <sys/errno.h>
26 #include <sys/file.h>
27 #include <sys/stat.h>
28 #include <sys/utsname.h>
29 #include <sys/sysmacros.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 #include <termios.h>
43 #include <unistd.h>
44 #include <syscall.h>
45
46 /* This is in netdevice.h. However, this compile will fail miserably if
47    you attempt to include netdevice.h because it has so many references
48    to __memcpy functions which it should not attempt to do. So, since I
49    really don't use it, but it must be defined, define it now. */
50
51 #ifndef MAX_ADDR_LEN
52 #define MAX_ADDR_LEN 7
53 #endif
54
55 #if __GLIBC__ >= 2
56 #include <asm/types.h>          /* glibc 2 conflicts with linux/types.h */
57 #include <net/if.h>
58 #include <net/if_arp.h>
59 #include <net/route.h>
60 #include <netinet/if_ether.h>
61 #else
62 #include <linux/types.h>
63 #include <linux/if.h>
64 #include <linux/if_arp.h>
65 #include <linux/route.h>
66 #include <linux/if_ether.h>
67 #endif
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70
71 #include <linux/ppp_defs.h>
72 #include <linux/if_ppp.h>
73
74 #include "pppd.h"
75 #include "fsm.h"
76 #include "ipcp.h"
77
78 /* We can get an EIO error on an ioctl if the modem has hung up */
79 #define ok_error(num) ((num)==EIO)
80
81 static int tty_disc = N_TTY;    /* The TTY discipline */
82 static int initfdflags = -1;    /* Initial file descriptor flags for fd */
83 static int ppp_fd = -1;         /* fd which is set to PPP discipline */
84 static int sock_fd = -1;        /* socket for doing interface ioctls */
85 static int slave_fd = -1;
86 static int master_fd = -1;
87 static int ppp_dev_fd = -1;     /* fd for /dev/ppp (new style driver) */
88 static int chindex;             /* channel index (new style driver) */
89
90 static fd_set in_fds;           /* set of fds that wait_input waits for */
91 static int max_in_fd;           /* highest fd set in in_fds */
92
93 static int driver_version      = 0;
94 static int driver_modification = 0;
95 static int driver_patch        = 0;
96
97 static int      if_is_up;       /* Interface has been marked up */
98 static u_int32_t our_old_addr;          /* for detecting address changes */
99 static int      dynaddr_set;            /* 1 if ip_dynaddr set */
100 static const int        looped = 0;                     /* 1 if using loop */
101
102 static int kernel_version;
103 #define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p))
104
105 #define MAX_IFS         100
106
107 #define FLAGS_GOOD (IFF_UP          | IFF_BROADCAST)
108 #define FLAGS_MASK (IFF_UP          | IFF_BROADCAST | \
109                     IFF_POINTOPOINT | IFF_LOOPBACK  | IFF_NOARP)
110
111 #define SIN_ADDR(x)     (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr)
112
113 /* Prototypes for procedures local to this file. */
114 static int get_flags (int fd);
115 static void set_flags (int fd, int flags);
116 static int make_ppp_unit(void);
117
118 extern u_char   inpacket_buf[]; /* borrowed from main.c */
119
120 /*
121  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
122  * if it exists.
123  */
124
125 #define SET_SA_FAMILY(addr, family)                     \
126     memset ((char *) &(addr), '\0', sizeof(addr));      \
127     addr.sa_family = (family);
128
129 /*
130  * Determine if the PPP connection should still be present.
131  */
132
133 extern int hungup;
134
135 /* new_fd is the fd of a tty */
136 static void set_ppp_fd (int new_fd)
137 {
138         SYSDEBUG ((LOG_DEBUG, "setting ppp_fd to %d\n", new_fd));
139         ppp_fd = new_fd;
140         if (!new_style_driver)
141                 ppp_dev_fd = new_fd;
142 }
143
144 static int still_ppp(void)
145 {
146         if (new_style_driver)
147                 return !hungup && ppp_fd >= 0;
148         if (!hungup || ppp_fd == slave_fd)
149                 return 1;
150         if (slave_fd >= 0) {
151                 set_ppp_fd(slave_fd);
152                 return 1;
153         }
154         return 0;
155 }
156
157 /********************************************************************
158  *
159  * Functions to read and set the flags value in the device driver
160  */
161
162 static int get_flags (int fd)
163 {
164     int flags;
165
166     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
167         if ( ok_error (errno) )
168             flags = 0;
169         else
170             fatal("ioctl(PPPIOCGFLAGS): %m");
171     }
172
173     SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
174     return flags;
175 }
176
177 /********************************************************************/
178
179 static void set_flags (int fd, int flags)
180 {
181     SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
182
183     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
184         if (! ok_error (errno) )
185             fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno);
186     }
187 }
188
189 /********************************************************************
190  *
191  * sys_init - System-dependent initialization.
192  */
193
194 void sys_init(void)
195 {
196     int flags;
197
198     if (new_style_driver) {
199         ppp_dev_fd = open("/dev/ppp", O_RDWR);
200         if (ppp_dev_fd < 0)
201             fatal("Couldn't open /dev/ppp: %m");
202         flags = fcntl(ppp_dev_fd, F_GETFL);
203         if (flags == -1
204             || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
205             warn("Couldn't set /dev/ppp to nonblock: %m");
206     }
207
208     /* Get an internet socket for doing socket ioctls. */
209     sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
210     if (sock_fd < 0)
211         fatal("Couldn't create IP socket: %m(%d)", errno);
212
213     FD_ZERO(&in_fds);
214     max_in_fd = 0;
215 }
216
217 /********************************************************************
218  *
219  * sys_cleanup - restore any system state we modified before exiting:
220  * mark the interface down, delete default route and/or proxy arp entry.
221  * This shouldn't call die() because it's called from die().
222  */
223
224 void sys_cleanup(void)
225 {
226 /*
227  * Take down the device
228  */
229     if (if_is_up) {
230         if_is_up = 0;
231         sifdown(0);
232     }
233 }
234
235 /********************************************************************
236  *
237  * sys_close - Clean up in a child process before execing.
238  */
239 void
240 sys_close(void)
241 {
242         close(ppp_dev_fd);
243     if (sock_fd >= 0)
244         close(sock_fd);
245     if (slave_fd >= 0)
246         close(slave_fd);
247     if (master_fd >= 0)
248         close(master_fd);
249     closelog();
250 }
251
252 /********************************************************************
253  *
254  * set_kdebugflag - Define the debugging level for the kernel
255  */
256
257 static int set_kdebugflag (int requested_level)
258 {
259     if (new_style_driver && ifunit < 0)
260         return 1;
261     if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
262         if ( ! ok_error (errno) )
263             error("ioctl(PPPIOCSDEBUG): %m");
264         return (0);
265     }
266     SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d",
267                 requested_level));
268     return (1);
269 }
270
271
272 /********************************************************************
273  *
274  * generic_establish_ppp - Turn the fd into a ppp interface.
275  */
276 int generic_establish_ppp (int fd)
277 {
278     int x;
279 /*
280  * Demand mode - prime the old ppp device to relinquish the unit.
281  */
282     if (!new_style_driver && looped
283         && ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
284         error("ioctl(transfer ppp unit): %m");
285         return -1;
286     }
287
288
289     if (new_style_driver) {
290         /* Open another instance of /dev/ppp and connect the channel to it */
291         int flags;
292
293         if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) {
294             error("Couldn't get channel number: %m");
295             goto err;
296         }
297         dbglog("using channel %d", chindex);
298         fd = open("/dev/ppp", O_RDWR);
299         if (fd < 0) {
300             error("Couldn't reopen /dev/ppp: %m");
301             goto err;
302         }
303         if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
304             error("Couldn't attach to channel %d: %m", chindex);
305             goto err_close;
306         }
307         flags = fcntl(fd, F_GETFL);
308         if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
309             warn("Couldn't set /dev/ppp (channel) to nonblock: %m");
310         set_ppp_fd(fd);
311
312         if (!looped)
313             ifunit = -1;
314         if (!looped && !multilink) {
315             /*
316              * Create a new PPP unit.
317              */
318             if (make_ppp_unit() < 0)
319                 goto err_close;
320         }
321
322         if (looped)
323             set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
324
325         if (!multilink) {
326             add_fd(ppp_dev_fd);
327             if (ioctl(fd, PPPIOCCONNECT, &ifunit) < 0) {
328                 error("Couldn't attach to PPP unit %d: %m", ifunit);
329                 goto err_close;
330             }
331         }
332
333     } else {
334
335         /*
336          * Old-style driver: find out which interface we were given.
337          */
338         set_ppp_fd (fd);
339         if (ioctl(fd, PPPIOCGUNIT, &x) < 0) {
340             if (ok_error (errno))
341                 goto err;
342             fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
343         }
344         /* Check that we got the same unit again. */
345         if (looped && x != ifunit)
346             fatal("transfer_ppp failed: wanted unit %d, got %d", ifunit, x);
347         ifunit = x;
348
349         /*
350          * Fetch the initial file flags and reset blocking mode on the file.
351          */
352         initfdflags = fcntl(fd, F_GETFL);
353         if (initfdflags == -1 ||
354             fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
355             if ( ! ok_error (errno))
356                 warn("Couldn't set device to non-blocking mode: %m");
357         }
358     }
359
360
361     /*
362      * Enable debug in the driver if requested.
363      */
364     if (!looped)
365         set_kdebugflag (kdebugflag);
366
367     SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
368             driver_version, driver_modification, driver_patch));
369
370     return ppp_fd;
371
372  err_close:
373     close(fd);
374  err:
375     if (ioctl(fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
376         warn("Couldn't reset tty to normal line discipline: %m");
377     return -1;
378 }
379
380 /********************************************************************
381  *
382  * generic_disestablish_ppp - Restore device components to normal
383  * operation, and reconnect the ppp unit to the loopback if in demand
384  * mode.  This shouldn't call die() because it's called from die().
385 */
386 void generic_disestablish_ppp(int dev_fd){
387     /* Finally detach the device */
388     initfdflags = -1;
389
390     if (new_style_driver) {
391         close(ppp_fd);
392         ppp_fd = -1;
393         if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
394             error("Couldn't release PPP unit: %m");
395         if (!multilink)
396             remove_fd(ppp_dev_fd);
397     }
398 }
399
400 /*
401  * make_ppp_unit - make a new ppp unit for ppp_dev_fd.
402  * Assumes new_style_driver.
403  */
404 static int make_ppp_unit()
405 {
406         int x;
407
408         ifunit = req_unit;
409         x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
410         if (x < 0 && req_unit >= 0 && errno == EEXIST) {
411                 warn("Couldn't allocate PPP unit %d as it is already in use");
412                 ifunit = -1;
413                 x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
414         }
415         if (x < 0)
416                 error("Couldn't create new ppp unit: %m");
417         return x;
418 }
419
420 /********************************************************************
421  *
422  * clean_check - Fetch the flags for the device and generate
423  * appropriate error messages.
424  */
425 void clean_check(void)
426 {
427     int x;
428     char *s;
429
430     if (still_ppp()) {
431         if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
432             s = NULL;
433             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
434             case SC_RCV_B7_0:
435                 s = "all had bit 7 set to 1";
436                 break;
437
438             case SC_RCV_B7_1:
439                 s = "all had bit 7 set to 0";
440                 break;
441
442             case SC_RCV_EVNP:
443                 s = "all had odd parity";
444                 break;
445
446             case SC_RCV_ODDP:
447                 s = "all had even parity";
448                 break;
449             }
450
451             if (s != NULL) {
452                 warn("Receive serial link is not 8-bit clean:");
453                 warn("Problem: %s", s);
454             }
455         }
456     }
457 }
458
459 /********************************************************************
460  *
461  * output - Output PPP packet.
462  */
463
464 void output (int unit, unsigned char *p, int len)
465 {
466     int fd = ppp_fd;
467     int proto;
468
469     if (debug)
470         dbglog("sent %P", p, len);
471
472     if (len < PPP_HDRLEN)
473         return;
474     if (new_style_driver) {
475         p += 2;
476         len -= 2;
477         proto = (p[0] << 8) + p[1];
478         if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
479             fd = ppp_dev_fd;
480     }
481     if (write(fd, p, len) < 0) {
482         if (errno == EWOULDBLOCK || errno == ENOBUFS
483             || errno == ENXIO || errno == EIO || errno == EINTR)
484             warn("write: warning: %m (%d)", errno);
485         else
486             error("write: %m (%d)", errno);
487     }
488 }
489
490 /********************************************************************
491  *
492  * wait_input - wait until there is data available,
493  * for the length of time specified by *timo (indefinite
494  * if timo is NULL).
495  */
496
497 void wait_input(struct timeval *timo)
498 {
499     fd_set ready, exc;
500     int n;
501
502     ready = in_fds;
503     exc = in_fds;
504     n = select(max_in_fd + 1, &ready, NULL, &exc, timo);
505     if (n < 0 && errno != EINTR)
506         fatal("select: %m(%d)", errno);
507 }
508
509 /*
510  * add_fd - add an fd to the set that wait_input waits for.
511  */
512 void add_fd(int fd)
513 {
514     FD_SET(fd, &in_fds);
515     if (fd > max_in_fd)
516         max_in_fd = fd;
517 }
518
519 /*
520  * remove_fd - remove an fd from the set that wait_input waits for.
521  */
522 void remove_fd(int fd)
523 {
524     FD_CLR(fd, &in_fds);
525 }
526
527
528 /********************************************************************
529  *
530  * read_packet - get a PPP packet from the serial device.
531  */
532
533 int read_packet (unsigned char *buf)
534 {
535     int len, nr;
536
537     len = PPP_MRU + PPP_HDRLEN;
538     if (new_style_driver) {
539         *buf++ = PPP_ALLSTATIONS;
540         *buf++ = PPP_UI;
541         len -= 2;
542     }
543     nr = -1;
544     if (ppp_fd >= 0) {
545         nr = read(ppp_fd, buf, len);
546         if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
547             error("read: %m");
548         if (nr < 0 && errno == ENXIO)
549             return 0;
550     }
551     if (nr < 0 && new_style_driver && ifunit >= 0) {
552         /* N.B. we read ppp_fd first since LCP packets come in there. */
553         nr = read(ppp_dev_fd, buf, len);
554         if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
555             error("read /dev/ppp: %m");
556         if (nr < 0 && errno == ENXIO)
557             return 0;
558     }
559     return (new_style_driver && nr > 0)? nr+2: nr;
560 }
561
562 /*
563  * netif_set_mtu - set the MTU on the PPP network interface.
564  */
565 void
566 netif_set_mtu(int unit, int mtu)
567 {
568     struct ifreq ifr;
569
570     SYSDEBUG ((LOG_DEBUG, "netif_set_mtu: mtu = %d\n", mtu));
571
572     memset (&ifr, '\0', sizeof (ifr));
573     strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
574     ifr.ifr_mtu = mtu;
575
576     if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
577         fatal("ioctl(SIOCSIFMTU): %m");
578 }
579
580 /********************************************************************
581  *
582  * ccp_test - ask kernel whether a given compression method
583  * is acceptable for use.
584  */
585
586 int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
587 {
588     struct ppp_option_data data;
589
590     memset (&data, '\0', sizeof (data));
591     data.ptr      = opt_ptr;
592     data.length   = opt_len;
593     data.transmit = for_transmit;
594
595     if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
596         return 1;
597
598     return (errno == ENOBUFS)? 0: -1;
599 }
600
601 /********************************************************************
602  *
603  * ccp_flags_set - inform kernel about the current state of CCP.
604  */
605
606 void ccp_flags_set (int unit, int isopen, int isup)
607 {
608     if (still_ppp()) {
609         int x = get_flags(ppp_dev_fd);
610         x = isopen? x | SC_CCP_OPEN : x &~ SC_CCP_OPEN;
611         x = isup?   x | SC_CCP_UP   : x &~ SC_CCP_UP;
612         set_flags (ppp_dev_fd, x);
613     }
614 }
615
616 /********************************************************************
617  *
618  * get_idle_time - return how long the link has been idle.
619  */
620 int
621 get_idle_time(u, ip)
622     int u;
623     struct ppp_idle *ip;
624 {
625     return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) >= 0;
626 }
627
628 /********************************************************************
629  *
630  * get_ppp_stats - return statistics for the link.
631  */
632 int
633 get_ppp_stats(u, stats)
634     int u;
635     struct pppd_stats *stats;
636 {
637     struct ifpppstatsreq req;
638
639     memset (&req, 0, sizeof (req));
640
641     req.stats_ptr = (caddr_t) &req.stats;
642     strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
643     if (ioctl(sock_fd, SIOCGPPPSTATS, &req) < 0) {
644         error("Couldn't get PPP statistics: %m");
645         return 0;
646     }
647     stats->bytes_in = req.stats.p.ppp_ibytes;
648     stats->bytes_out = req.stats.p.ppp_obytes;
649     return 1;
650 }
651
652 /********************************************************************
653  *
654  * ccp_fatal_error - returns 1 if decompression was disabled as a
655  * result of an error detected after decompression of a packet,
656  * 0 otherwise.  This is necessary because of patent nonsense.
657  */
658
659 int ccp_fatal_error (int unit)
660 {
661     int x = get_flags(ppp_dev_fd);
662
663     return x & SC_DC_FERROR;
664 }
665
666 /********************************************************************
667  *
668  * Return user specified netmask, modified by any mask we might determine
669  * for address `addr' (in network byte order).
670  * Here we scan through the system's list of interfaces, looking for
671  * any non-point-to-point interfaces which might appear to be on the same
672  * network as `addr'.  If we find any, we OR in their netmask to the
673  * user-specified netmask.
674  */
675
676 u_int32_t GetMask (u_int32_t addr)
677 {
678     u_int32_t mask, nmask, ina;
679     struct ifreq *ifr, *ifend, ifreq;
680     struct ifconf ifc;
681     struct ifreq ifs[MAX_IFS];
682
683     addr = ntohl(addr);
684
685     if (IN_CLASSA(addr))        /* determine network mask for address class */
686         nmask = IN_CLASSA_NET;
687     else if (IN_CLASSB(addr))
688             nmask = IN_CLASSB_NET;
689     else
690             nmask = IN_CLASSC_NET;
691
692     /* class D nets are disallowed by bad_ip_adrs */
693     mask = netmask | htonl(nmask);
694 /*
695  * Scan through the system's network interfaces.
696  */
697     ifc.ifc_len = sizeof(ifs);
698     ifc.ifc_req = ifs;
699     if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
700         if ( ! ok_error ( errno ))
701             warn("ioctl(SIOCGIFCONF): %m(%d)", errno);
702         return mask;
703     }
704
705     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
706     for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
707 /*
708  * Check the interface's internet address.
709  */
710         if (ifr->ifr_addr.sa_family != AF_INET)
711             continue;
712         ina = SIN_ADDR(ifr->ifr_addr);
713         if (((ntohl(ina) ^ addr) & nmask) != 0)
714             continue;
715 /*
716  * Check that the interface is up, and not point-to-point nor loopback.
717  */
718         strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
719         if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
720             continue;
721
722         if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
723             continue;
724 /*
725  * Get its netmask and OR it into our mask.
726  */
727         if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
728             continue;
729         mask |= SIN_ADDR(ifreq.ifr_addr);
730         break;
731     }
732     return mask;
733 }
734
735 /********************************************************************
736  *
737  * ppp_available - check whether the system has any ppp interfaces
738  * (in fact we check whether we can do an ioctl on ppp0).
739  */
740
741 int ppp_available(void)
742 {
743     struct utsname utsname;     /* for the kernel version */
744     int osmaj, osmin, ospatch;
745
746     /* get the kernel version now, since we are called before sys_init */
747     uname(&utsname);
748     osmaj = osmin = ospatch = 0;
749     sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
750     kernel_version = KVERSION(osmaj, osmin, ospatch);
751
752     /* XXX should get from driver */
753     driver_version = 2;
754     driver_modification = 4;
755     driver_patch = 0;
756
757     return 1;
758 }
759
760 /********************************************************************
761  *
762  * sifvjcomp - config tcp header compression
763  */
764
765 int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
766 {
767     u_int x = get_flags(ppp_dev_fd);
768
769     if (vjcomp) {
770         if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
771             if (! ok_error (errno))
772                 error("ioctl(PPPIOCSMAXCID): %m(%d)", errno);
773             vjcomp = 0;
774         }
775     }
776
777     x = vjcomp  ? x | SC_COMP_TCP     : x &~ SC_COMP_TCP;
778     x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
779     set_flags (ppp_dev_fd, x);
780
781     return 1;
782 }
783
784 /********************************************************************
785  *
786  * sifup - Config the interface up and enable IP packets to pass.
787  */
788
789 int sifup(int u)
790 {
791     struct ifreq ifr;
792
793     memset (&ifr, '\0', sizeof (ifr));
794     strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
795     if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
796         if (! ok_error (errno))
797             error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
798         return 0;
799     }
800
801     ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
802     if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
803         if (! ok_error (errno))
804             error("ioctl(SIOCSIFFLAGS): %m(%d)", errno);
805         return 0;
806     }
807     if_is_up++;
808
809     return 1;
810 }
811
812 /********************************************************************
813  *
814  * sifdown - Disable the indicated protocol and config the interface
815  *           down if there are no remaining protocols.
816  */
817
818 int sifdown (int u)
819 {
820     struct ifreq ifr;
821
822     if (if_is_up && --if_is_up > 0)
823         return 1;
824
825     memset (&ifr, '\0', sizeof (ifr));
826     strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
827     if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
828         if (! ok_error (errno))
829             error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
830         return 0;
831     }
832
833     ifr.ifr_flags &= ~IFF_UP;
834     ifr.ifr_flags |= IFF_POINTOPOINT;
835     if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
836         if (! ok_error (errno))
837             error("ioctl(SIOCSIFFLAGS): %m(%d)", errno);
838         return 0;
839     }
840     return 1;
841 }
842
843 /********************************************************************
844  *
845  * sifaddr - Config the interface IP addresses and netmask.
846  */
847
848 int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
849              u_int32_t net_mask)
850 {
851     struct ifreq   ifr;
852     struct rtentry rt;
853
854     memset (&ifr, '\0', sizeof (ifr));
855     memset (&rt,  '\0', sizeof (rt));
856
857     SET_SA_FAMILY (ifr.ifr_addr,    AF_INET);
858     SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
859     SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
860
861     strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
862 /*
863  *  Set our IP address
864  */
865     SIN_ADDR(ifr.ifr_addr) = our_adr;
866     if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
867         if (errno != EEXIST) {
868             if (! ok_error (errno))
869                 error("ioctl(SIOCSIFADDR): %m(%d)", errno);
870         }
871         else {
872             warn("ioctl(SIOCSIFADDR): Address already exists");
873         }
874         return (0);
875     }
876 /*
877  *  Set the gateway address
878  */
879     SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
880
881     if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
882         if (! ok_error (errno))
883             error("ioctl(SIOCSIFDSTADDR): %m(%d)", errno);
884         return (0);
885     }
886 /*
887  *  Set the netmask.
888  *  For recent kernels, force the netmask to 255.255.255.255.
889  */
890     if (kernel_version >= KVERSION(2,1,16))
891         net_mask = ~0L;
892     if (net_mask != 0) {
893         SIN_ADDR(ifr.ifr_netmask) = net_mask;
894         if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
895             if (! ok_error (errno))
896                 error("ioctl(SIOCSIFNETMASK): %m(%d)", errno);
897             return (0);
898         }
899     }
900 /*
901  *  Add the device route
902  */
903     if (kernel_version < KVERSION(2,1,16)) {
904         SET_SA_FAMILY (rt.rt_dst,     AF_INET);
905         SET_SA_FAMILY (rt.rt_gateway, AF_INET);
906         rt.rt_dev = ifname;
907
908         SIN_ADDR(rt.rt_gateway) = 0L;
909         SIN_ADDR(rt.rt_dst)     = his_adr;
910         rt.rt_flags = RTF_UP | RTF_HOST;
911
912         if (kernel_version > KVERSION(2,1,0)) {
913             SET_SA_FAMILY (rt.rt_genmask, AF_INET);
914             SIN_ADDR(rt.rt_genmask) = -1L;
915         }
916
917         if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
918             if (! ok_error (errno))
919                 error("ioctl(SIOCADDRT) device route: %m(%d)", errno);
920             return (0);
921         }
922     }
923
924     /* set ip_dynaddr in demand mode if address changes */
925     if (demand && tune_kernel && !dynaddr_set
926         && our_old_addr && our_old_addr != our_adr) {
927         /* set ip_dynaddr if possible */
928         char *path;
929         int fd;
930
931         path = "/proc/sys/net/ipv4/ip_dynaddr";
932         if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
933             if (write(fd, "1", 1) != 1)
934                 error("Couldn't enable dynamic IP addressing: %m");
935             close(fd);
936         }
937         dynaddr_set = 1;        /* only 1 attempt */
938     }
939     our_old_addr = 0;
940
941     return 1;
942 }
943
944 /********************************************************************
945  *
946  * cifaddr - Clear the interface IP addresses, and delete routes
947  * through the interface if possible.
948  */
949
950 int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
951 {
952     struct ifreq ifr;
953
954     create_msg(BCM_PPPOE_CLIENT_STATE_DOWN);
955     syslog(LOG_CRIT,"Clear IP addresses.  PPP connection DOWN.\n");   
956
957     if (kernel_version < KVERSION(2,1,16)) {
958 /*
959  *  Delete the route through the device
960  */
961         struct rtentry rt;
962         memset (&rt, '\0', sizeof (rt));
963
964         SET_SA_FAMILY (rt.rt_dst,     AF_INET);
965         SET_SA_FAMILY (rt.rt_gateway, AF_INET);
966         rt.rt_dev = ifname;
967
968         SIN_ADDR(rt.rt_gateway) = 0;
969         SIN_ADDR(rt.rt_dst)     = his_adr;
970         rt.rt_flags = RTF_UP | RTF_HOST;
971
972         if (kernel_version > KVERSION(2,1,0)) {
973             SET_SA_FAMILY (rt.rt_genmask, AF_INET);
974             SIN_ADDR(rt.rt_genmask) = -1L;
975         }
976
977         if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
978             if (still_ppp() && ! ok_error (errno))
979                 error("ioctl(SIOCDELRT) device route: %m(%d)", errno);
980             return (0);
981         }
982     }
983
984     /* This way it is possible to have an IPX-only or IPv6-only interface */
985     memset(&ifr, 0, sizeof(ifr));
986     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
987     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
988
989     if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
990         if (! ok_error (errno)) {
991             error("ioctl(SIOCSIFADDR): %m(%d)", errno);
992             return 0;
993         }
994     }
995
996     our_old_addr = our_adr;
997
998     return 1;
999 }
1000
1001 /********************************************************************
1002  *
1003  * sifnpmode - Set the mode for handling packets for a given NP.
1004  */
1005
1006 int
1007 sifnpmode(u, proto, mode)
1008     int u;
1009     int proto;
1010     enum NPmode mode;
1011 {
1012     struct npioctl npi;
1013
1014     npi.protocol = proto;
1015     npi.mode     = mode;
1016     if (ioctl(ppp_dev_fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
1017         if (! ok_error (errno))
1018             error("ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)",
1019                    proto, mode, errno);
1020         return 0;
1021     }
1022     return 1;
1023 }
1024
1025 /*
1026  * Use the hostname as part of the random number seed.
1027  */
1028 int
1029 get_host_seed()
1030 {
1031     int h;
1032     char *p = hostname;
1033
1034     h = 407;
1035     for (p = hostname; *p != 0; ++p)
1036         h = h * 37 + *p;
1037     return h;
1038 }