Enabling multithreaded compilation.
[debian/lxpanel.git] / src / plugins / netstatus / netstatus-iface.c
1 /*
2 * Copyright (C) 2003 Sun Microsystems, Inc.
3 * Copyright (C) 2004 Red Hat Inc.
4 *
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.
9 *
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.
14 *
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
18 * 02111-1307, USA.
19 *
20 * Authors:
21 * Erwann Chenede <erwann.chenede@sun.com>
22 * Mark McLoughlin <mark@skynet.ie>
23 *
24 * Support for the various hardware types is adapted from the
25 * net-tools package (version 1.60) which is also distributed
26 * under the GNU General Public License. The code used below
27 * is Copyright (C) 1993 MicroWalt Corporation.
28 */
29
30 #include <config.h>
31
32 #include "netstatus-iface.h"
33
34 #include <glib/gi18n.h>
35
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #ifdef HAVE_SYS_SOCKIO_H
39 #include <sys/sockio.h>
40 #endif /* HAVE_SYS_SOCKIO_H */
41 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <net/if.h>
44 #include <net/if_arp.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <string.h>
50
51 #include "netstatus-sysdeps.h"
52 #include "netstatus-enums.h"
53
54 #define NETSTATUS_IFACE_POLL_DELAY 500 /* milliseconds between polls */
55 #define NETSTATUS_IFACE_POLLS_IN_ERROR 10 /* no. of polls in error before increasing delay */
56 #define NETSTATUS_IFACE_ERROR_POLL_DELAY 5000 /* delay to use when in error state */
57
58 enum
59 {
60 PROP_0,
61 PROP_NAME,
62 PROP_STATE,
63 PROP_STATS,
64 PROP_WIRELESS,
65 PROP_SIGNAL_STRENGTH,
66 PROP_ERROR
67 };
68
69 struct _NetstatusIfacePrivate
70 {
71 char *name;
72
73 NetstatusState state;
74 NetstatusStats stats;
75 int signal_strength;
76 GError *error;
77
78 int sockfd;
79 guint monitor_id;
80
81 guint error_polling : 1;
82 guint is_wireless : 1;
83 };
84
85 static void netstatus_iface_instance_init (NetstatusIface *iface,
86 NetstatusIfaceClass *klass);
87 static void netstatus_iface_class_init (NetstatusIfaceClass *klass);
88 static void netstatus_iface_finalize (GObject *object);
89 static void netstatus_iface_set_property (GObject *object,
90 guint property_id,
91 const GValue *value,
92 GParamSpec *pspec);
93 static void netstatus_iface_get_property (GObject *object,
94 guint property_id,
95 GValue *value,
96 GParamSpec *pspec);
97 static gboolean netstatus_iface_monitor_timeout (NetstatusIface *iface);
98 static void netstatus_iface_init_monitor (NetstatusIface *iface);
99
100 static GObjectClass *parent_class;
101
102 GType
103 netstatus_iface_get_type (void)
104 {
105 static GType type = 0;
106 if (!type)
107 {
108 static const GTypeInfo info =
109 {
110 sizeof (NetstatusIfaceClass),
111 NULL,
112 NULL,
113 (GClassInitFunc) netstatus_iface_class_init,
114 NULL,
115 NULL,
116 sizeof (NetstatusIface),
117 0,
118 (GInstanceInitFunc) netstatus_iface_instance_init,
119 NULL
120 };
121 type = g_type_register_static (G_TYPE_OBJECT, "NetstatusIface", &info, 0);
122 }
123 return type;
124 }
125
126 static void
127 netstatus_iface_instance_init (NetstatusIface *iface,
128 NetstatusIfaceClass *klass __attribute__((unused)))
129 {
130 iface->priv = g_new0 (NetstatusIfacePrivate, 1);
131 iface->priv->state = NETSTATUS_STATE_DISCONNECTED;
132 }
133
134 static void
135 netstatus_iface_class_init (NetstatusIfaceClass *klass)
136 {
137 GObjectClass *gobject_class = (GObjectClass *) klass;
138
139 parent_class = g_type_class_peek_parent (klass);
140
141 gobject_class->finalize = netstatus_iface_finalize;
142 gobject_class->get_property = netstatus_iface_get_property;
143 gobject_class->set_property = netstatus_iface_set_property;
144
145 g_object_class_install_property (gobject_class,
146 PROP_NAME,
147 g_param_spec_string ("name",
148 _("Name"),
149 _("The interface name"),
150 NULL,
151 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
152
153 g_object_class_install_property (gobject_class,
154 PROP_STATE,
155 g_param_spec_enum ("state",
156 _("State"),
157 _("The interface state"),
158 NETSTATUS_TYPE_STATE,
159 NETSTATUS_STATE_DISCONNECTED,
160 G_PARAM_READABLE));
161
162 g_object_class_install_property (gobject_class,
163 PROP_STATS,
164 g_param_spec_boxed ("stats",
165 _("Stats"),
166 _("The interface packets/bytes statistics"),
167 NETSTATUS_TYPE_STATS,
168 G_PARAM_READABLE));
169
170 g_object_class_install_property (gobject_class,
171 PROP_WIRELESS,
172 g_param_spec_boolean ("wireless",
173 _("Wireless"),
174 _("Whether the interface is a wireless interface"),
175 FALSE,
176 G_PARAM_READABLE));
177
178 g_object_class_install_property (gobject_class,
179 PROP_SIGNAL_STRENGTH,
180 g_param_spec_int ("signal-strength",
181 _("Signal"),
182 _("Wireless signal strength percentage"),
183 0,
184 100,
185 0,
186 G_PARAM_READABLE));
187
188 g_object_class_install_property (gobject_class,
189 PROP_ERROR,
190 g_param_spec_boxed ("error",
191 _("Error"),
192 _("The current error condition"),
193 NETSTATUS_TYPE_G_ERROR,
194 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
195 }
196
197 static void
198 netstatus_iface_finalize (GObject *object)
199 {
200 NetstatusIface *iface = (NetstatusIface *) object;
201
202 if (iface->priv->error)
203 g_error_free (iface->priv->error);
204 iface->priv->error = NULL;
205
206 if (iface->priv->monitor_id)
207 g_source_remove (iface->priv->monitor_id);
208 iface->priv->monitor_id = 0;
209
210 if (iface->priv->sockfd)
211 close (iface->priv->sockfd);
212 iface->priv->sockfd = 0;
213
214 g_free (iface->priv->name);
215 iface->priv->name = NULL;
216
217 g_free (iface->priv);
218 iface->priv = NULL;
219
220 parent_class->finalize (object);
221 }
222
223 static void
224 netstatus_iface_set_property (GObject *object,
225 guint property_id,
226 const GValue *value,
227 GParamSpec *pspec)
228 {
229 NetstatusIface *iface = (NetstatusIface *) object;
230
231 switch (property_id)
232 {
233 case PROP_NAME:
234 netstatus_iface_set_name (iface, g_value_get_string (value));
235 break;
236 case PROP_ERROR:
237 netstatus_iface_set_error (iface, g_value_get_boxed (value));
238 break;
239 default:
240 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
241 break;
242 }
243 }
244
245 static void
246 netstatus_iface_get_property (GObject *object,
247 guint property_id,
248 GValue *value,
249 GParamSpec *pspec)
250 {
251 NetstatusIface *iface = (NetstatusIface *) object;
252
253 switch (property_id)
254 {
255 case PROP_NAME:
256 g_value_set_string (value, iface->priv->name);
257 break;
258 case PROP_STATE:
259 g_value_set_enum (value, iface->priv->state);
260 break;
261 case PROP_STATS:
262 g_value_set_boxed (value, &iface->priv->stats);
263 break;
264 case PROP_WIRELESS:
265 g_value_set_boolean (value, iface->priv->is_wireless);
266 break;
267 case PROP_SIGNAL_STRENGTH:
268 g_value_set_int (value, iface->priv->signal_strength);
269 break;
270 case PROP_ERROR:
271 g_value_set_boxed (value, iface->priv->error);
272 default:
273 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
274 break;
275 }
276 }
277
278 NetstatusIface *
279 netstatus_iface_new (const char *name)
280 {
281 return g_object_new (NETSTATUS_TYPE_IFACE,
282 "name", name,
283 NULL);
284 }
285
286 void
287 netstatus_iface_set_name (NetstatusIface *iface,
288 const char *name)
289 {
290 g_return_if_fail (NETSTATUS_IS_IFACE (iface));
291
292 if (iface->priv->name && name &&
293 !strcmp (iface->priv->name, name))
294 return;
295
296 if (name && strlen (name) >= IF_NAMESIZE)
297 {
298 g_warning (G_STRLOC ": interface name '%s' is too long\n", name);
299 return;
300 }
301
302 if (iface->priv->name)
303 g_free (iface->priv->name);
304 iface->priv->name = g_strdup (name);
305
306 netstatus_iface_init_monitor (iface);
307
308 g_object_notify (G_OBJECT (iface), "name");
309 }
310
311 G_CONST_RETURN char *
312 netstatus_iface_get_name (NetstatusIface *iface)
313 {
314 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), NULL);
315
316 return iface->priv->name;
317 }
318
319 NetstatusState
320 netstatus_iface_get_state (NetstatusIface *iface)
321 {
322 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), NETSTATUS_STATE_DISCONNECTED);
323
324 return iface->priv->state;
325 }
326
327 void
328 netstatus_iface_get_statistics (NetstatusIface *iface,
329 NetstatusStats *stats)
330 {
331 g_return_if_fail (NETSTATUS_IS_IFACE (iface));
332
333 if (stats)
334 *stats = iface->priv->stats;
335 }
336
337 gboolean
338 netstatus_iface_get_is_wireless (NetstatusIface *iface)
339 {
340 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
341
342 return iface->priv->is_wireless;
343 }
344
345 int
346 netstatus_iface_get_signal_strength (NetstatusIface *iface)
347 {
348 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), 0);
349
350 return iface->priv->signal_strength;
351 }
352
353 void
354 netstatus_iface_set_error (NetstatusIface *iface,
355 const GError *error)
356 {
357 g_return_if_fail (NETSTATUS_IS_IFACE (iface));
358
359 if (iface->priv->state != NETSTATUS_STATE_ERROR && error)
360 {
361 g_assert (iface->priv->error == NULL);
362
363 iface->priv->state = NETSTATUS_STATE_ERROR;
364 iface->priv->error = g_error_copy (error);
365
366 g_object_notify (G_OBJECT (iface), "state");
367 g_object_notify (G_OBJECT (iface), "error");
368 }
369 }
370
371 G_CONST_RETURN GError *
372 netstatus_iface_get_error (NetstatusIface *iface)
373 {
374 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), NULL);
375
376 return iface->priv->error;
377 }
378
379 void
380 netstatus_iface_clear_error (NetstatusIface *iface,
381 NetstatusError code)
382 {
383 g_return_if_fail (NETSTATUS_IS_IFACE (iface));
384
385 if (iface->priv->state == NETSTATUS_STATE_ERROR &&
386 g_error_matches (iface->priv->error, NETSTATUS_ERROR, code))
387 {
388 iface->priv->state = NETSTATUS_STATE_DISCONNECTED;
389
390 g_error_free (iface->priv->error);
391 iface->priv->error = NULL;
392
393 g_object_notify (G_OBJECT (iface), "state");
394 g_object_notify (G_OBJECT (iface), "error");
395 }
396 }
397
398 static void
399 netstatus_iface_set_polling_error (NetstatusIface *iface,
400 NetstatusError code,
401 const char *format,
402 ...)
403 {
404 GError *error;
405 va_list args;
406 char *error_message;
407
408 va_start (args, format);
409
410 error_message = g_strdup_vprintf (format, args);
411 error = g_error_new (NETSTATUS_ERROR, code, error_message);
412
413 dprintf (POLLING, "ERROR: %s\n", error->message);
414 netstatus_iface_set_error (iface, error);
415
416 g_error_free (error);
417 g_free (error_message);
418
419 va_end (args);
420 }
421
422 static int
423 netstatus_iface_get_sockfd (NetstatusIface *iface)
424 {
425 int fd;
426
427 if (iface->priv->sockfd)
428 return iface->priv->sockfd;
429
430 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
431 {
432 netstatus_iface_set_polling_error (iface,
433 NETSTATUS_ERROR_SOCKET,
434 _("Unable to open socket: %s"),
435 g_strerror (errno));
436 return 0;
437 }
438
439 dprintf (POLLING, "Successfully opened socket for polling\n");
440 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_SOCKET);
441
442 iface->priv->sockfd = fd;
443
444 return iface->priv->sockfd;
445 }
446
447 static gboolean
448 netstatus_iface_poll_iface_statistics (NetstatusIface *iface,
449 gulong *in_packets,
450 gulong *out_packets,
451 gulong *in_bytes,
452 gulong *out_bytes)
453 {
454 char *error_message;
455
456 error_message = netstatus_sysdeps_read_iface_statistics (iface->priv->name,
457 in_packets,
458 out_packets,
459 in_bytes,
460 out_bytes);
461 if (error_message)
462 {
463 netstatus_iface_set_polling_error (iface,
464 NETSTATUS_ERROR_STATISTICS,
465 error_message);
466 g_free (error_message);
467
468 return FALSE;
469 }
470
471 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_STATISTICS);
472
473 return TRUE;
474 }
475
476 static NetstatusState
477 netstatus_iface_poll_state (NetstatusIface *iface)
478 {
479 NetstatusState state;
480 struct ifreq if_req;
481 gboolean tx, rx;
482 int fd;
483 gulong in_packets, out_packets;
484 gulong in_bytes, out_bytes;
485
486 if (!(fd = netstatus_iface_get_sockfd (iface)))
487 return NETSTATUS_STATE_DISCONNECTED;
488
489 memset (&if_req, 0, sizeof (struct ifreq));
490 strcpy (if_req.ifr_name, iface->priv->name);
491
492 if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0)
493 {
494 netstatus_iface_set_polling_error (iface,
495 NETSTATUS_ERROR_IOCTL_IFFLAGS,
496 _("SIOCGIFFLAGS error: %s"),
497 g_strerror (errno));
498 return NETSTATUS_STATE_DISCONNECTED;
499 }
500
501 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_IOCTL_IFFLAGS);
502
503 dprintf (POLLING, "Interface is %sup and %srunning\n",
504 if_req.ifr_flags & IFF_UP ? "" : "not ",
505 if_req.ifr_flags & IFF_RUNNING ? "" : "not ");
506
507 if (!(if_req.ifr_flags & IFF_UP) || !(if_req.ifr_flags & IFF_RUNNING))
508 return NETSTATUS_STATE_DISCONNECTED;
509
510 if (!netstatus_iface_poll_iface_statistics (iface, &in_packets, &out_packets, &in_bytes, &out_bytes))
511 return NETSTATUS_STATE_IDLE;
512
513 dprintf (POLLING, "Packets in: %ld out: %ld. Prev in: %ld out: %ld\n",
514 in_packets, out_packets,
515 iface->priv->stats.in_packets, iface->priv->stats.out_packets);
516 dprintf (POLLING, "Bytes in: %ld out: %ld. Prev in: %ld out: %ld\n",
517 in_bytes, out_bytes,
518 iface->priv->stats.in_bytes, iface->priv->stats.out_bytes);
519
520 rx = in_packets > iface->priv->stats.in_packets;
521 tx = out_packets > iface->priv->stats.out_packets;
522
523 if (!tx && !rx)
524 state = NETSTATUS_STATE_IDLE;
525 else if (tx && rx)
526 state = NETSTATUS_STATE_TX_RX;
527 else if (tx)
528 state = NETSTATUS_STATE_TX;
529 else /* if (rx) */
530 state = NETSTATUS_STATE_RX;
531
532 dprintf (POLLING, "State: %s\n", netstatus_get_state_string (state));
533
534 if (tx || rx)
535 {
536 iface->priv->stats.in_packets = in_packets;
537 iface->priv->stats.out_packets = out_packets;
538 iface->priv->stats.in_bytes = in_bytes;
539 iface->priv->stats.out_bytes = out_bytes;
540
541 g_object_notify (G_OBJECT (iface), "stats");
542 }
543
544 return state;
545 }
546
547 static gboolean
548 netstatus_iface_poll_wireless_details (NetstatusIface *iface,
549 int *signal_strength)
550 {
551 char *error_message;
552 gboolean is_wireless;
553
554 error_message = netstatus_sysdeps_read_iface_wireless_details (iface->priv->name,
555 &is_wireless,
556 signal_strength);
557
558 if (error_message)
559 {
560 netstatus_iface_set_polling_error (iface,
561 NETSTATUS_ERROR_WIRELESS_DETAILS,
562 error_message);
563 g_free (error_message);
564
565 return FALSE;
566 }
567
568 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_WIRELESS_DETAILS);
569
570 return is_wireless;
571 }
572
573 static void
574 netstatus_iface_increase_poll_delay_in_error (NetstatusIface *iface)
575 {
576 static int polls_in_error = 0;
577
578 if (iface->priv->state == NETSTATUS_STATE_ERROR)
579 {
580 dprintf (POLLING, "Interface in error state\n");
581
582 if (!iface->priv->error_polling &&
583 ++polls_in_error >= NETSTATUS_IFACE_POLLS_IN_ERROR)
584 {
585 dprintf (POLLING, "Increasing polling delay after too many errors\n");
586 iface->priv->error_polling = TRUE;
587 g_source_remove (iface->priv->monitor_id);
588 iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_ERROR_POLL_DELAY,
589 (GSourceFunc) netstatus_iface_monitor_timeout,
590 iface);
591 }
592 }
593 else if (iface->priv->error_polling)
594 {
595 dprintf (POLLING, "Recovered from errors. Increasing polling delay again\n");
596
597 iface->priv->error_polling = FALSE;
598 polls_in_error = 0;
599
600 g_source_remove (iface->priv->monitor_id);
601 iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_POLL_DELAY,
602 (GSourceFunc) netstatus_iface_monitor_timeout,
603 iface);
604 }
605 }
606
607 static gboolean
608 netstatus_iface_monitor_timeout (NetstatusIface *iface)
609 {
610 NetstatusState state;
611 int signal_strength;
612 gboolean is_wireless;
613
614 state = netstatus_iface_poll_state (iface);
615
616 if (iface->priv->state != state &&
617 iface->priv->state != NETSTATUS_STATE_ERROR)
618 {
619 iface->priv->state = state;
620 g_object_notify (G_OBJECT (iface), "state");
621 }
622
623 is_wireless = netstatus_iface_poll_wireless_details (iface, &signal_strength);
624 if (iface->priv->is_wireless != is_wireless)
625 {
626 iface->priv->is_wireless = is_wireless;
627 g_object_notify (G_OBJECT (iface), "wireless");
628 }
629
630 if (iface->priv->signal_strength != signal_strength)
631 {
632 iface->priv->signal_strength = signal_strength;
633 g_object_notify (G_OBJECT (iface), "signal-strength");
634 }
635
636 netstatus_iface_increase_poll_delay_in_error (iface);
637
638 return TRUE;
639 }
640
641 static void
642 netstatus_iface_init_monitor (NetstatusIface *iface)
643 {
644 iface->priv->stats.in_packets = 0;
645 iface->priv->stats.out_packets = 0;
646 iface->priv->stats.in_bytes = 0;
647 iface->priv->stats.out_bytes = 0;
648 iface->priv->signal_strength = 0;
649 iface->priv->is_wireless = FALSE;
650
651 g_object_freeze_notify (G_OBJECT (iface));
652 g_object_notify (G_OBJECT (iface), "state");
653 g_object_notify (G_OBJECT (iface), "wireless");
654 g_object_notify (G_OBJECT (iface), "signal-strength");
655 g_object_thaw_notify (G_OBJECT (iface));
656
657 if (iface->priv->monitor_id)
658 {
659 dprintf (POLLING, "Removing existing monitor\n");
660 g_source_remove (iface->priv->monitor_id);
661 iface->priv->monitor_id = 0;
662 }
663
664 if (iface->priv->name)
665 {
666 dprintf (POLLING, "Initialising monitor with delay of %d\n", NETSTATUS_IFACE_POLL_DELAY);
667 iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_POLL_DELAY,
668 (GSourceFunc) netstatus_iface_monitor_timeout,
669 iface);
670
671 netstatus_iface_monitor_timeout (iface);
672 }
673 }
674
675 gboolean
676 netstatus_iface_get_inet4_details (NetstatusIface *iface,
677 char **addr,
678 char **dest,
679 char **bcast,
680 char **mask)
681 {
682 struct ifreq if_req;
683 int fd;
684 int flags;
685
686 if (addr)
687 *addr = NULL;
688 if (dest)
689 *dest = NULL;
690 if (mask)
691 *mask = NULL;
692
693 if (!iface->priv->name)
694 return FALSE;
695
696 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
697 {
698 g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n",
699 g_strerror (errno));
700 return FALSE;
701 }
702
703 if_req.ifr_addr.sa_family = AF_INET;
704
705 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
706 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
707 if (addr && ioctl (fd, SIOCGIFADDR, &if_req) == 0)
708 *addr = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr));
709
710 if (addr && !*addr)
711 {
712 close (fd);
713 return FALSE;
714 }
715
716 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
717 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
718 if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0)
719 {
720 close (fd);
721 return TRUE;
722 }
723
724 flags = if_req.ifr_flags;
725
726 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
727 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
728 if (dest && flags & IFF_POINTOPOINT &&
729 ioctl (fd, SIOCGIFDSTADDR, &if_req) == 0)
730 *dest = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_dstaddr)->sin_addr));
731
732 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
733 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
734 if (bcast && flags & IFF_BROADCAST &&
735 ioctl (fd, SIOCGIFBRDADDR, &if_req) == 0)
736 *bcast = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_broadaddr)->sin_addr));
737
738 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
739 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
740 if (mask && ioctl (fd, SIOCGIFNETMASK, &if_req) == 0)
741 *mask = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr));
742
743 close (fd);
744
745 return TRUE;
746 }
747
748 static char *
749 print_mac_addr (guchar *p)
750 {
751 return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
752 p [0] & 0377,
753 p [1] & 0377,
754 p [2] & 0377,
755 p [3] & 0377,
756 p [4] & 0377,
757 p [5] & 0377);
758 }
759
760 static char *
761 print_ash_addr (guchar *p)
762 {
763 #define ASH_ALEN 64
764
765 GString *str;
766 char *retval;
767 int i = 0;
768
769 str = g_string_new ("[");
770
771 while (p [i] != 0xc9 && p [i] != 0xff && (i < ASH_ALEN))
772 g_string_append_printf (str, "%1x", p [i++]);
773
774 g_string_append_c (str, ']');
775
776 retval = str->str;
777 g_string_free (str, FALSE);
778
779 return retval;
780
781 #undef ASH_ALEN
782 }
783
784 static char *
785 print_ax25_addr (guchar *p)
786 {
787 GString *str;
788 char *retval;
789 int i;
790
791 str = g_string_new (NULL);
792
793 for (i = 0; i < 6; i++)
794 {
795 char c = (p [i] & 0377) >> 1;
796
797 if (c == ' ')
798 {
799 retval = str->str;
800 g_string_free (str, FALSE);
801
802 return retval;
803 }
804
805 g_string_append_c (str, c);
806 }
807
808 i = (p [6] & 0x1E) >> 1;
809 if (i != 0)
810 g_string_append_printf (str, "-%d", i);
811
812 retval = str->str;
813 g_string_free (str, FALSE);
814
815 return retval;
816 }
817
818 static char *
819 print_rose_addr (guchar *p)
820 {
821 return g_strdup_printf ("%02x%02x%02x%02x%02x", p [0], p [1], p [2], p [3], p [4]);
822 }
823
824 static char *
825 print_x25_addr (guchar *p)
826 {
827 return g_strdup ((const gchar *) p);
828 }
829
830 static char *
831 print_arcnet_addr (guchar *p)
832 {
833 return g_strdup_printf ("%02X", p [0] & 0377);
834 }
835
836 static char *
837 print_dlci_addr (guchar *p)
838 {
839 return g_strdup_printf ("%i", *(short *) p);
840 }
841
842 static char *
843 print_irda_addr (guchar *p)
844 {
845 return g_strdup_printf ("%02x:%02x:%02x:%02x", p [3], p [2], p [1], p [0]);
846 }
847
848 static char *
849 print_econet_addr (guchar *p)
850 {
851 /* This should really be:
852 * #include <neteconet/ec.h>
853 *
854 * struct ec_addr *ec = (struct ec_addr *) p;
855 * return g_strdup_printf ("%d.%d, ec->net, ec->station);
856 *
857 * But I think the hack is safe enough.
858 */
859 return g_strdup_printf ("%d.%d", p [0], p [1]);
860 }
861
862 static struct HwType
863 {
864 int hw_type;
865 char *hw_name;
866 char *(*print_hw_addr) (guchar *p);
867 } hw_types [] =
868 {
869 #ifdef ARPHRD_NETROM
870 { ARPHRD_NETROM, N_("AMPR NET/ROM"), print_ax25_addr },
871 #endif
872 #ifdef ARPHRD_ETHER
873 { ARPHRD_ETHER, N_("Ethernet"), print_mac_addr },
874 #endif
875 #ifdef ARPHRD_EETHER
876 { ARPHRD_EETHER, NULL, NULL },
877 #endif
878 #ifdef ARPHRD_AX25
879 { ARPHRD_AX25, N_("AMPR AX.25"), NULL },
880 #endif
881 #ifdef ARPHRD_PRONET
882 { ARPHRD_PRONET, NULL, NULL },
883 #endif
884 #ifdef ARPHRD_CHAOS
885 { ARPHRD_CHAOS, NULL, NULL },
886 #endif
887 #ifdef ARPHRD_IEEE802
888 { ARPHRD_IEEE802, N_("16/4 Mbps Token Ring"), print_mac_addr },
889 #endif
890 #ifdef ARPHRD_ARCNET
891 { ARPHRD_ARCNET, N_("ARCnet"), print_arcnet_addr },
892 #endif
893 #ifdef ARPHRD_APPLETLK
894 { ARPHRD_APPLETLK, NULL, NULL },
895 #endif
896 #ifdef ARPHRD_DLCI
897 { ARPHRD_DLCI, N_("Frame Relay DLCI"), print_dlci_addr },
898 #endif
899 #ifdef ARPHRD_ATM
900 { ARPHRD_ATM, NULL, NULL },
901 #endif
902 #ifdef ARPHRD_METRICOM
903 { ARPHRD_METRICOM, N_("Metricom Starmode IP"), NULL },
904 #endif
905 #ifdef ARPHRD_SLIP
906 { ARPHRD_SLIP, N_("Serial Line IP"), NULL },
907 #endif
908 #ifdef ARPHRD_CSLIP
909 { ARPHRD_CSLIP, N_("VJ Serial Line IP"), NULL },
910 #endif
911 #ifdef ARPHRD_SLIP6
912 { ARPHRD_SLIP6, N_("6-bit Serial Line IP"), NULL },
913 #endif
914 #ifdef ARPHRD_CSLIP6
915 { ARPHRD_CSLIP6, N_("VJ 6-bit Serial Line IP"), NULL },
916 #endif
917 #ifdef ARPHRD_RSRVD
918 { ARPHRD_RSRVD, NULL, NULL },
919 #endif
920 #ifdef ARPHRD_ADAPT
921 { ARPHRD_ADAPT, N_("Adaptive Serial Line IP"), NULL },
922 #endif
923 #ifdef ARPHRD_ROSE
924 { ARPHRD_ROSE, N_("AMPR ROSE"), print_rose_addr },
925 #endif
926 #ifdef ARPHRD_X25
927 { ARPHRD_X25, N_("Generic X.25"), print_x25_addr },
928 #endif
929 #ifdef ARPHRD_PPP
930 { ARPHRD_PPP, N_("Point-to-Point Protocol"), NULL },
931 #endif
932 #ifdef ARPHRD_CISCO
933 { ARPHRD_CISCO, NULL, NULL },
934 #endif
935 #ifdef ARPHRD_HDLC
936 { ARPHRD_HDLC, N_("(Cisco)-HDLC"), NULL },
937 #endif
938 #ifdef ARPHRD_LAPB
939 { ARPHRD_LAPB, N_("LAPB"), NULL },
940 #endif
941 #ifdef ARPHRD_DDCMP
942 { ARPHRD_DDCMP, NULL, NULL },
943 #endif
944 #ifdef ARPHRD_RAWHDLC
945 { ARPHRD_RAWHDLC, NULL, NULL },
946 #endif
947 #ifdef ARPHRD_TUNNEL
948 { ARPHRD_TUNNEL, N_("IPIP Tunnel"), NULL },
949 #endif
950 #ifdef ARPHRD_TUNNEL6
951 { ARPHRD_TUNNEL6, NULL, NULL },
952 #endif
953 #ifdef ARPHRD_FRAD
954 { ARPHRD_FRAD, N_("Frame Relay Access Device"), NULL },
955 #endif
956 #ifdef ARPHRD_SKIP
957 { ARPHRD_SKIP, NULL, NULL },
958 #endif
959 #ifdef ARPHRD_LOOPBACK
960 { ARPHRD_LOOPBACK, N_("Local Loopback"), print_mac_addr },
961 #endif
962 #ifdef ARPHRD_LOCALTLK
963 { ARPHRD_LOCALTLK, NULL, NULL },
964 #endif
965 #ifdef ARPHRD_FDDI
966 { ARPHRD_FDDI, N_("Fiber Distributed Data Interface"), print_mac_addr },
967 #endif
968 #ifdef ARPHRD_BIF
969 { ARPHRD_BIF, NULL, NULL },
970 #endif
971 #ifdef ARPHRD_SIT
972 { ARPHRD_SIT, N_("IPv6-in-IPv4"), NULL },
973 #endif
974 #ifdef ARPHRD_IPDDP
975 { ARPHRD_IPDDP, NULL, NULL },
976 #endif
977 #ifdef ARPHRD_IPGRE
978 { ARPHRD_IPGRE, NULL, NULL },
979 #endif
980 #ifdef ARPHRD_PIMREG
981 { ARPHRD_PIMREG, NULL, NULL },
982 #endif
983 #ifdef ARPHRD_HIPPI
984 { ARPHRD_HIPPI, N_("HIPPI"), print_mac_addr },
985 #endif
986 #ifdef ARPHRD_ASH
987 { ARPHRD_ASH, N_("Ash"), print_ash_addr },
988 #endif
989 #ifdef ARPHRD_ECONET
990 { ARPHRD_ECONET, N_("Econet"), print_econet_addr },
991 #endif
992 #ifdef ARPHRD_IRDA
993 { ARPHRD_IRDA, N_("IrLAP"), print_irda_addr },
994 #endif
995 #ifdef ARPHRD_FCPP
996 { ARPHRD_FCPP, NULL, NULL },
997 #endif
998 #ifdef ARPHRD_FCAL
999 { ARPHRD_FCAL, NULL, NULL },
1000 #endif
1001 #ifdef ARPHRD_FCPL
1002 { ARPHRD_FCPL, NULL, NULL },
1003 #endif
1004 #ifdef ARPHRD_FCPFABRIC
1005 { ARPHRD_FCPFABRIC, NULL, NULL },
1006 #endif
1007 #ifdef ARPHRD_IEEE802_TR
1008 { ARPHRD_IEEE802_TR, N_("16/4 Mbps Token Ring"), print_mac_addr },
1009 #endif
1010 #ifdef ARPHRD_IEEE80211
1011 { ARPHRD_IEEE80211, NULL, NULL },
1012 #endif
1013 };
1014
1015 static struct HwType *
1016 netstatus_iface_get_hw_details (NetstatusIface *iface,
1017 char **hw_addr)
1018
1019 {
1020 #ifdef SIOCGIFHWADDR
1021 static struct HwType *hw_type = NULL;
1022 struct ifreq if_req;
1023 int fd;
1024 unsigned int i;
1025
1026 if (hw_addr)
1027 *hw_addr = NULL;
1028
1029 if (!iface->priv->name)
1030 return NULL;
1031
1032 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
1033 {
1034 g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n",
1035 g_strerror (errno));
1036 return NULL;
1037 }
1038
1039 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
1040 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
1041 if (ioctl (fd, SIOCGIFHWADDR, &if_req) < 0)
1042 {
1043 g_warning (G_STRLOC ": unable to obtain hardware address: %s\n",
1044 g_strerror (errno));
1045 close (fd);
1046 return NULL;
1047 }
1048
1049 close (fd);
1050
1051 if (hw_type && hw_type->hw_type != if_req.ifr_hwaddr.sa_family)
1052 hw_type = NULL;
1053
1054 for (i = 0; !hw_type && i < G_N_ELEMENTS (hw_types); i++)
1055 if (hw_types [i].hw_type == if_req.ifr_hwaddr.sa_family)
1056 hw_type = &hw_types [i];
1057
1058 if (!hw_type || !hw_type->hw_name)
1059 {
1060 g_warning (G_STRLOC ": no support for hardware type %d\n",
1061 if_req.ifr_hwaddr.sa_family);
1062 return NULL;
1063 }
1064
1065 if (hw_addr && if_req.ifr_hwaddr.sa_data && hw_type->print_hw_addr)
1066 *hw_addr = hw_type->print_hw_addr ((guchar *) if_req.ifr_hwaddr.sa_data);
1067
1068 return hw_type;
1069
1070 #else /* !defined(SIOCGIFHWADDR) */
1071 return NULL;
1072 #endif
1073 }
1074
1075 gboolean
1076 netstatus_iface_get_is_loopback (NetstatusIface *iface)
1077 {
1078 struct HwType *hw_type;
1079
1080 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
1081
1082 if (!(hw_type = netstatus_iface_get_hw_details (iface, NULL)))
1083 return FALSE;
1084
1085 #ifdef ARPHRD_LOOPBACK
1086 return hw_type->hw_type == ARPHRD_LOOPBACK ? TRUE : FALSE;
1087 #else
1088 return FALSE;
1089 #endif
1090 }
1091
1092 gboolean
1093 netstatus_iface_get_device_details (NetstatusIface *iface,
1094 const char **hw_name,
1095 char **hw_addr)
1096 {
1097 struct HwType *hw_type;
1098
1099 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
1100
1101 if (hw_name)
1102 *hw_name = NULL;
1103 if (hw_addr)
1104 *hw_addr = NULL;
1105
1106 if (!(hw_type = netstatus_iface_get_hw_details (iface, hw_addr)))
1107 return FALSE;
1108
1109 g_assert (hw_type->hw_name != NULL);
1110
1111 if (hw_name)
1112 *hw_name = _(hw_type->hw_name);
1113
1114 return TRUE;
1115 }
1116
1117 #if !defined(HAVE_SOCKADDR_SA_LEN)
1118 #define NETSTATUS_SA_LEN(saddr) (sizeof (struct sockaddr))
1119 #else
1120 #define NETSTATUS_SA_LEN(saddr) (MAX ((saddr)->sa_len, sizeof (struct sockaddr)))
1121 #endif /* HAVE_SOCKADDR_SA_LEN */
1122
1123 /* Taken From R. Stevens Unix Network Programming Vol. 1.
1124 *
1125 * SIOCGIFCONF does not return an error on all systems if
1126 * the buffer is not large enough for all available
1127 * interfaces. This loop portably ensures that we get the
1128 * information for all interfaces.
1129 */
1130 static struct ifconf *
1131 get_ifconf (int fd,
1132 GError **error)
1133 {
1134 struct ifconf if_conf;
1135 struct ifconf *retval;
1136 int len, lastlen;
1137
1138 lastlen = 0;
1139 len = 10 * sizeof (struct ifreq);
1140
1141 while (TRUE)
1142 {
1143 if_conf.ifc_len = len;
1144 if_conf.ifc_buf = g_malloc0 (len);
1145
1146 if (ioctl (fd, SIOCGIFCONF, &if_conf) < 0)
1147 {
1148 if (errno != EINVAL || lastlen != 0)
1149 {
1150 g_free (if_conf.ifc_buf);
1151
1152 if (error)
1153 *error = g_error_new (NETSTATUS_ERROR,
1154 NETSTATUS_ERROR_IOCTL_IFCONF,
1155 _("SIOCGIFCONF error: %s"),
1156 g_strerror (errno));
1157
1158 return NULL;
1159 }
1160 }
1161 else
1162 {
1163 if (if_conf.ifc_len == lastlen)
1164 break;
1165 lastlen = if_conf.ifc_len;
1166 }
1167
1168 g_free (if_conf.ifc_buf);
1169 if_conf.ifc_buf = NULL;
1170
1171 len *= 2;
1172 }
1173
1174 retval = g_new0 (struct ifconf, 1);
1175
1176 retval->ifc_len = if_conf.ifc_len;
1177 retval->ifc_buf = if_conf.ifc_buf;
1178
1179 return retval;
1180 }
1181
1182 GList *
1183 netstatus_list_interface_names (GError **error)
1184 {
1185
1186 struct ifconf *if_conf;
1187 GList *interfaces;
1188 GList *loopbacks;
1189 char *p;
1190 int fd;
1191
1192 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
1193 {
1194 if (error)
1195 *error = g_error_new (NETSTATUS_ERROR,
1196 NETSTATUS_ERROR_SOCKET,
1197 _("Unable to open socket: %s"),
1198 g_strerror (errno));
1199 return NULL;
1200 }
1201
1202 if ((if_conf = get_ifconf (fd, error)) == NULL)
1203 {
1204 close (fd);
1205 return NULL;
1206 }
1207
1208 interfaces = NULL;
1209 loopbacks = NULL;
1210
1211 for (p = if_conf->ifc_buf; p < if_conf->ifc_buf + if_conf->ifc_len;)
1212 {
1213 struct ifreq *if_req = (struct ifreq *) p;
1214 gboolean loopback = FALSE;
1215
1216 p += sizeof (if_req->ifr_name) + NETSTATUS_SA_LEN (&if_req->ifr_addr);
1217
1218 if (ioctl (fd, SIOCGIFFLAGS, if_req) < 0)
1219 {
1220 if (error)
1221 *error = g_error_new (NETSTATUS_ERROR,
1222 NETSTATUS_ERROR_IOCTL_IFFLAGS,
1223 _("SIOCGIFFLAGS error: %s"),
1224 g_strerror (errno));
1225 }
1226 else
1227 {
1228 loopback = (if_req->ifr_flags & IFF_LOOPBACK);
1229 }
1230
1231 if (!loopback)
1232 interfaces = netstatus_list_insert_unique (interfaces,
1233 g_strdup (if_req->ifr_name));
1234 else
1235 loopbacks = netstatus_list_insert_unique (loopbacks,
1236 g_strdup (if_req->ifr_name));
1237 }
1238
1239 interfaces = g_list_concat (interfaces, loopbacks);
1240
1241 g_free (if_conf->ifc_buf);
1242 g_free (if_conf);
1243 close (fd);
1244
1245 if (!interfaces && error)
1246 *error = g_error_new (NETSTATUS_ERROR,
1247 NETSTATUS_ERROR_NO_INTERFACES,
1248 _("No network devices found"));
1249
1250 return interfaces;
1251 }