1/*
2 *
3 * $Id$
4 *
5 * History:
6 *
7 * Bernd Wuebben, wuebben@math.cornell.edu:
8 *
9 * Much of this is taken from the pppd sources in particular
10 * /pppstat/pppstat.c, and modified to suit the needs of kppp.
11 *
12 *
13 * Here the original history of pppstat.c:
14 *
15 * perkins@cps.msu.edu: Added compression statistics and alternate
16 * display. 11/94
17 *
18 * Brad Parker (brad@cayman.com) 6/92
19 *
20 * from the original "slstats" by Van Jaconson
21 *
22 * Copyright (c) 1989 Regents of the University of California.
23 * All rights reserved.
24 *
25 * Redistribution and use in source and binary forms are permitted
26 * provided that the above copyright notice and this paragraph are
27 * duplicated in all such forms and that any documentation,
28 * advertising materials, and other materials related to such
29 * distribution and use acknowledge that the software was developed
30 * by the University of California, Berkeley. The name of the
31 * University may not be used to endorse or promote products derived
32 * from this software without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
35 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
36 *
37 * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
38 * - Initial distribution.
39 */
40
41#include <kdefakes.h>
42#include <config-kppp.h>
43
44#include <ctype.h>
45#include <errno.h>
46
47#include <stdio.h>
48#include <signal.h>
49#include <fcntl.h>
50#include <sys/param.h>
51#include <sys/types.h>
52#include <sys/ioctl.h>
53#include <string.h>
54#include <arpa/inet.h>
55#include <unistd.h>
56#include <netinet/in.h>
57#ifdef __DragonFly__
58#include <net/ppp_layer/ppp_defs.h>
59#else
60#include <net/ppp_defs.h>
61#endif
62
63#include "pppstats.h"
64
65#ifndef STREAMS
66 #if defined(__linux__) && defined(__powerpc__) \
67 && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
68 /* kludge alert! */
69 #undef __GLIBC__
70 #endif
71 #include <sys/socket.h> /* *BSD, Linux, NeXT, Ultrix etc. */
72 #ifndef HAVE_NET_IF_PPP_H
73 #ifdef HAVE_LINUX_IF_PPP_H
74 #include <linux/if.h>
75 #include <linux/if_ppp.h>
76 #elif defined(__DragonFly__)
77 #include <net/if.h>
78 #include <net/ppp/if_ppp.h>
79 #endif
80 #else
81 #include <net/if.h>
82 #include <net/if_ppp.h>
83 #endif
84
85#else /* STREAMS */
86 #include <sys/socket.h>
87 #include <sys/stropts.h> /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
88 #include <net/ppp_defs.h>
89 #include <net/pppio.h>
90 #include <net/if.h>
91 #include <sys/sockio.h>
92
93#endif /* STREAMS */
94
95#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
96 #include <sys/socket.h>
97 #include <net/if.h>
98 #include <net/if_ppp.h>
99 #include <sys/sockio.h>
100#endif
101
102#include <qtimer.h>
103#include <kdebug.h>
104
105PPPStats::PPPStats()
106{
107 clear();
108 timer = new QTimer;
109 connect(timer, SIGNAL(timeout()), SLOT(timerClick()));
110}
111
112
113PPPStats::~PPPStats() {
114 stop();
115 delete timer;
116}
117
118
119void PPPStats::clear()
120{
121 ibytes = 0;
122 ipackets = 0;
123 ibytes_last = 0;
124 obytes_last = 0;
125 compressedin = 0;
126 uncompressedin = 0;
127 errorin = 0;
128 obytes = 0;
129 opackets = 0;
130 compressed = 0;
131 packetsunc = 0;
132 packetsoutunc = 0;
133 ioStatus = BytesNone;
134}
135
136void PPPStats::timerClick() {
137 enum IOStatus newStatus;
138
139 doStats();
140
141 if((ibytes != ibytes_last) && (obytes != obytes_last))
142 newStatus = BytesBoth;
143 else if(ibytes != ibytes_last)
144 newStatus = BytesIn;
145 else if(obytes != obytes_last)
146 newStatus = BytesOut;
147 else
148 newStatus = BytesNone;
149
150 if(newStatus != ioStatus)
151 emit statsChanged(ioStatus = newStatus);
152
153 ibytes_last = ibytes;
154 obytes_last = obytes;
155}
156
157void PPPStats::setUnit(int u) {
158 unit = u;
159 sprintf(unitName, "ppp%d", unit);
160}
161
162
163void PPPStats::start() {
164 timer->start(PPP_STATS_INTERVAL);
165}
166
167
168void PPPStats::stop() {
169 emit statsChanged(BytesNone);
170 timer->stop();
171}
172
173
174bool PPPStats::ifIsUp() {
175 bool is_up;
176 struct ifreq ifr;
177
178#if defined(__SVR4)
179 usleep(1000000); // Needed for Solaris ?!
180#endif
181
182#ifdef STREAMS
183 if ((t = open("/dev/ppp", O_RDONLY)) < 0) {
184 perror("pppstats: Couldn't open /dev/ppp: ");
185 return false;
186 }
187 if (!strioctl(t, PPPIO_ATTACH, (char*)&unit, sizeof(int), 0)) {
188 fprintf(stderr, "pppstats: ppp%d is not available\n", unit);
189 ::close(t);
190 return false;
191 }
192 // TODO: close t somewhere again
193#endif
194 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
195 perror("Couldn't create IP socket");
196 return false;
197 }
198
199 strlcpy(ifr.ifr_name, unitName, sizeof(ifr.ifr_name));
200
201 if(ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
202 if (errno)
203 fprintf(stderr, "Couldn't find interface %s: %s\n",
204 unitName, strerror(errno));
205 ::close(s);
206 s = 0;
207 return 0;
208 }
209
210 if ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)) {
211 is_up = true;
212 kDebug(5002) << "Interface is up";
213 }
214 else{
215 is_up = false;
216 ::close(s);
217 s = 0;
218 kDebug(5002) << "Interface is down";
219 }
220
221 return is_up;
222}
223
224
225bool PPPStats::initStats() {
226
227 struct sockaddr_in *sinp;
228 struct ifreq ifr;
229
230 clear();
231
232 strlcpy(ifr.ifr_name, unitName, sizeof(ifr.ifr_name));
233
234 if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
235 }
236
237 sinp = (struct sockaddr_in*)&ifr.ifr_addr;
238
239 if(sinp->sin_addr.s_addr)
240 local_ip_address = inet_ntoa(sinp->sin_addr);
241 else
242 local_ip_address = "";
243 kDebug(5002) << "Local IP: " << local_ip_address;
244
245 if (ioctl(s, SIOCGIFDSTADDR, &ifr) < 0) {
246 }
247
248 sinp = (struct sockaddr_in*)&ifr.ifr_dstaddr;
249
250 if(sinp->sin_addr.s_addr)
251 remote_ip_address = inet_ntoa(sinp->sin_addr);
252 else
253 remote_ip_address = "";
254 kDebug(5002) << "Remote IP: " << remote_ip_address;
255
256 return true;
257
258}
259
260
261bool PPPStats::doStats() {
262 struct ppp_stats cur;
263
264 if(! get_ppp_stats(&cur)){
265 return false;
266 }
267
268 // "in" "pack" "comp" "uncomp" "err"
269 // IN PACK VJCOMP VJUNC VJERR
270
271 ibytes = cur.p.ppp_ibytes; // bytes received
272 ipackets = cur.p.ppp_ipackets; // packets received
273 compressedin = cur.vj.vjs_compressedin; // inbound compressed packets
274 uncompressedin = cur.vj.vjs_uncompressedin; // inbound uncompressed packets
275 errorin = cur.vj.vjs_errorin; //receive errors
276
277 // "out" "pack" "comp" "uncomp" "ip"
278 // OUT PACK JCOMP VJUNC NON-VJ
279
280 obytes = cur.p.ppp_obytes; // raw bytes sent
281 opackets = cur.p.ppp_opackets; // packets sent
282 compressed = cur.vj.vjs_compressed; //outbound compressed packets
283
284 // outbound packets - outbound compressed packets
285 packetsunc = cur.vj.vjs_packets - cur.vj.vjs_compressed;
286
287 // packets sent - oubount compressed
288 packetsoutunc = cur.p.ppp_opackets - cur.vj.vjs_packets;
289
290 return true;
291}
292
293
294#ifndef STREAMS
295bool PPPStats::get_ppp_stats(struct ppp_stats *curp){
296
297 struct ifpppstatsreq req;
298
299 if(s==0)
300 return false;
301
302#ifdef __linux__
303 req.stats_ptr = (caddr_t) &req.stats;
304 sprintf(req.ifr__name, "ppp%d", unit);
305#else
306 sprintf(req.ifr_name, "ppp%d", unit);
307#endif
308 if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
309 if (errno == ENOTTY)
310 fprintf(stderr, "pppstats: kernel support missing\n");
311 else
312 perror("ioctl(SIOCGPPPSTATS)");
313 return false;
314 }
315 *curp = req.stats;
316 return true;
317}
318
319#else /* STREAMS */
320bool PPPStats::get_ppp_stats( struct ppp_stats *curp){
321
322 if (!strioctl(t, PPPIO_GETSTAT, (char*)curp, 0, sizeof(*curp))) {
323 if (errno == EINVAL)
324 fprintf(stderr, "pppstats: kernel support missing\n");
325 else
326 perror("pppstats: Couldn't get statistics");
327 return false;
328 }
329 return true;
330}
331
332bool PPPStats::strioctl(int fd, int cmd, char* ptr, int ilen, int olen){
333
334 struct strioctl str;
335
336 str.ic_cmd = cmd;
337 str.ic_timout = 0;
338 str.ic_len = ilen;
339 str.ic_dp = ptr;
340 if (ioctl(fd, I_STR, &str) == -1)
341 return false;
342 if (str.ic_len != olen)
343 fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
344 olen, str.ic_len, cmd);
345 return true;
346}
347#endif /* STREAMS */
348
349#include "pppstats.moc"
350
351