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
netstatus_iface_get_type(void)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
netstatus_iface_instance_init(NetstatusIface * iface,NetstatusIfaceClass * klass)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
netstatus_iface_class_init(NetstatusIfaceClass * klass)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
netstatus_iface_finalize(GObject * object)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
netstatus_iface_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)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
netstatus_iface_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)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 *
netstatus_iface_new(const char * name)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
netstatus_iface_set_name(NetstatusIface * iface,const char * name)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 const char *
netstatus_iface_get_name(NetstatusIface * iface)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
netstatus_iface_get_state(NetstatusIface * iface)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
netstatus_iface_get_statistics(NetstatusIface * iface,NetstatusStats * stats)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
netstatus_iface_get_is_wireless(NetstatusIface * iface)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
netstatus_iface_get_signal_strength(NetstatusIface * iface)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
netstatus_iface_set_error(NetstatusIface * iface,const GError * error)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 const GError *
netstatus_iface_get_error(NetstatusIface * iface)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
netstatus_iface_clear_error(NetstatusIface * iface,NetstatusError code)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
netstatus_iface_set_polling_error(NetstatusIface * iface,NetstatusError code,const char * format,...)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 #if !GLIB_CHECK_VERSION(2, 22, 0)
407 char *error_message;
408 #endif
409
410 va_start (args, format);
411
412 #if GLIB_CHECK_VERSION(2, 22, 0)
413 error = g_error_new_valist (NETSTATUS_ERROR, code, format, args);
414 #else
415 error_message = g_strdup_vprintf (format, args);
416 error = g_error_new (NETSTATUS_ERROR, code, "%s", error_message);
417 g_free (error_message);
418 #endif
419
420 dprintf (POLLING, "ERROR: %s\n", error->message);
421 netstatus_iface_set_error (iface, error);
422
423 g_error_free (error);
424
425 va_end (args);
426 }
427
428 static int
netstatus_iface_get_sockfd(NetstatusIface * iface)429 netstatus_iface_get_sockfd (NetstatusIface *iface)
430 {
431 int fd;
432
433 if (iface->priv->sockfd)
434 return iface->priv->sockfd;
435
436 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
437 {
438 netstatus_iface_set_polling_error (iface,
439 NETSTATUS_ERROR_SOCKET,
440 _("Unable to open socket: %s"),
441 g_strerror (errno));
442 return 0;
443 }
444
445 dprintf (POLLING, "Successfully opened socket for polling\n");
446 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_SOCKET);
447
448 iface->priv->sockfd = fd;
449
450 return iface->priv->sockfd;
451 }
452
453 static gboolean
netstatus_iface_poll_iface_statistics(NetstatusIface * iface,gulong * in_packets,gulong * out_packets,gulong * in_bytes,gulong * out_bytes)454 netstatus_iface_poll_iface_statistics (NetstatusIface *iface,
455 gulong *in_packets,
456 gulong *out_packets,
457 gulong *in_bytes,
458 gulong *out_bytes)
459 {
460 char *error_message;
461
462 error_message = netstatus_sysdeps_read_iface_statistics (iface->priv->name,
463 in_packets,
464 out_packets,
465 in_bytes,
466 out_bytes);
467 if (error_message)
468 {
469 netstatus_iface_set_polling_error (iface,
470 NETSTATUS_ERROR_STATISTICS,
471 error_message);
472 g_free (error_message);
473
474 return FALSE;
475 }
476
477 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_STATISTICS);
478
479 return TRUE;
480 }
481
482 static NetstatusState
netstatus_iface_poll_state(NetstatusIface * iface)483 netstatus_iface_poll_state (NetstatusIface *iface)
484 {
485 NetstatusState state;
486 struct ifreq if_req;
487 gboolean tx, rx;
488 int fd;
489 gulong in_packets, out_packets;
490 gulong in_bytes, out_bytes;
491
492 if (!(fd = netstatus_iface_get_sockfd (iface)))
493 return NETSTATUS_STATE_DISCONNECTED;
494
495 memset (&if_req, 0, sizeof (struct ifreq));
496 strcpy (if_req.ifr_name, iface->priv->name);
497
498 if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0)
499 {
500 netstatus_iface_set_polling_error (iface,
501 NETSTATUS_ERROR_IOCTL_IFFLAGS,
502 _("SIOCGIFFLAGS error: %s"),
503 g_strerror (errno));
504 return NETSTATUS_STATE_DISCONNECTED;
505 }
506
507 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_IOCTL_IFFLAGS);
508
509 dprintf (POLLING, "Interface is %sup and %srunning\n",
510 if_req.ifr_flags & IFF_UP ? "" : "not ",
511 if_req.ifr_flags & IFF_RUNNING ? "" : "not ");
512
513 if (!(if_req.ifr_flags & IFF_UP) || !(if_req.ifr_flags & IFF_RUNNING))
514 return NETSTATUS_STATE_DISCONNECTED;
515
516 if (!netstatus_iface_poll_iface_statistics (iface, &in_packets, &out_packets, &in_bytes, &out_bytes))
517 return NETSTATUS_STATE_IDLE;
518
519 dprintf (POLLING, "Packets in: %ld out: %ld. Prev in: %ld out: %ld\n",
520 in_packets, out_packets,
521 iface->priv->stats.in_packets, iface->priv->stats.out_packets);
522 dprintf (POLLING, "Bytes in: %ld out: %ld. Prev in: %ld out: %ld\n",
523 in_bytes, out_bytes,
524 iface->priv->stats.in_bytes, iface->priv->stats.out_bytes);
525
526 rx = in_packets > iface->priv->stats.in_packets;
527 tx = out_packets > iface->priv->stats.out_packets;
528
529 if (!tx && !rx)
530 state = NETSTATUS_STATE_IDLE;
531 else if (tx && rx)
532 state = NETSTATUS_STATE_TX_RX;
533 else if (tx)
534 state = NETSTATUS_STATE_TX;
535 else /* if (rx) */
536 state = NETSTATUS_STATE_RX;
537
538 dprintf (POLLING, "State: %s\n", netstatus_get_state_string (state));
539
540 if (tx || rx)
541 {
542 iface->priv->stats.in_packets = in_packets;
543 iface->priv->stats.out_packets = out_packets;
544 iface->priv->stats.in_bytes = in_bytes;
545 iface->priv->stats.out_bytes = out_bytes;
546
547 g_object_notify (G_OBJECT (iface), "stats");
548 }
549
550 return state;
551 }
552
553 static gboolean
netstatus_iface_poll_wireless_details(NetstatusIface * iface,int * signal_strength)554 netstatus_iface_poll_wireless_details (NetstatusIface *iface,
555 int *signal_strength)
556 {
557 char *error_message;
558 gboolean is_wireless;
559
560 error_message = netstatus_sysdeps_read_iface_wireless_details (iface->priv->name,
561 &is_wireless,
562 signal_strength);
563
564 if (error_message)
565 {
566 netstatus_iface_set_polling_error (iface,
567 NETSTATUS_ERROR_WIRELESS_DETAILS,
568 error_message);
569 g_free (error_message);
570
571 return FALSE;
572 }
573
574 netstatus_iface_clear_error (iface, NETSTATUS_ERROR_WIRELESS_DETAILS);
575
576 return is_wireless;
577 }
578
579 static void
netstatus_iface_increase_poll_delay_in_error(NetstatusIface * iface)580 netstatus_iface_increase_poll_delay_in_error (NetstatusIface *iface)
581 {
582 static int polls_in_error = 0;
583
584 if (iface->priv->state == NETSTATUS_STATE_ERROR)
585 {
586 dprintf (POLLING, "Interface in error state\n");
587
588 if (!iface->priv->error_polling &&
589 ++polls_in_error >= NETSTATUS_IFACE_POLLS_IN_ERROR)
590 {
591 dprintf (POLLING, "Increasing polling delay after too many errors\n");
592 iface->priv->error_polling = TRUE;
593 g_source_remove (iface->priv->monitor_id);
594 iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_ERROR_POLL_DELAY,
595 (GSourceFunc) netstatus_iface_monitor_timeout,
596 iface);
597 }
598 }
599 else if (iface->priv->error_polling)
600 {
601 dprintf (POLLING, "Recovered from errors. Increasing polling delay again\n");
602
603 iface->priv->error_polling = FALSE;
604 polls_in_error = 0;
605
606 g_source_remove (iface->priv->monitor_id);
607 iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_POLL_DELAY,
608 (GSourceFunc) netstatus_iface_monitor_timeout,
609 iface);
610 }
611 }
612
613 static gboolean
netstatus_iface_monitor_timeout(NetstatusIface * iface)614 netstatus_iface_monitor_timeout (NetstatusIface *iface)
615 {
616 NetstatusState state;
617 int signal_strength;
618 gboolean is_wireless;
619
620 if (g_source_is_destroyed(g_main_current_source()))
621 return FALSE;
622
623 state = netstatus_iface_poll_state (iface);
624
625 if (iface->priv->state != state &&
626 iface->priv->state != NETSTATUS_STATE_ERROR)
627 {
628 iface->priv->state = state;
629 g_object_notify (G_OBJECT (iface), "state");
630 }
631
632 is_wireless = netstatus_iface_poll_wireless_details (iface, &signal_strength);
633 if (iface->priv->is_wireless != is_wireless)
634 {
635 iface->priv->is_wireless = is_wireless;
636 g_object_notify (G_OBJECT (iface), "wireless");
637 }
638
639 if (iface->priv->signal_strength != signal_strength)
640 {
641 iface->priv->signal_strength = signal_strength;
642 g_object_notify (G_OBJECT (iface), "signal-strength");
643 }
644
645 netstatus_iface_increase_poll_delay_in_error (iface);
646
647 return TRUE;
648 }
649
650 static void
netstatus_iface_init_monitor(NetstatusIface * iface)651 netstatus_iface_init_monitor (NetstatusIface *iface)
652 {
653 iface->priv->stats.in_packets = 0;
654 iface->priv->stats.out_packets = 0;
655 iface->priv->stats.in_bytes = 0;
656 iface->priv->stats.out_bytes = 0;
657 iface->priv->signal_strength = 0;
658 iface->priv->is_wireless = FALSE;
659
660 g_object_freeze_notify (G_OBJECT (iface));
661 g_object_notify (G_OBJECT (iface), "state");
662 g_object_notify (G_OBJECT (iface), "wireless");
663 g_object_notify (G_OBJECT (iface), "signal-strength");
664 g_object_thaw_notify (G_OBJECT (iface));
665
666 if (iface->priv->monitor_id)
667 {
668 dprintf (POLLING, "Removing existing monitor\n");
669 g_source_remove (iface->priv->monitor_id);
670 iface->priv->monitor_id = 0;
671 }
672
673 if (iface->priv->name)
674 {
675 dprintf (POLLING, "Initialising monitor with delay of %d\n", NETSTATUS_IFACE_POLL_DELAY);
676 iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_POLL_DELAY,
677 (GSourceFunc) netstatus_iface_monitor_timeout,
678 iface);
679
680 /* netstatus_iface_monitor_timeout (iface); */
681 }
682 }
683
684 gboolean
netstatus_iface_get_inet4_details(NetstatusIface * iface,char ** addr,char ** dest,char ** bcast,char ** mask)685 netstatus_iface_get_inet4_details (NetstatusIface *iface,
686 char **addr,
687 char **dest,
688 char **bcast,
689 char **mask)
690 {
691 struct ifreq if_req;
692 int fd;
693 int flags;
694
695 if (addr)
696 *addr = NULL;
697 if (dest)
698 *dest = NULL;
699 if (mask)
700 *mask = NULL;
701
702 if (!iface->priv->name)
703 return FALSE;
704
705 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
706 {
707 g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n",
708 g_strerror (errno));
709 return FALSE;
710 }
711
712 if_req.ifr_addr.sa_family = AF_INET;
713
714 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
715 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
716 if (addr && ioctl (fd, SIOCGIFADDR, &if_req) == 0)
717 *addr = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr));
718
719 if (addr && !*addr)
720 {
721 close (fd);
722 return FALSE;
723 }
724
725 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
726 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
727 if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0)
728 {
729 close (fd);
730 return TRUE;
731 }
732
733 flags = if_req.ifr_flags;
734
735 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
736 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
737 if (dest && flags & IFF_POINTOPOINT &&
738 ioctl (fd, SIOCGIFDSTADDR, &if_req) == 0)
739 *dest = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_dstaddr)->sin_addr));
740
741 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
742 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
743 if (bcast && flags & IFF_BROADCAST &&
744 ioctl (fd, SIOCGIFBRDADDR, &if_req) == 0)
745 *bcast = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_broadaddr)->sin_addr));
746
747 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
748 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
749 if (mask && ioctl (fd, SIOCGIFNETMASK, &if_req) == 0)
750 *mask = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr));
751
752 close (fd);
753
754 return TRUE;
755 }
756
757 static char *
print_mac_addr(guchar * p)758 print_mac_addr (guchar *p)
759 {
760 return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
761 p [0] & 0377,
762 p [1] & 0377,
763 p [2] & 0377,
764 p [3] & 0377,
765 p [4] & 0377,
766 p [5] & 0377);
767 }
768
769 static char *
print_ash_addr(guchar * p)770 print_ash_addr (guchar *p)
771 {
772 #define ASH_ALEN 64
773
774 GString *str;
775 char *retval;
776 int i = 0;
777
778 str = g_string_new ("[");
779
780 while (p [i] != 0xc9 && p [i] != 0xff && (i < ASH_ALEN))
781 g_string_append_printf (str, "%1x", p [i++]);
782
783 g_string_append_c (str, ']');
784
785 retval = str->str;
786 g_string_free (str, FALSE);
787
788 return retval;
789
790 #undef ASH_ALEN
791 }
792
793 static char *
print_ax25_addr(guchar * p)794 print_ax25_addr (guchar *p)
795 {
796 GString *str;
797 char *retval;
798 int i;
799
800 str = g_string_new (NULL);
801
802 for (i = 0; i < 6; i++)
803 {
804 char c = (p [i] & 0377) >> 1;
805
806 if (c == ' ')
807 {
808 retval = str->str;
809 g_string_free (str, FALSE);
810
811 return retval;
812 }
813
814 g_string_append_c (str, c);
815 }
816
817 i = (p [6] & 0x1E) >> 1;
818 if (i != 0)
819 g_string_append_printf (str, "-%d", i);
820
821 retval = str->str;
822 g_string_free (str, FALSE);
823
824 return retval;
825 }
826
827 static char *
print_rose_addr(guchar * p)828 print_rose_addr (guchar *p)
829 {
830 return g_strdup_printf ("%02x%02x%02x%02x%02x", p [0], p [1], p [2], p [3], p [4]);
831 }
832
833 static char *
print_x25_addr(guchar * p)834 print_x25_addr (guchar *p)
835 {
836 return g_strdup ((const gchar *) p);
837 }
838
839 static char *
print_arcnet_addr(guchar * p)840 print_arcnet_addr (guchar *p)
841 {
842 return g_strdup_printf ("%02X", p [0] & 0377);
843 }
844
845 static char *
print_dlci_addr(guchar * p)846 print_dlci_addr (guchar *p)
847 {
848 return g_strdup_printf ("%i", *(short *) p);
849 }
850
851 static char *
print_irda_addr(guchar * p)852 print_irda_addr (guchar *p)
853 {
854 return g_strdup_printf ("%02x:%02x:%02x:%02x", p [3], p [2], p [1], p [0]);
855 }
856
857 static char *
print_econet_addr(guchar * p)858 print_econet_addr (guchar *p)
859 {
860 /* This should really be:
861 * #include <neteconet/ec.h>
862 *
863 * struct ec_addr *ec = (struct ec_addr *) p;
864 * return g_strdup_printf ("%d.%d, ec->net, ec->station);
865 *
866 * But I think the hack is safe enough.
867 */
868 return g_strdup_printf ("%d.%d", p [0], p [1]);
869 }
870
871 static struct HwType
872 {
873 int hw_type;
874 char *hw_name;
875 char *(*print_hw_addr) (guchar *p);
876 } hw_types [] =
877 {
878 #ifdef ARPHRD_NETROM
879 { ARPHRD_NETROM, N_("AMPR NET/ROM"), print_ax25_addr },
880 #endif
881 #ifdef ARPHRD_ETHER
882 { ARPHRD_ETHER, N_("Ethernet"), print_mac_addr },
883 #endif
884 #ifdef ARPHRD_EETHER
885 { ARPHRD_EETHER, NULL, NULL },
886 #endif
887 #ifdef ARPHRD_AX25
888 { ARPHRD_AX25, N_("AMPR AX.25"), NULL },
889 #endif
890 #ifdef ARPHRD_PRONET
891 { ARPHRD_PRONET, NULL, NULL },
892 #endif
893 #ifdef ARPHRD_CHAOS
894 { ARPHRD_CHAOS, NULL, NULL },
895 #endif
896 #ifdef ARPHRD_IEEE802
897 { ARPHRD_IEEE802, N_("16/4 Mbps Token Ring"), print_mac_addr },
898 #endif
899 #ifdef ARPHRD_ARCNET
900 { ARPHRD_ARCNET, N_("ARCnet"), print_arcnet_addr },
901 #endif
902 #ifdef ARPHRD_APPLETLK
903 { ARPHRD_APPLETLK, NULL, NULL },
904 #endif
905 #ifdef ARPHRD_DLCI
906 { ARPHRD_DLCI, N_("Frame Relay DLCI"), print_dlci_addr },
907 #endif
908 #ifdef ARPHRD_ATM
909 { ARPHRD_ATM, NULL, NULL },
910 #endif
911 #ifdef ARPHRD_METRICOM
912 { ARPHRD_METRICOM, N_("Metricom Starmode IP"), NULL },
913 #endif
914 #ifdef ARPHRD_SLIP
915 { ARPHRD_SLIP, N_("Serial Line IP"), NULL },
916 #endif
917 #ifdef ARPHRD_CSLIP
918 { ARPHRD_CSLIP, N_("VJ Serial Line IP"), NULL },
919 #endif
920 #ifdef ARPHRD_SLIP6
921 { ARPHRD_SLIP6, N_("6-bit Serial Line IP"), NULL },
922 #endif
923 #ifdef ARPHRD_CSLIP6
924 { ARPHRD_CSLIP6, N_("VJ 6-bit Serial Line IP"), NULL },
925 #endif
926 #ifdef ARPHRD_RSRVD
927 { ARPHRD_RSRVD, NULL, NULL },
928 #endif
929 #ifdef ARPHRD_ADAPT
930 { ARPHRD_ADAPT, N_("Adaptive Serial Line IP"), NULL },
931 #endif
932 #ifdef ARPHRD_ROSE
933 { ARPHRD_ROSE, N_("AMPR ROSE"), print_rose_addr },
934 #endif
935 #ifdef ARPHRD_X25
936 { ARPHRD_X25, N_("Generic X.25"), print_x25_addr },
937 #endif
938 #ifdef ARPHRD_PPP
939 { ARPHRD_PPP, N_("Point-to-Point Protocol"), NULL },
940 #endif
941 #ifdef ARPHRD_CISCO
942 { ARPHRD_CISCO, NULL, NULL },
943 #endif
944 #ifdef ARPHRD_HDLC
945 { ARPHRD_HDLC, N_("(Cisco)-HDLC"), NULL },
946 #endif
947 #ifdef ARPHRD_LAPB
948 { ARPHRD_LAPB, N_("LAPB"), NULL },
949 #endif
950 #ifdef ARPHRD_DDCMP
951 { ARPHRD_DDCMP, NULL, NULL },
952 #endif
953 #ifdef ARPHRD_RAWHDLC
954 { ARPHRD_RAWHDLC, NULL, NULL },
955 #endif
956 #ifdef ARPHRD_TUNNEL
957 { ARPHRD_TUNNEL, N_("IPIP Tunnel"), NULL },
958 #endif
959 #ifdef ARPHRD_TUNNEL6
960 { ARPHRD_TUNNEL6, NULL, NULL },
961 #endif
962 #ifdef ARPHRD_FRAD
963 { ARPHRD_FRAD, N_("Frame Relay Access Device"), NULL },
964 #endif
965 #ifdef ARPHRD_SKIP
966 { ARPHRD_SKIP, NULL, NULL },
967 #endif
968 #ifdef ARPHRD_LOOPBACK
969 { ARPHRD_LOOPBACK, N_("Local Loopback"), print_mac_addr },
970 #endif
971 #ifdef ARPHRD_LOCALTLK
972 { ARPHRD_LOCALTLK, NULL, NULL },
973 #endif
974 #ifdef ARPHRD_FDDI
975 { ARPHRD_FDDI, N_("Fiber Distributed Data Interface"), print_mac_addr },
976 #endif
977 #ifdef ARPHRD_BIF
978 { ARPHRD_BIF, NULL, NULL },
979 #endif
980 #ifdef ARPHRD_SIT
981 { ARPHRD_SIT, N_("IPv6-in-IPv4"), NULL },
982 #endif
983 #ifdef ARPHRD_IPDDP
984 { ARPHRD_IPDDP, NULL, NULL },
985 #endif
986 #ifdef ARPHRD_IPGRE
987 { ARPHRD_IPGRE, NULL, NULL },
988 #endif
989 #ifdef ARPHRD_PIMREG
990 { ARPHRD_PIMREG, NULL, NULL },
991 #endif
992 #ifdef ARPHRD_HIPPI
993 { ARPHRD_HIPPI, N_("HIPPI"), print_mac_addr },
994 #endif
995 #ifdef ARPHRD_ASH
996 { ARPHRD_ASH, N_("Ash"), print_ash_addr },
997 #endif
998 #ifdef ARPHRD_ECONET
999 { ARPHRD_ECONET, N_("Econet"), print_econet_addr },
1000 #endif
1001 #ifdef ARPHRD_IRDA
1002 { ARPHRD_IRDA, N_("IrLAP"), print_irda_addr },
1003 #endif
1004 #ifdef ARPHRD_FCPP
1005 { ARPHRD_FCPP, NULL, NULL },
1006 #endif
1007 #ifdef ARPHRD_FCAL
1008 { ARPHRD_FCAL, NULL, NULL },
1009 #endif
1010 #ifdef ARPHRD_FCPL
1011 { ARPHRD_FCPL, NULL, NULL },
1012 #endif
1013 #ifdef ARPHRD_FCPFABRIC
1014 { ARPHRD_FCPFABRIC, NULL, NULL },
1015 #endif
1016 #ifdef ARPHRD_IEEE802_TR
1017 { ARPHRD_IEEE802_TR, N_("16/4 Mbps Token Ring"), print_mac_addr },
1018 #endif
1019 #ifdef ARPHRD_IEEE80211
1020 { ARPHRD_IEEE80211, NULL, NULL },
1021 #endif
1022 };
1023
1024 static struct HwType *
netstatus_iface_get_hw_details(NetstatusIface * iface,char ** hw_addr)1025 netstatus_iface_get_hw_details (NetstatusIface *iface,
1026 char **hw_addr)
1027 {
1028 #ifdef SIOCGIFHWADDR
1029 static struct HwType *hw_type = NULL;
1030 struct ifreq if_req;
1031 int fd;
1032 unsigned int i;
1033
1034 if (hw_addr)
1035 *hw_addr = NULL;
1036
1037 if (!iface->priv->name)
1038 return NULL;
1039
1040 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
1041 {
1042 g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n",
1043 g_strerror (errno));
1044 return NULL;
1045 }
1046
1047 strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
1048 if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
1049 if (ioctl (fd, SIOCGIFHWADDR, &if_req) < 0)
1050 {
1051 g_warning (G_STRLOC ": unable to obtain hardware address: %s\n",
1052 g_strerror (errno));
1053 close (fd);
1054 return NULL;
1055 }
1056
1057 close (fd);
1058
1059 if (hw_type && hw_type->hw_type != if_req.ifr_hwaddr.sa_family)
1060 hw_type = NULL;
1061
1062 for (i = 0; !hw_type && i < G_N_ELEMENTS (hw_types); i++)
1063 if (hw_types [i].hw_type == if_req.ifr_hwaddr.sa_family)
1064 hw_type = &hw_types [i];
1065
1066 if (!hw_type || !hw_type->hw_name)
1067 {
1068 g_warning (G_STRLOC ": no support for hardware type %d\n",
1069 if_req.ifr_hwaddr.sa_family);
1070 return NULL;
1071 }
1072
1073 if (hw_addr && if_req.ifr_hwaddr.sa_data && hw_type->print_hw_addr)
1074 *hw_addr = hw_type->print_hw_addr ((guchar *) if_req.ifr_hwaddr.sa_data);
1075
1076 return hw_type;
1077
1078 #else /* !defined(SIOCGIFHWADDR) */
1079 return NULL;
1080 #endif
1081 }
1082
1083 gboolean
netstatus_iface_get_is_loopback(NetstatusIface * iface)1084 netstatus_iface_get_is_loopback (NetstatusIface *iface)
1085 {
1086 struct HwType *hw_type;
1087
1088 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
1089
1090 if (!(hw_type = netstatus_iface_get_hw_details (iface, NULL)))
1091 return FALSE;
1092
1093 #ifdef ARPHRD_LOOPBACK
1094 return hw_type->hw_type == ARPHRD_LOOPBACK ? TRUE : FALSE;
1095 #else
1096 return FALSE;
1097 #endif
1098 }
1099
1100 gboolean
netstatus_iface_get_device_details(NetstatusIface * iface,const char ** hw_name,char ** hw_addr)1101 netstatus_iface_get_device_details (NetstatusIface *iface,
1102 const char **hw_name,
1103 char **hw_addr)
1104 {
1105 struct HwType *hw_type;
1106
1107 g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
1108
1109 if (hw_name)
1110 *hw_name = NULL;
1111 if (hw_addr)
1112 *hw_addr = NULL;
1113
1114 if (!(hw_type = netstatus_iface_get_hw_details (iface, hw_addr)))
1115 return FALSE;
1116
1117 g_assert (hw_type->hw_name != NULL);
1118
1119 if (hw_name)
1120 *hw_name = _(hw_type->hw_name);
1121
1122 return TRUE;
1123 }
1124
1125 #if !defined(HAVE_SOCKADDR_SA_LEN)
1126 #define NETSTATUS_SA_LEN(saddr) (sizeof (struct sockaddr))
1127 #else
1128 #define NETSTATUS_SA_LEN(saddr) (MAX ((saddr)->sa_len, sizeof (struct sockaddr)))
1129 #endif /* HAVE_SOCKADDR_SA_LEN */
1130
1131 /* Taken From R. Stevens Unix Network Programming Vol. 1.
1132 *
1133 * SIOCGIFCONF does not return an error on all systems if
1134 * the buffer is not large enough for all available
1135 * interfaces. This loop portably ensures that we get the
1136 * information for all interfaces.
1137 */
1138 static struct ifconf *
get_ifconf(int fd,GError ** error)1139 get_ifconf (int fd,
1140 GError **error)
1141 {
1142 struct ifconf if_conf;
1143 struct ifconf *retval;
1144 int len, lastlen;
1145
1146 lastlen = 0;
1147 len = 10 * sizeof (struct ifreq);
1148
1149 while (TRUE)
1150 {
1151 if_conf.ifc_len = len;
1152 if_conf.ifc_buf = g_malloc0 (len);
1153
1154 if (ioctl (fd, SIOCGIFCONF, &if_conf) < 0)
1155 {
1156 if (errno != EINVAL || lastlen != 0)
1157 {
1158 g_free (if_conf.ifc_buf);
1159
1160 if (error)
1161 *error = g_error_new (NETSTATUS_ERROR,
1162 NETSTATUS_ERROR_IOCTL_IFCONF,
1163 _("SIOCGIFCONF error: %s"),
1164 g_strerror (errno));
1165
1166 return NULL;
1167 }
1168 }
1169 else
1170 {
1171 if (if_conf.ifc_len == lastlen)
1172 break;
1173 lastlen = if_conf.ifc_len;
1174 }
1175
1176 g_free (if_conf.ifc_buf);
1177 if_conf.ifc_buf = NULL;
1178
1179 len *= 2;
1180 }
1181
1182 retval = g_new0 (struct ifconf, 1);
1183
1184 retval->ifc_len = if_conf.ifc_len;
1185 retval->ifc_buf = if_conf.ifc_buf;
1186
1187 return retval;
1188 }
1189
1190 GList *
netstatus_list_interface_names(GError ** error)1191 netstatus_list_interface_names (GError **error)
1192 {
1193
1194 struct ifconf *if_conf;
1195 GList *interfaces;
1196 GList *loopbacks;
1197 char *p;
1198 int fd;
1199
1200 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
1201 {
1202 if (error)
1203 *error = g_error_new (NETSTATUS_ERROR,
1204 NETSTATUS_ERROR_SOCKET,
1205 _("Unable to open socket: %s"),
1206 g_strerror (errno));
1207 return NULL;
1208 }
1209
1210 if ((if_conf = get_ifconf (fd, error)) == NULL)
1211 {
1212 close (fd);
1213 return NULL;
1214 }
1215
1216 interfaces = NULL;
1217 loopbacks = NULL;
1218
1219 for (p = if_conf->ifc_buf; p < if_conf->ifc_buf + if_conf->ifc_len;)
1220 {
1221 struct ifreq *if_req = (struct ifreq *) p;
1222 gboolean loopback = FALSE;
1223
1224 p += sizeof (if_req->ifr_name) + NETSTATUS_SA_LEN (&if_req->ifr_addr);
1225
1226 if (ioctl (fd, SIOCGIFFLAGS, if_req) < 0)
1227 {
1228 if (error)
1229 *error = g_error_new (NETSTATUS_ERROR,
1230 NETSTATUS_ERROR_IOCTL_IFFLAGS,
1231 _("SIOCGIFFLAGS error: %s"),
1232 g_strerror (errno));
1233 }
1234 else
1235 {
1236 loopback = (if_req->ifr_flags & IFF_LOOPBACK);
1237 }
1238
1239 if (!loopback)
1240 interfaces = netstatus_list_insert_unique (interfaces,
1241 g_strdup (if_req->ifr_name));
1242 else
1243 loopbacks = netstatus_list_insert_unique (loopbacks,
1244 g_strdup (if_req->ifr_name));
1245 }
1246
1247 interfaces = g_list_concat (interfaces, loopbacks);
1248
1249 g_free (if_conf->ifc_buf);
1250 g_free (if_conf);
1251 close (fd);
1252
1253 if (!interfaces && error)
1254 *error = g_error_new (NETSTATUS_ERROR,
1255 NETSTATUS_ERROR_NO_INTERFACES,
1256 _("No network devices found"));
1257
1258 return interfaces;
1259 }
1260