To make a version of pppstats for Linux, you need to perform the
following steps.

1. Apply the patches in the file Linux.diffs to the files in this
   directory.

   patch -p0 <README.Linux

2. Ensure that the linux distribution is stored in the directory
   /usr/src/linux. If you do not have it located there than change
   the Makefile.linux accordingly to the proper directory.

3. Issue the command:

   make -f Makefile.linux

   to construct the program.

This program is not "distributed" in the true sense. It should work with
kernels greater than 1.1.17 (that is 1.1.18 or later) as it contains the
patches which the program needs to access the statistics.

I do not know if the statistics are proper. I chose to keep the statistics
in the format needed by LQP rather than the names used by pppstats. So,
some of the statistics are separated when they were merged for the other
platforms, and visa-versa.

A great program, pppstats is not. However, it is interesting and worth
running once.

                            -----------------

*** pppstats.c.orig	Sat Jun 11 07:18:15 1994
--- pppstats.c	Sat Jun 11 07:17:44 1994
***************
*** 33,53 ****
  #include <errno.h>
  #include <nlist.h>
  #include <stdio.h>
  #include <signal.h>
  #include <sys/param.h>
- #include <sys/mbuf.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <sys/file.h>
  #include <net/if.h>
  #include <netinet/in.h>
- #include <netinet/in_systm.h>
  #include <netinet/ip.h>
  #include <netinet/ip_var.h>
- 
- #define	VJC	1
  #include <net/slcompress.h>
  
  #ifndef STREAMS
  #include <net/if_ppp.h>
  #endif
--- 33,71 ----
  #include <errno.h>
  #include <nlist.h>
  #include <stdio.h>
  #include <signal.h>
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <sys/file.h>
  #include <net/if.h>
+ 
+ #define	VJC	1
+ 
+ #ifdef _linux_
+ #include <sys/types.h>
+ #include <sys/fcntl.h>
+ #include <malloc.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <signal.h>
+ #include <linux/ppp.h>
+ #include <netinet/ip.h>
+ #include <netinet/tcp.h>
+ #include <slhc.h> /* linux base directory passed on -I parameter */
+ 
+ struct ifreq	ifreq;
+ int		fd;
+ 
+ #else	/* _linux_ */
+ 
+ #include <sys/mbuf.h>
  #include <netinet/in.h>
  #include <netinet/ip.h>
+ #include <netinet/in_systm.h>
  #include <netinet/ip_var.h>
  #include <net/slcompress.h>
  
  #ifndef STREAMS
  #include <net/if_ppp.h>
  #endif
***************
*** 69,79 ****
  #include <machine/cpu.h>
  #endif
  
  struct	pte *Sysmap;
  int	kmem;
- char	*kmemf = "/dev/kmem";
  extern	off_t lseek();
  
  #else	/* KVMLIB */
  
  char	*kmemf;
--- 87,96 ----
***************
*** 101,124 ****
  	{ "_ppp_softc" },
  	"",
  };
  #endif
  
! #ifndef BSD4_4
! char	*system = "/vmunix";
! #else
  #include <paths.h>
! char	*system = _PATH_UNIX;
  #endif
  
  int	kflag;
  int	vflag;
  unsigned interval = 5;
  int	unit;
  
- extern	char *malloc();
- 
  main(argc, argv)
  	int argc;
  	char *argv[];
  {
  	--argc; ++argv;
--- 118,146 ----
  	{ "_ppp_softc" },
  	"",
  };
  #endif
  
! extern	char *malloc();
! #endif	/* _linux_ */
! 
! #ifdef BSD4_4
  #include <paths.h>
! #endif
! 
! #ifndef _PATH_UNIX
! #define _PATH_UNIX "/vmunix"
  #endif
  
+ char	*kmemf  = "/dev/kmem";
+ char	*system = _PATH_UNIX;
+ 
  int	kflag;
  int	vflag;
  unsigned interval = 5;
  int	unit;
  
  main(argc, argv)
  	int argc;
  	char *argv[];
  {
  	--argc; ++argv;
***************
*** 153,162 ****
--- 175,195 ----
  			kmemf = *argv++;
  			--argc;
  			kflag++;
  		}
  	}
+ 
+ #ifdef _linux_
+ 	memset (&ifreq, '\0', sizeof (ifreq));
+ 	sprintf (ifreq.ifr_ifrn.ifrn_name, "ppp%d", unit);
+ 	/* Get an internet socket for doing socket ioctls. */
+ 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ 		perror("socket(AF_INET,SOCK_DGRAM,0)");
+ 		exit(1);
+ 	}
+ #else  /* _linux_ */
+ 
  #ifndef KVMLIB
  	if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
  		fprintf(stderr, "%s: no namelist\n", system);
  		exit(1);
  	}
***************
*** 179,189 ****
  		(void)lseek(kmem, off, L_SET);
  		(void)read(kmem, (char *)Sysmap,
  		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
  	}
  #endif
! #else
  #ifdef sun
  	/* SunOS */
  	if ((kd = kvm_open(system, kmemf, (char *)0, O_RDONLY, NULL)) == NULL) {
  	    perror("kvm_open");
  	    exit(1);
--- 212,222 ----
  		(void)lseek(kmem, off, L_SET);
  		(void)read(kmem, (char *)Sysmap,
  		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
  	}
  #endif
! #else  /* KVMLIB */
  #ifdef sun
  	/* SunOS */
  	if ((kd = kvm_open(system, kmemf, (char *)0, O_RDONLY, NULL)) == NULL) {
  	    perror("kvm_open");
  	    exit(1);
***************
*** 192,212 ****
  	/* BSD4.3+ */
  	if (kvm_openfiles(system, kmemf, (char *)0) == -1) {
  	    fprintf(stderr, "kvm_openfiles: %s", kvm_geterr());
  	    exit(1);
  	}
! #endif
  
  	if (kvm_nlist(KDARG nl)) {
  	    fprintf(stderr, "pppstats: can't find symbols in nlist\n");
  	    exit(1);
  	}
! #endif
  	intpr();
  	exit(0);
  }
  
  #ifndef KVMLIB
  /*
   * Seek into the kernel for a value.
   */
  off_t
--- 225,247 ----
  	/* BSD4.3+ */
  	if (kvm_openfiles(system, kmemf, (char *)0) == -1) {
  	    fprintf(stderr, "kvm_openfiles: %s", kvm_geterr());
  	    exit(1);
  	}
! #endif	/* sun */
  
  	if (kvm_nlist(KDARG nl)) {
  	    fprintf(stderr, "pppstats: can't find symbols in nlist\n");
  	    exit(1);
  	}
! #endif	/* KVMLIB  */
! #endif	/* _linux_ */
  	intpr();
  	exit(0);
  }
  
+ #ifndef _linux_
  #ifndef KVMLIB
  /*
   * Seek into the kernel for a value.
   */
  off_t
***************
*** 218,254 ****
  #ifdef ultrix
  		base = K0_TO_PHYS(base);
  #else
  		/* get kernel pte */
  		base &= ~KERNBASE;
!                 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
  #endif
  	}
  	return (lseek(fd, base, off));
  }
  #endif
  
  usage()
  {
! 	fprintf(stderr,"usage: pppstats [-i interval] [-v] [unit] [system] [core]\n");
  	exit(1);
  }
  
  u_char	signalled;			/* set if alarm goes off "early" */
  
  #define V(offset) ((line % 20)? sc->offset - osc->offset : sc->offset)
  
  #ifdef STREAMS
  #define STRUCT	struct ppp_if_info
  #define	COMP	pii_sc_comp
  #define	STATS	pii_ifnet
  #else
  #define STRUCT	struct ppp_softc
  #define	COMP	sc_comp
  #define	STATS	sc_if
  #endif
  
  /*
   * Print a running summary of interface statistics.
   * Repeat display every interval seconds, showing statistics
   * collected over that interval.  Assumes that interval is non-zero.
   * First line printed at top of screen is always cumulative.
--- 253,369 ----
  #ifdef ultrix
  		base = K0_TO_PHYS(base);
  #else
  		/* get kernel pte */
  		base &= ~KERNBASE;
! 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
  #endif
  	}
  	return (lseek(fd, base, off));
  }
  #endif
+ #endif	/* _linux_ */
  
  usage()
  {
! 	fprintf(stderr,"usage: pppstats [-i interval] [-v] [unit]"
! #ifndef _linux_
! 		" [system] [core]"
! #endif
! 		"\n");
  	exit(1);
  }
  
  u_char	signalled;			/* set if alarm goes off "early" */
  
  #define V(offset) ((line % 20)? sc->offset - osc->offset : sc->offset)
  
+ #ifdef _linux_
+ typedef struct __struct
+ {
+   struct ppp_stats  stats;
+   struct slcompress slcomp;
+ } STRUCT;
+ 
+ #define STATS		stats
+ #define COMP		slcomp
+ 
+ #define RCOMP			V(STATS.rcomp)
+ #define RUNCOMP			V(STATS.runcomp)
+ #define ROTHERS			V(STATS.rothers)
+ #define RPACKETS		(RCOMP+RUNCOMP+ROTHERS)
+ #define RERRORS			V(STATS.rerrors)
+ #define ROVERRUN		V(STATS.roverrun)
+ #define RTOSSED			V(STATS.tossed)
+ #define RERROR			(RERRORS+ROVERRUN+RTOSSED)
+ #define SCOMP			V(STATS.scomp)
+ #define SUNCOMP			V(STATS.suncomp)
+ #define SOTHERS			V(STATS.sothers)
+ #define SPACKETS		(SCOMP+SUNCOMP+SOTHERS)
+ #define SERROR			V(STATS.serrors)
+ 
+ #define stats_ibytes		V(STATS.rbytes)
+ #define stats_ipackets		RPACKETS
+ #define stats_compressedin	RCOMP
+ #define stats_uncompressedin	RUNCOMP
+ #define stats_errorin		RERROR
+ #define stats_tossed		RTOSSED
+ #define stats_ip		(RPACKETS-RERROR-ROTHERS)
+ #define stats_obytes		V(STATS.sbytes)
+ #define stats_opackets		SPACKETS
+ #define stats_compressedout	SCOMP
+ #define stats_uncompressedout	SUNCOMP
+ #define stats_errorout		SERROR
+ #define stats_searches		V(COMP.sls_o_searches)
+ #define stats_misses		V(COMP.sls_o_misses)
+ 
+ #else  /* _linux_ */
+ 
+ #define stats_ipackets		V(STATS.if_ipackets)
+ #define stats_compressedin	V(COMP.sls_compressedin)
+ #define stats_uncompressedin	V(COMP.sls_uncompressedin)
+ #define stats_errorin		V(COMP.sls_errorin)
+ #define stats_tossed		V(COMP.sls_tossed)
+ #define stats_ip		V(STATS.if_ipackets) -		\
+ 				V(COMP.sls_compressedin) -	\
+ 				V(COMP.sls_uncompressedin) -	\
+ 				V(COMP.sls_errorin)
+ #define stats_opackets		V(STATS.if_opackets)
+ #define stats_compressedout	V(COMP.sls_compressed)
+ #define stats_uncompressedout	V(COMP.sls_packets) - V(COMP.sls_compressed)
+ #define stats_errorout		V(STATS.if_opackets) - V(COMP.sls_packets)
+ #define stats_searches		V(COMP.sls_searches)
+ #define stats_misses		V(COMP.sls_misses)
+ 
  #ifdef STREAMS
  #define STRUCT	struct ppp_if_info
  #define	COMP	pii_sc_comp
  #define	STATS	pii_ifnet
  #else
  #define STRUCT	struct ppp_softc
  #define	COMP	sc_comp
  #define	STATS	sc_if
  #endif
  
+ #ifdef BSD4_4
+ #define stats_ibytes	V(STATS.if_ibytes)
+ #define stats_obytes	V(STATS.if_obytes)
+ #ifndef STREAMS
+ #define stats_ibytes	V(sc_bytesrcvd)
+ #define stats_obytes	V(sc_bytessent)
+ #else
+ #ifdef PPP_STATS
+ #define stats_ibytes	V(pii_stats.ppp_ibytes)
+ #define stats_obytes	V(pii_stats.ppp_obytes)
+ #else
+ #define stats_ibytes	0
+ #define stats_obytes	0
+ #endif /* BSD4_4 */
+ #endif /* STREAMS */
+ #endif /* PPP_STATS */
+ #endif /* _linux_ */
+ 
  /*
   * Print a running summary of interface statistics.
   * Repeat display every interval seconds, showing statistics
   * collected over that interval.  Assumes that interval is non-zero.
   * First line printed at top of screen is always cumulative.
***************
*** 263,279 ****
  	void catchalarm();
  #endif
  
  	STRUCT *sc, *osc;
  
! 	nl[N_SOFTC].n_value += unit * sizeof(STRUCT);
! 	sc = (STRUCT *)malloc(sizeof(STRUCT));
! 	osc = (STRUCT *)malloc(sizeof(STRUCT));
  
! 	bzero((char *)osc, sizeof(STRUCT));
  
  	while (1) {
  #ifndef KVMLIB
  	    if (klseek(kmem, (off_t)nl[N_SOFTC].n_value, 0) == -1) {
  		perror("kmem seek");
  		exit(1);
  	    }
--- 378,403 ----
  	void catchalarm();
  #endif
  
  	STRUCT *sc, *osc;
  
! 	sc  = (STRUCT *) calloc (1, sizeof(STRUCT));
! 	osc = (STRUCT *) calloc (1, sizeof(STRUCT));
  
! #ifdef _linux_
! 	ifreq.ifr_ifru.ifru_data = (caddr_t) sc;
! #else
! 	nl[N_SOFTC].n_value += unit * sizeof(STRUCT);
! #endif
  
  	while (1) {
+ #ifdef _linux_
+ 	    if (ioctl (fd, SIOCDEVPRIVATE, (caddr_t) &ifreq) < 0) {
+ 		perror ("ioctl(SIOCDEVPRIVATE)");
+ 		exit(1);
+ 	    }
+ #else
  #ifndef KVMLIB
  	    if (klseek(kmem, (off_t)nl[N_SOFTC].n_value, 0) == -1) {
  		perror("kmem seek");
  		exit(1);
  	    }
***************
*** 286,295 ****
--- 410,420 ----
  			 sizeof(STRUCT)) != sizeof(STRUCT)) {
  		perror("kvm_read");
  		exit(1);
  	    }
  #endif
+ #endif
  
  	    (void)signal(SIGALRM, catchalarm);
  	    signalled = 0;
  	    (void)alarm(interval);
  
***************
*** 304,357 ****
  		    printf(" %6.6s %6.6s", "search", "miss");
  		putchar('\n');
  	    }
  
  	    printf("%6d %6d %6d %6d %6d",
! #ifdef BSD4_4
! 		   V(STATS.if_ibytes),
! #else
! #ifndef STREAMS
! 		   V(sc_bytesrcvd),
! #else
! #ifdef PPP_STATS
! 		   V(pii_stats.ppp_ibytes),
! #else
! 		   0,
! #endif
! #endif
! #endif
! 		   V(STATS.if_ipackets),
! 		   V(COMP.sls_compressedin),
! 		   V(COMP.sls_uncompressedin),
! 		   V(COMP.sls_errorin));
  	    if (vflag)
  		printf(" %6d %6d",
! 		       V(COMP.sls_tossed),
! 		       V(STATS.if_ipackets) - V(COMP.sls_compressedin) -
! 		        V(COMP.sls_uncompressedin) - V(COMP.sls_errorin));
  	    printf(" | %6d %6d %6d %6d %6d",
! #ifdef BSD4_4
! 		   V(STATS.if_obytes),
! #else
! #ifndef STREAMS
! 		   V(sc_bytessent),
! #else
! #ifdef PPP_STATS
! 		   V(pii_stats.ppp_obytes),
! #else
! 		   0,
! #endif
! #endif
! #endif
! 		   V(STATS.if_opackets),
! 		   V(COMP.sls_compressed),
! 		   V(COMP.sls_packets) - V(COMP.sls_compressed),
! 		   V(STATS.if_opackets) - V(COMP.sls_packets));
  	    if (vflag)
  		printf(" %6d %6d",
! 		       V(COMP.sls_searches),
! 		       V(COMP.sls_misses));
  
  	    putchar('\n');
  	    fflush(stdout);
  	    line++;
  
--- 429,460 ----
  		    printf(" %6.6s %6.6s", "search", "miss");
  		putchar('\n');
  	    }
  
  	    printf("%6d %6d %6d %6d %6d",
! 		   stats_ibytes,
! 		   stats_ipackets,
! 		   stats_compressedin,
! 		   stats_uncompressedin,
! 		   stats_errorin);
! 
  	    if (vflag)
  		printf(" %6d %6d",
! 		       stats_tossed,
! 		       stats_ip);
! 
  	    printf(" | %6d %6d %6d %6d %6d",
! 		   stats_obytes,
! 		   stats_opackets,
! 		   stats_compressedout,
! 		   stats_uncompressedout,
! 		   stats_errorout);
! 
  	    if (vflag)
  		printf(" %6d %6d",
! 		       stats_searches,
! 		       stats_misses);
  
  	    putchar('\n');
  	    fflush(stdout);
  	    line++;
  

*** /dev/null	Tue Nov 30 11:30:13 1993
--- Makefile.linux	Sat Jun 11 07:15:35 1994
***************
*** 0 ****
--- 1,29 ----
+ #
+ # pppstats makefile
+ # $Id: Makefile.linux,v 1.1 1994/04/21 03:10:50 paulus Exp $
+ #
+ 
+ PPPSTATSRCS = pppstats.c
+ PPPSTATOBJS = pppstats.o
+ 
+ #CC = gcc
+ COPTS = -O2
+ COMPILE_FLAGS = -D_linux_=1
+ LIBS = 
+ LINUX = /usr/src/linux
+ 
+ CFLAGS = -I$(LINUX)/drivers/net -I.. $(COPTS) $(COMPILE_FLAGS)
+ 
+ all: pppstats
+ 
+ install:
+ 	install -c -g kmem pppstats $(BINDIR)/pppstats
+ 
+ pppstats: $(PPPSTATSRCS)
+ 	$(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
+ 
+ clean:
+ 	rm -f pppstats *~ #* core
+ 
+ depend:
+ 	cpp -M $(CFLAGS) $(PPPSTATSRCS) >.depend

--
Al Longyear                     longyear@netcom.com



