/* * * $Id$ * * History: * * Bernd Wuebben, wuebben@math.cornell.edu: * * Much of this is taken from the pppd sources in particular * /pppstat/pppstat.c, and modified to suit the needs of kppp. * * * Here the original history of pppstat.c: * * perkins@cps.msu.edu: Added compression statistics and alternate * display. 11/94 * * Brad Parker (brad@cayman.com) 6/92 * * from the original "slstats" by Van Jaconson * * Copyright (c) 1989 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. */ #include <config.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <signal.h> #include <fcntl.h> #include <sys/param.h> #include <sys/types.h> #include <sys/ioctl.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <netinet/in.h> #ifdef __DragonFly__ #include <net/ppp_layer/ppp_defs.h> #else #include <net/ppp_defs.h> #endif #include "config.h" #include "pppstats.h" #ifndef STREAMS #if defined(__linux__) && defined(__powerpc__) \ && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) /* kludge alert! */ #undef __GLIBC__ #endif #include <sys/socket.h> /* *BSD, Linux, NeXT, Ultrix etc. */ #ifndef HAVE_NET_IF_PPP_H #ifdef HAVE_LINUX_IF_PPP_H #include <linux/if.h> #ifndef aligned_u64 #define aligned_u64 unsigned long long __attribute__((aligned(8))) #endif #include <linux/if_ppp.h> #elif defined(__DragonFly__) #include <net/if.h> #include <net/ppp/if_ppp.h> #endif #else #include <net/if.h> #include <net/if_ppp.h> #endif #else /* STREAMS */ #include <sys/socket.h> #include <sys/stropts.h> /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */ #include <net/ppp_defs.h> #include <net/pppio.h> #include <net/if.h> #include <sys/sockio.h> #endif /* STREAMS */ #include <tqtimer.h> #include <kdebug.h> PPPStats::PPPStats() { clear(); timer = new TQTimer; connect(timer, TQT_SIGNAL(timeout()), TQT_SLOT(timerClick())); } PPPStats::~PPPStats() { stop(); delete timer; } void PPPStats::clear() { ibytes = 0; ipackets = 0; ibytes_last = 0; obytes_last = 0; compressedin = 0; uncompressedin = 0; errorin = 0; obytes = 0; opackets = 0; compressed = 0; packetsunc = 0; packetsoutunc = 0; ioStatus = BytesNone; } void PPPStats::timerClick() { enum IOStatus newStatus; doStats(); if((ibytes != ibytes_last) && (obytes != obytes_last)) newStatus = BytesBoth; else if(ibytes != ibytes_last) newStatus = BytesIn; else if(obytes != obytes_last) newStatus = BytesOut; else newStatus = BytesNone; if(newStatus != ioStatus) emit statsChanged(ioStatus = newStatus); ibytes_last = ibytes; obytes_last = obytes; } void PPPStats::setUnit(int u) { unit = u; sprintf(unitName, "ppp%d", unit); } void PPPStats::start() { timer->start(PPP_STATS_INTERVAL); } void PPPStats::stop() { emit statsChanged(BytesNone); timer->stop(); } bool PPPStats::ifIsUp() { bool is_up; struct ifreq ifr; #if defined(__svr4__ ) usleep(1000000); // Needed for Solaris ?! #endif #ifdef STREAMS if ((t = open("/dev/ppp", O_RDONLY)) < 0) { perror("pppstats: Couldn't open /dev/ppp: "); return false; } if (!strioctl(t, PPPIO_ATTACH, (char*)&unit, sizeof(int), 0)) { fprintf(stderr, "pppstats: ppp%d is not available\n", unit); ::close(t); return false; } // TODO: close t somewhere again #endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Couldn't create IP socket"); return false; } strlcpy(ifr.ifr_name, unitName, sizeof(ifr.ifr_name)); if(ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { if (errno) fprintf(stderr, "Couldn't find interface %s: %s\n", unitName, strerror(errno)); ::close(s); s = 0; return 0; } if ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)) { is_up = true; kdDebug(5002) << "Interface is up" << endl; } else{ is_up = false; ::close(s); s = 0; kdDebug(5002) << "Interface is down" << endl; } return is_up; } bool PPPStats::initStats() { struct sockaddr_in *sinp; struct ifreq ifr; clear(); strlcpy(ifr.ifr_name, unitName, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { } sinp = (struct sockaddr_in*)&ifr.ifr_addr; if(sinp->sin_addr.s_addr) local_ip_address = inet_ntoa(sinp->sin_addr); else local_ip_address = ""; kdDebug(5002) << "Local IP: " << local_ip_address << endl; (void) ioctl(s, SIOCGIFDSTADDR, &ifr); sinp = (struct sockaddr_in*)&ifr.ifr_dstaddr; if(sinp->sin_addr.s_addr) remote_ip_address = inet_ntoa(sinp->sin_addr); else remote_ip_address = ""; kdDebug(5002) << "Remote IP: " << remote_ip_address << endl; return true; } bool PPPStats::doStats() { struct ppp_stats cur; if(! get_ppp_stats(&cur)){ return false; } // "in" "pack" "comp" "uncomp" "err" // IN PACK VJCOMP VJUNC VJERR ibytes = cur.p.ppp_ibytes; // bytes received ipackets = cur.p.ppp_ipackets; // packets recieved compressedin = cur.vj.vjs_compressedin; // inbound compressed packets uncompressedin = cur.vj.vjs_uncompressedin; // inbound uncompressed packets errorin = cur.vj.vjs_errorin; //receive errors // "out" "pack" "comp" "uncomp" "ip" // OUT PACK JCOMP VJUNC NON-VJ obytes = cur.p.ppp_obytes; // raw bytes sent opackets = cur.p.ppp_opackets; // packets sent compressed = cur.vj.vjs_compressed; //outbound compressed packets // outbound packets - outbound compressed packets packetsunc = cur.vj.vjs_packets - cur.vj.vjs_compressed; // packets sent - oubount compressed packetsoutunc = cur.p.ppp_opackets - cur.vj.vjs_packets; return true; } #ifndef STREAMS bool PPPStats::get_ppp_stats(struct ppp_stats *curp){ struct ifpppstatsreq req; if(s==0) return false; #ifdef __linux__ req.stats_ptr = (caddr_t) &req.stats; sprintf(req.ifr__name, "ppp%d", unit); #else sprintf(req.ifr_name, "ppp%d", unit); #endif if (ioctl(s, SIOCGPPPSTATS, &req) < 0) { if (errno == ENOTTY) fprintf(stderr, "pppstats: kernel support missing\n"); else perror("ioctl(SIOCGPPPSTATS)"); return false; } *curp = req.stats; return true; } #else /* STREAMS */ bool PPPStats::get_ppp_stats( struct ppp_stats *curp){ if (!strioctl(t, PPPIO_GETSTAT, (char*)curp, 0, sizeof(*curp))) { if (errno == EINVAL) fprintf(stderr, "pppstats: kernel support missing\n"); else perror("pppstats: Couldn't get statistics"); return false; } return true; } bool PPPStats::strioctl(int fd, int cmd, char* ptr, int ilen, int olen){ struct strioctl str; str.ic_cmd = cmd; str.ic_timout = 0; str.ic_len = ilen; str.ic_dp = ptr; if (ioctl(fd, I_STR, &str) == -1) return false; if (str.ic_len != olen) fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n", olen, str.ic_len, cmd); return true; } #endif /* STREAMS */ #include "pppstats.moc"