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 | |
105 | PPPStats::PPPStats() |
106 | { |
107 | clear(); |
108 | timer = new QTimer; |
109 | connect(timer, SIGNAL(timeout()), SLOT(timerClick())); |
110 | } |
111 | |
112 | |
113 | PPPStats::~PPPStats() { |
114 | stop(); |
115 | delete timer; |
116 | } |
117 | |
118 | |
119 | void 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 | |
136 | void 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 | |
157 | void PPPStats::setUnit(int u) { |
158 | unit = u; |
159 | sprintf(unitName, "ppp%d" , unit); |
160 | } |
161 | |
162 | |
163 | void PPPStats::start() { |
164 | timer->start(PPP_STATS_INTERVAL); |
165 | } |
166 | |
167 | |
168 | void PPPStats::stop() { |
169 | emit statsChanged(BytesNone); |
170 | timer->stop(); |
171 | } |
172 | |
173 | |
174 | bool 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 | |
225 | bool 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 | |
261 | bool 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 |
295 | bool 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 */ |
320 | bool 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 | |
332 | bool 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 | |