"Fossies" - the Fresh Open Source Software Archive 
Member "atop-2.8.1/ifprop.c" (7 Jan 2023, 9907 Bytes) of package /linux/misc/atop-2.8.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ifprop.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.6.0_vs_2.7.0.
1 /*
2 ** ATOP - System & Process Monitor
3 **
4 ** The program 'atop' offers the possibility to view the activity of
5 ** the system on system-level as well as process-level.
6 **
7 ** ==========================================================================
8 ** Author: Gerlof Langeveld
9 ** E-mail: gerlof.langeveld@atoptool.nl
10 ** Date: January 2007
11 ** --------------------------------------------------------------------------
12 ** Copyright (C) 2007-2010 Gerlof Langeveld
13 **
14 ** This program is free software; you can redistribute it and/or modify it
15 ** under the terms of the GNU General Public License as published by the
16 ** Free Software Foundation; either version 2, or (at your option) any
17 ** later version.
18 **
19 ** This program is distributed in the hope that it will be useful, but
20 ** WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 ** See the GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License
25 ** along with this program; if not, write to the Free Software
26 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 ** --------------------------------------------------------------------------
28 */
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <linux/sockios.h>
38 #include <linux/if.h>
39 #include <linux/in.h>
40 #include <dirent.h>
41
42 typedef __u64 u64;
43 typedef __u32 u32;
44 typedef __u16 u16;
45 typedef __u8 u8;
46 #include <linux/ethtool.h>
47 #include <linux/wireless.h>
48
49 #ifndef SPEED_UNKNOWN
50 #define SPEED_UNKNOWN -1
51 #endif
52
53 #include "atop.h"
54 #include "ifprop.h"
55 #include "photosyst.h"
56
57 static int calcbucket(char *);
58 static int getphysprop(struct ifprop *);
59
60 /*
61 ** hash table for linked lists with *all* interfaces
62 ** of this system (including virtual interfaces), even
63 ** if the number of interfaces exceeds the maximum that
64 ** is supported by atop (MAXINTF)
65 ** when the number of interfaces in the system exceeds MAXINTF,
66 ** preferably virtual interfaces are marked 'invalid' to ensure
67 ** that all physical interfaces are reported
68 **
69 ** the hash table is meant to be searched on interface name
70 */
71 #define NUMIFHASH 256 // must be power of 2!!
72 static struct ifprop *ifhash[NUMIFHASH];
73
74 /*
75 ** refresh interval of ifhash table
76 **
77 ** periodic refreshing is needed because interfaces might have been
78 ** created or removed, or the speed might have changed (e.g. with wireless)
79 */
80 #define REFRESHTIME 60 // seconds
81 static time_t lastrefreshed; // epoch
82
83 /*
84 ** function that searches for the properties of a particular interface;
85 ** the interface name should be filled in the struct ifprop before
86 ** calling this function
87 **
88 ** return value reflects true (valid interface) or false (invalid interface)
89 */
90 int
91 getifprop(struct ifprop *p)
92 {
93 register int bucket;
94 struct ifprop *ifp;
95
96 /*
97 ** search properties related to given interface name
98 */
99 bucket = calcbucket(p->name);
100
101 for (ifp=ifhash[bucket]; ifp; ifp=ifp->next)
102 {
103 if ( strcmp(ifp->name, p->name) == EQ )
104 {
105 if (ifp->type == 'i') // invalidated interface?
106 break;
107
108 // valid interface; copy properties
109 *p = *ifp;
110 return 1;
111 }
112 }
113
114 p->type = '?';
115 p->speed = 0;
116 p->fullduplex = 0;
117
118 return 0;
119 }
120
121 /*
122 ** function (re)stores properties of all interfaces in a hash table
123 */
124 void
125 initifprop(void)
126 {
127 FILE *fp;
128 char *cp, linebuf[2048];
129 struct ifprop *ifp, *ifpsave = NULL;
130 int bucket, nrinterfaces=0, nrphysical=0;
131
132 DIR *dirp;
133 struct dirent *dentry;
134
135 /*
136 ** verify if the interface properties have to be refreshed
137 ** at this moment already
138 */
139 if (time(0) < lastrefreshed + REFRESHTIME)
140 return;
141
142 /*
143 ** when this function has been called before, first remove
144 ** old entries
145 */
146 if (lastrefreshed)
147 {
148 for (bucket=0; bucket < NUMIFHASH; bucket++)
149 {
150 for (ifp = ifhash[bucket]; ifp; ifp = ifpsave)
151 {
152 ifpsave = ifp->next;
153 free(ifp);
154 }
155
156 ifhash[bucket] = NULL;
157 }
158 }
159
160 /*
161 ** open /proc/net/dev and read all interface names to be able to
162 ** setup new entries in the hash table
163 */
164 if ( (fp = fopen("/proc/net/dev", "r")) == NULL)
165 return;
166
167 while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
168 {
169 /*
170 ** skip lines containing a '|' symbol (headers)
171 */
172 if ( strchr(linebuf, '|') != NULL)
173 continue;
174
175 if ( (cp = strchr(linebuf, ':')) != NULL)
176 *cp = ' '; /* subst ':' by space */
177
178 /*
179 ** allocate new ifprop struct for this interface
180 */
181 ifp = malloc(sizeof *ifp);
182
183 ptrverify(ifp, "Malloc failed for ifprop struct\n");
184
185 memset(ifp, 0, sizeof *ifp);
186 sscanf(linebuf, "%30s", ifp->name); // fill name
187 ifp->type = 'i'; // initially 'invalid'
188
189 /*
190 ** add ifprop struct to proper hash bucket
191 */
192 bucket = calcbucket(ifp->name);
193
194 ifp->next = ifhash[bucket];
195 ifhash[bucket] = ifp;
196
197 nrinterfaces++;
198 }
199
200 fclose(fp);
201
202 /*
203 ** read /sys/devices/virtual/net/xxx to determine which
204 ** interfaces are virtual (xxx is subdirectory name)
205 */
206 if ( (dirp = opendir("/sys/devices/virtual/net")) )
207 {
208 while ( (dentry = readdir(dirp)) )
209 {
210 if (dentry->d_name[0] == '.')
211 continue;
212
213 // valid name
214 // search ifprop and mark it as 'virtual'
215 bucket = calcbucket(dentry->d_name);
216
217 for (ifp = ifhash[bucket]; ifp; ifp = ifp->next)
218 {
219 if ( strcmp(ifp->name, dentry->d_name) == EQ )
220 {
221 ifp->type = 'v'; // virtual interface
222 break;
223 }
224 }
225 }
226
227 closedir(dirp);
228 }
229
230
231 /*
232 ** for physical interfaces, determine the speed and duplex mode
233 */
234 for (bucket=0; bucket < NUMIFHASH; bucket++)
235 {
236 for (ifp=ifhash[bucket]; ifp; ifp=ifp->next)
237 {
238 // possible physical interface?
239 if (ifp->type == 'i')
240 {
241 if (getphysprop(ifp))
242 nrphysical++;
243 }
244 }
245 }
246
247 lastrefreshed = time(0);
248
249 if (nrinterfaces < MAXINTF)
250 return;
251
252 /*
253 ** when the number of interfaces exceeds the maximum,
254 ** invalidate the appropriate number of interfaces (preferably
255 ** virtual interfaces)
256 */
257 for (bucket=0; bucket < NUMIFHASH && nrinterfaces >= MAXINTF; bucket++)
258 {
259 for (ifp=ifhash[bucket]; ifp && nrinterfaces >= MAXINTF; ifp=ifp->next)
260 {
261 // interface invalid already?
262 if (ifp->type == 'i')
263 {
264 nrinterfaces--;
265 continue;
266 }
267
268 // physical interface (ethernet or wireless)?
269 if (ifp->type == 'e' || ifp->type == 'w')
270 {
271 // only invalidate when the number of physical
272 // interfaces exceeds MAXINTF
273 if (nrphysical >= MAXINTF)
274 {
275 ifp->type = 'i';
276
277 nrphysical--;
278 nrinterfaces--;
279 }
280 continue;
281 }
282
283 // virtual or unknown interface, invalidate anyhow
284 ifp->type = 'i';
285 nrinterfaces--;
286 }
287 }
288 }
289
290 static int
291 calcbucket(char *p)
292 {
293 int bucket = 0;
294
295 while (*p)
296 bucket += *p++;
297
298 return bucket & (NUMIFHASH-1);
299 }
300
301 /*
302 ** function gathers the properties of a particular physical interface;
303 ** the name of the interface should have been filled before calling
304 **
305 ** return value reflects true (success) or false (unknown interface type)
306 */
307 static int
308 getphysprop(struct ifprop *p)
309 {
310 int sockfd;
311
312 #ifdef ETHTOOL_GLINKSETTINGS
313 struct ethtool_link_settings *ethlink; // preferred!
314 #endif
315 struct ethtool_cmd ethcmd; // deprecated
316
317 struct ifreq ifreq;
318 struct iwreq iwreq;
319
320 unsigned long speed = 0;
321 unsigned char duplex = 0, ethernet = 0;
322
323
324 if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
325 return 0;
326
327 /*
328 ** determine properties of ethernet interface
329 ** preferably with actual struct ethtool_link_settings,
330 ** otherwise with deprecated struct ethtool_cmd
331 */
332 memset(&ifreq, 0, sizeof ifreq);
333
334 strncpy((void *)&ifreq.ifr_ifrn.ifrn_name, p->name,
335 sizeof ifreq.ifr_ifrn.ifrn_name-1);
336
337 #ifdef ETHTOOL_GLINKSETTINGS
338 ethlink = calloc(1, sizeof *ethlink);
339
340 ptrverify(ethlink, "Calloc failed for ethtool_link_settings\n");
341
342 ethlink->cmd = ETHTOOL_GLINKSETTINGS;
343
344 ifreq.ifr_ifru.ifru_data = (void *)ethlink;
345
346 if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) == 0)
347 {
348 if (ethlink->link_mode_masks_nwords <= 0)
349 {
350 /*
351 ** hand shaked ethlink required with added maps
352 **
353 ** layout of link_mode_masks fields:
354 ** __u32 map_supported[link_mode_masks_nwords];
355 ** __u32 map_advertising[link_mode_masks_nwords];
356 ** __u32 map_lp_advertising[link_mode_masks_nwords];
357 */
358 ethlink->link_mode_masks_nwords = -ethlink->link_mode_masks_nwords;
359
360 ethlink = realloc(ethlink, sizeof *ethlink +
361 3 * sizeof(__u32) * ethlink->link_mode_masks_nwords);
362
363 ptrverify(ethlink, "Realloc failed for ethtool_link_settings\n");
364
365 ifreq.ifr_ifru.ifru_data = (void *)ethlink; // might have changed
366
367 if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) != 0 )
368 {
369 close(sockfd);
370 free(ethlink);
371 return 0;
372 }
373 }
374
375 ethernet = 1;
376 speed = ethlink->speed;
377 duplex = ethlink->duplex;
378
379 free(ethlink);
380 }
381 else
382 #endif
383 {
384 memset(ðcmd, 0, sizeof ethcmd);
385
386 ethcmd.cmd = ETHTOOL_GSET;
387 ifreq.ifr_ifru.ifru_data = (void *)ðcmd;
388
389 if ( ioctl(sockfd, SIOCETHTOOL, &ifreq) == 0)
390 {
391 ethernet = 1;
392 speed = ethcmd.speed;
393 duplex = ethcmd.duplex;
394 }
395 }
396
397 if (ethernet)
398 {
399 p->type = 'e'; // type ethernet
400
401 if (speed == (u32)SPEED_UNKNOWN || speed == 65535)
402 p->speed = 0;
403 else
404 p->speed = speed;
405
406 switch (duplex)
407 {
408 case DUPLEX_FULL:
409 p->fullduplex = 1;
410 break;
411 default:
412 p->fullduplex = 0;
413 }
414 }
415 else
416 {
417 /*
418 ** determine properties of wireless interface
419 */
420 memset(&iwreq, 0, sizeof iwreq);
421
422 strncpy(iwreq.ifr_ifrn.ifrn_name, p->name,
423 sizeof iwreq.ifr_ifrn.ifrn_name-1);
424
425 if ( ioctl(sockfd, SIOCGIWRATE, &iwreq) == 0)
426 {
427 p->type = 'w'; // type wireless
428 p->fullduplex = 0;
429 p->speed = (iwreq.u.bitrate.value + 500000) / 1000000;
430 }
431 else
432 {
433 p->type = '?'; // type unknown
434 p->fullduplex = 0;
435 p->speed = 0;
436 }
437 }
438
439 close(sockfd);
440
441 return 1;
442 }