2
* Copyright (C) 2003 Sun Microsystems, Inc.
3
* Copyright (C) 2004 Red Hat Inc.
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21
* Erwann Chenede <erwann.chenede@sun.com>
22
* Mark McLoughlin <mark@skynet.ie>
23
* Joe Marcus Clarke <marcus@freebsd.org>
28
#include "netstatus-sysdeps.h"
36
#include <glib/gi18n.h>
39
#include <sys/types.h>
40
#include <sys/socket.h>
41
#include <sys/ioctl.h>
43
#include <net/if_var.h>
44
#include <dev/an/if_aironet_ieee.h>
45
#include <dev/wi/if_wavelan_ieee.h>
48
static inline gboolean
49
parse_stats (char *buf,
62
p = strtok (buf, " \t\n");
63
for (i = 0; p; i++, p = strtok (NULL, " \t\n"))
66
*in_packets = g_ascii_strtoull (p, NULL, 10);
68
*out_packets = g_ascii_strtoull (p, NULL, 10);
70
*in_bytes = g_ascii_strtoull (p, NULL, 10);
72
*out_bytes = g_ascii_strtoull (p, NULL, 10);
75
if (i <= prx_idx || i <= ptx_idx || i <= brx_idx || i <=btx_idx)
81
#if !defined (__FreeBSD__)
84
parse_iface_name (const char *buf)
88
if ((p1 = strchr (buf, ':')))
92
p2 = strchr (p1, ':');
100
else if ((p1 = strchr (buf, ' ')))
110
parse_stats_header (char *buf,
119
*prx_idx = *ptx_idx = -1;
120
*brx_idx = *btx_idx = -1;
122
p = strtok (buf, "| \t\n");
123
p = strtok (NULL, "| \t\n"); /* Skip the first one */
124
for (i = 0; p; i++, p = strtok (NULL, "| \t\n"))
126
if (!strcmp (p, "packets"))
133
else if (!strcmp (p, "bytes"))
144
get_proc_net_dev_fh (void)
146
static FILE *retval = NULL;
151
return retval = fopen ("/proc/net/dev", "r");
155
netstatus_sysdeps_read_iface_statistics (const char *iface,
163
int prx_idx, ptx_idx;
164
int brx_idx, btx_idx;
165
char *error_message = NULL;
167
g_return_val_if_fail (iface != NULL, NULL);
168
g_return_val_if_fail (in_packets != NULL, NULL);
169
g_return_val_if_fail (out_packets != NULL, NULL);
170
g_return_val_if_fail (in_bytes != NULL, NULL);
171
g_return_val_if_fail (out_bytes != NULL, NULL);
178
fh = get_proc_net_dev_fh ();
180
return g_strdup_printf (_("Cannot open /proc/net/dev: %s"),
183
fgets (buf, sizeof (buf), fh);
184
fgets (buf, sizeof (buf), fh);
186
parse_stats_header (buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx);
187
if (prx_idx == -1 || ptx_idx == -1 ||
188
brx_idx == -1 || btx_idx == -1)
189
return g_strdup (_("Could not parse /proc/net/dev. Unknown format."));
191
while (fgets (buf, sizeof (buf), fh))
197
while (g_ascii_isspace (name [0]))
200
stats = parse_iface_name (name);
204
error_message = g_strdup_printf (_("Could not parse interface name from '%s'"), buf);
208
if (strcmp (name, iface) != 0)
211
if (!parse_stats (stats,
212
prx_idx, ptx_idx, in_packets, out_packets,
213
brx_idx, btx_idx, in_bytes, out_bytes))
216
g_free (error_message);
217
error_message = g_strdup_printf (_("Could not parse interface statistics from '%s'. "
218
"prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;"),
219
buf, prx_idx, ptx_idx, brx_idx, btx_idx);
226
if ((*in_packets == (gulong) -1 || *out_packets == (gulong) -1 || *in_bytes == (gulong) -1 || *out_bytes == (gulong) -1) && !error_message)
227
error_message = g_strdup_printf ("Could not find information on interface '%s' in /proc/net/dev", iface);
232
return error_message;
235
static inline gboolean
236
parse_wireless (char *buf,
243
p = strtok (buf, " \t\n");
244
for (i = 0; p; i++, p = strtok (NULL, " \t\n"))
247
*link = g_ascii_strtoull (p, NULL, 10);
257
parse_wireless_header (char *buf)
262
p = strtok (buf, "| \t\n");
263
p = strtok (NULL, "| \t\n"); /* Skip the first one */
264
for (i = 0; p; i++, p = strtok (NULL, "| \t\n"))
266
if (!strcmp (p, "link"))
276
get_proc_net_wireless_fh (void)
278
static FILE *retval = NULL;
283
return retval = fopen ("/proc/net/wireless", "r");
287
netstatus_sysdeps_read_iface_wireless_details (const char *iface,
288
gboolean *is_wireless,
289
int *signal_strength)
294
char *error_message = NULL;
296
g_return_val_if_fail (iface != NULL, NULL);
297
g_return_val_if_fail (is_wireless != NULL, NULL);
298
g_return_val_if_fail (signal_strength != NULL, NULL);
301
*is_wireless = FALSE;
303
*signal_strength = 0;
305
fh = get_proc_net_wireless_fh ();
309
fgets (buf, sizeof (buf), fh);
310
fgets (buf, sizeof (buf), fh);
312
link_idx = parse_wireless_header (buf);
314
return g_strdup (_("Could not parse /proc/net/wireless. Unknown format."));
316
while (fgets (buf, sizeof (buf), fh))
323
while (g_ascii_isspace (name [0]))
326
details = parse_iface_name (name);
330
error_message = g_strdup_printf (_("Could not parse interface name from '%s'"), buf);
334
if (strcmp (name, iface) != 0)
337
if (!parse_wireless (details, link_idx, &link))
340
g_free (error_message);
341
error_message = g_strdup_printf (_("Could not parse wireless details from '%s'. link_idx = %d;"),
346
/* Stolen from the wireless applet */
347
*signal_strength = (int) rint ((log (link) / log (92)) * 100.0);
348
*signal_strength = CLAMP (*signal_strength, 0, 100);
357
return error_message;
360
#else /* defined(__FreeBSD__) */
363
parse_header (char *buf,
372
*prx_idx = *ptx_idx = -1;
373
*brx_idx = *btx_idx = -1;
375
p = strtok (buf, " \n\t");
376
for (i = 0; p; i++, p = strtok (NULL, " \t\n"))
378
if (!strcmp (p, "Ipkts"))
382
else if (!strcmp (p, "Ibytes"))
386
else if (!strcmp (p, "Opkts"))
390
else if (!strcmp (p, "Obytes"))
397
static inline gboolean
398
wireless_getval (const char *iface,
400
unsigned long req_type,
406
memset (&ifr, 0, sizeof (ifr));
408
strlcpy (ifr.ifr_name, iface, sizeof (ifr.ifr_name));
409
ifr.ifr_data = (caddr_t) req;
411
s = socket (AF_INET, SOCK_DGRAM, 0);
414
*error = g_strdup_printf (_("Could not connect to interface, '%s'"), iface);
418
if (ioctl (s, req_type, &ifr) == -1)
420
*error = g_strdup_printf (_("Could not send ioctl to interface, '%s'"), iface);
430
get_an_data (const char *iface,
431
int *signal_strength)
433
#ifdef AN_RID_RSSI_MAP
434
struct an_ltv_rssi_map an_rssimap;
437
struct an_ltv_status *sts;
440
gboolean rssimap_valid = FALSE;
442
#ifdef AN_RID_RSSI_MAP
443
an_rssimap.an_len = sizeof (an_rssimap);
444
an_rssimap.an_type = AN_RID_RSSI_MAP;
445
rssimap_valid = wireless_getval (iface, (gpointer) &an_rssimap, SIOCGAIRONET, &error);
448
areq.an_len = sizeof (areq);
449
areq.an_type = AN_RID_STATUS;
451
if (!wireless_getval (iface, (gpointer) &areq, SIOCGAIRONET, &error))
454
sts = (struct an_ltv_status *) &areq;
456
#ifdef AN_RID_RSSI_MAP
458
level = (int) (an_rssimap.an_entries[sts->an_normalized_strength].an_rss_pct);
460
level = (int) (sts->an_normalized_strength);
462
level = (int) (sts->an_normalized_rssi);
465
memcpy (signal_strength, &level, sizeof (signal_strength));
471
get_wi_data (const char *iface,
472
int *signal_strength)
478
memset (&wreq, 0, sizeof (wreq));
480
wreq.wi_len = WI_MAX_DATALEN;
481
wreq.wi_type = WI_RID_COMMS_QUALITY;
483
if (!wireless_getval (iface, &wreq, SIOCGWAVELAN, &error))
486
level = (int) wreq.wi_val[1];
488
#ifdef WI_RID_READ_APS
489
if (signal_strength <= 0)
491
/* we fail to get signal strength by usual means, try another way */
492
static time_t last_scan;
493
static long int cached;
498
/* XXX: this is long operation, and we will scan station not often then one in 5 secs */
499
if (now > last_scan + 5)
504
bzero (&wreq, sizeof (wreq));
505
wreq.wi_len = WI_MAX_DATALEN;
506
wreq.wi_type = WI_RID_READ_APS;
507
if (!wireless_getval (iface, &wreq, SIOCGWAVELAN, &error))
509
nstations = *(int *) wreq.wi_val;
512
w = (struct wi_apinfo *)(((char *) &wreq.wi_val) + sizeof (int));
513
signal_strength = (long int) w->signal;
516
cached = signal_strength;
521
signal_strength = cached;
526
memcpy (signal_strength, &level, sizeof (signal_strength));
532
netstatus_sysdeps_read_iface_wireless_details (const char *iface,
533
gboolean *is_wireless,
534
int *signal_strength)
536
char *error_message = NULL;
538
g_return_val_if_fail (iface != NULL, NULL);
539
g_return_val_if_fail (is_wireless != NULL, NULL);
540
g_return_val_if_fail (signal_strength != NULL, NULL);
543
*is_wireless = FALSE;
545
*signal_strength = 0;
547
if (g_strncasecmp (iface, "an", 2) &&
548
g_strncasecmp (iface, "wi", 2) &&
549
g_strncasecmp (iface, "ath", 3) &&
550
g_strncasecmp (iface, "ndis", 4) &&
551
g_strncasecmp (iface, "ipw", 3) &&
552
g_strncasecmp (iface, "iwi", 3) &&
553
g_strncasecmp (iface, "acx", 3))
554
return error_message;
556
if (g_strncasecmp (iface, "an", 2) == 0)
558
error_message = get_an_data (iface, signal_strength);
563
error_message = get_wi_data (iface, signal_strength);
567
return error_message;
571
netstatus_sysdeps_read_iface_statistics (const char *iface,
580
char *error_message = NULL;
583
g_return_val_if_fail (iface != NULL, NULL);
584
g_return_val_if_fail (in_packets != NULL, NULL);
585
g_return_val_if_fail (out_packets != NULL, NULL);
586
g_return_val_if_fail (in_bytes != NULL, NULL);
587
g_return_val_if_fail (out_bytes != NULL, NULL);
595
command_line = g_strdup_printf ("/usr/bin/netstat -n -I %s -b -f inet", iface);
596
if (!g_shell_parse_argv (command_line, NULL, &argv, &error))
598
error_message = g_strdup_printf (_("Could not parse command line '%s': %s"),
601
g_error_free (error);
602
g_free (command_line);
604
return error_message;
606
g_free (command_line);
609
if (g_spawn_async_with_pipes (NULL,
623
int prx_idx, ptx_idx;
624
int brx_idx, btx_idx;
626
channel = g_io_channel_unix_new (pipe_out);
628
g_io_channel_read_line (channel, &buf, NULL, NULL, NULL);
629
parse_header (buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx);
632
if (prx_idx == -1 || ptx_idx == -1 ||
633
brx_idx == -1 || btx_idx == -1)
635
error_message = g_strdup (_("Could not parse 'netstat' output. Unknown format"));
639
g_io_channel_read_line (channel, &buf, NULL, NULL, NULL);
641
if (!parse_stats (buf,
642
prx_idx, ptx_idx, in_packets, out_packets,
643
brx_idx, btx_idx, in_bytes, out_bytes))
645
error_message = g_strdup_printf (_("Could not parse interface statistics from '%s'. "
646
"prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;"),
647
buf, prx_idx, ptx_idx, brx_idx, btx_idx);
649
else if (*in_packets == -1 || *out_packets == -1 || *in_bytes == -1 || *out_bytes == -1)
651
error_message = g_strdup_printf ("Could not obtain information on interface '%s' from netstat",
658
g_io_channel_unref (channel);
663
error_message = g_strdup_printf ("Error running /usr/bin/netstat for '%s': %s",
664
iface, error->message);
665
g_error_free (error);
670
return error_message;
673
#endif /* !defined(__FreeBSD__) */