diff options
Diffstat (limited to 'netspeed/src/backend.c')
-rw-r--r-- | netspeed/src/backend.c | 380 |
1 files changed, 259 insertions, 121 deletions
diff --git a/netspeed/src/backend.c b/netspeed/src/backend.c index afbdea2e..e1321497 100644 --- a/netspeed/src/backend.c +++ b/netspeed/src/backend.c @@ -27,6 +27,12 @@ #include <sys/sockio.h> #endif +#include <sys/socket.h> +#include <sys/types.h> +#include <ifaddrs.h> +#include <netinet/in.h> +#include <arpa/inet.h> + #include <glib.h> #include <glib/gi18n.h> #include <glibtop/netlist.h> @@ -59,91 +65,217 @@ struct nl80211_state { #endif /* HAVE_NL */ gboolean -is_dummy_device(const char* device) +is_dummy_device (const char* device) { - glibtop_netload netload; - glibtop_get_netload(&netload, device); - - if (netload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK)) - return TRUE; - - /* Skip interfaces without any IPv4/IPv6 address (or - those with only a LINK ipv6 addr) However we need to - be able to exclude these while still keeping the - value so when they get online (with NetworkManager - for example) we don't get a suddent peak. Once we're - able to get this, ignoring down interfaces will be - possible too. */ - if (!(netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS6) - && netload.scope6 != GLIBTOP_IF_IN6_SCOPE_LINK) - && !(netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS))) - return TRUE; - - return FALSE; -} + glibtop_netload netload; + glibtop_get_netload (&netload, device); + if (netload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK)) + return TRUE; + + /* Skip interfaces without any IPv4/IPv6 address (or + those with only a LINK ipv6 addr) However we need to + be able to exclude these while still keeping the + value so when they get online (with NetworkManager + for example) we don't get a suddent peak. Once we're + able to get this, ignoring down interfaces will be + possible too. */ + if (!(netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS6) + && netload.scope6 != GLIBTOP_IF_IN6_SCOPE_LINK) + && !(netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS))) + return TRUE; + + return FALSE; +} /* Check for all available devices. This really should be * portable for at least all plattforms using the gnu c lib * TODO: drop it, use glibtop_get_netlist directly / gchar** */ GList* -get_available_devices(void) +get_available_devices (void) { - glibtop_netlist buf; - char **devices, **dev; - GList *device_glist = NULL; + glibtop_netlist buf; + char **devices, **dev; + GList *device_glist = NULL; + + devices = glibtop_get_netlist (&buf); - devices = glibtop_get_netlist(&buf); + for (dev = devices; *dev; ++dev) { + device_glist = g_list_prepend (device_glist, g_strdup (*dev)); + } + device_glist = g_list_sort (device_glist, (GCompareFunc) g_strcmp0); - for(dev = devices; *dev; ++dev) { - device_glist = g_list_prepend(device_glist, g_strdup(*dev)); - } + g_strfreev (devices); - g_strfreev(devices); + return device_glist; +} - return device_glist; +GSList* +get_ip_address_list (const char *iface_name, + gboolean ipv4) +{ + GSList *list = NULL; + struct ifaddrs *ifaces; + + if (getifaddrs (&ifaces) != -1) { + int family; + char ip[INET6_ADDRSTRLEN]; + + family = ipv4 ? AF_INET : AF_INET6; + for (struct ifaddrs *iface = ifaces; iface != NULL; iface = iface->ifa_next) { + if (iface->ifa_addr == NULL) + continue; + + if ((iface->ifa_addr->sa_family == family) && + !g_strcmp0 (iface->ifa_name, iface_name)) + { + unsigned int netmask = 0; + void *sinx_addr = NULL; + + if (iface->ifa_addr->sa_family == AF_INET6) { + struct sockaddr_in6 ip6_addr; + struct sockaddr_in6 ip6_network; + uint32_t ip6_netmask = 0; + const char *scope; + int i; + + memcpy (&ip6_addr, iface->ifa_addr, sizeof (struct sockaddr_in6)); + memcpy (&ip6_network, iface->ifa_netmask, sizeof (struct sockaddr_in6)); + + /* get network scope */ + if (IN6_IS_ADDR_LINKLOCAL (&ip6_addr.sin6_addr)) { + scope = _("link-local"); + } else if (IN6_IS_ADDR_SITELOCAL (&ip6_addr.sin6_addr)) { + scope = _("site-local"); + } else if (IN6_IS_ADDR_V4MAPPED (&ip6_addr.sin6_addr)) { + scope = _("v4mapped"); + } else if (IN6_IS_ADDR_V4COMPAT (&ip6_addr.sin6_addr)) { + scope = _("v4compat"); + } else if (IN6_IS_ADDR_LOOPBACK (&ip6_addr.sin6_addr)) { + scope = _("host"); + } else if (IN6_IS_ADDR_UNSPECIFIED (&ip6_addr.sin6_addr)) { + scope = _("unspecified"); + } else { + scope = _("global"); + } + + /* get network ip */ + sinx_addr = &ip6_addr.sin6_addr; + inet_ntop (iface->ifa_addr->sa_family, sinx_addr, ip, sizeof (ip)); + + /* get network mask length */ + for (i = 0; i < 4; i++) { + ip6_netmask = ntohl (((uint32_t*)(&ip6_network.sin6_addr))[i]); + while (ip6_netmask) { + netmask++; + ip6_netmask <<= 1; + } + } + + list = g_slist_prepend (list, + g_strdup_printf ("%s/%u (%s)", + ip, netmask, scope)); + } else { + struct sockaddr_in ip4_addr; + struct sockaddr_in ip4_network; + in_addr_t ip4_netmask = 0; + + memcpy (&ip4_addr, iface->ifa_addr, sizeof (struct sockaddr_in)); + memcpy (&ip4_network, iface->ifa_netmask, sizeof (struct sockaddr_in)); + + /* get network ip */ + sinx_addr = &ip4_addr.sin_addr; + inet_ntop (iface->ifa_addr->sa_family, sinx_addr, ip, sizeof (ip)); + + /* get network mask length */ + ip4_netmask = ntohl (ip4_network.sin_addr.s_addr); + while (ip4_netmask) { + netmask++; + ip4_netmask <<= 1; + } + + list = g_slist_prepend (list, + g_strdup_printf ("%s/%u", ip, netmask)); + } + } + } + if (list != NULL) + list = g_slist_sort (list, (GCompareFunc) g_strcmp0); + freeifaddrs (ifaces); + } + return list; } -const gchar* -get_default_route(void) +GSList* +get_ip6_address_list (const char *iface_name) { - FILE *fp; - static char device[50]; + GSList *list = NULL; + struct ifaddrs *ifaces; - fp = fopen("/proc/net/route", "r"); + if (getifaddrs (&ifaces) != -1) { + char ip6[INET6_ADDRSTRLEN]; - if (fp == NULL) return NULL; + for (struct ifaddrs *iface = ifaces; iface != NULL; iface = iface->ifa_next) { + if ((iface->ifa_addr == NULL) || (iface->ifa_addr->sa_family != AF_INET6)) + continue; - while (!feof(fp)) { - char buffer[1024]; - unsigned int ip, gw, flags, ref, use, metric, mask, mtu, window, irtt; - int retval; - char *rv; + if (!g_strcmp0 (iface->ifa_name, iface_name)) { + void *sinx_addr = NULL; - rv = fgets(buffer, 1024, fp); - if (!rv) { - break; - } + struct sockaddr_in6 ip6_addr; - retval = sscanf(buffer, "%49s %x %x %x %u %u %u %x %u %u %u", - device, &ip, &gw, &flags, &ref, &use, &metric, &mask, &mtu, &window, &irtt); + memcpy (&ip6_addr, iface->ifa_addr, sizeof (struct sockaddr_in6)); - if (retval != 11) continue; + /* get network ip */ + sinx_addr = &ip6_addr.sin6_addr; + inet_ntop (iface->ifa_addr->sa_family, sinx_addr, ip6, sizeof (ip6)); - if (ip == 0 && !is_dummy_device(device)) { - fclose(fp); - return device; - } - } - fclose(fp); - return NULL; + list = g_slist_prepend (list, g_strdup (ip6)); + } + } + + if (list != NULL) + list = g_slist_sort (list, (GCompareFunc) g_strcmp0); + freeifaddrs (ifaces); + } + return list; } -void -free_devices_list(GList *list) +const gchar* +get_default_route (void) { - g_list_free_full (list, g_free); + FILE *fp; + static char device[50]; + + fp = fopen ("/proc/net/route", "r"); + + if (fp == NULL) return NULL; + + while (!feof (fp)) { + char buffer[1024]; + unsigned int ip, gw, flags, ref, use, metric, mask, mtu, window, irtt; + int retval; + char *rv; + + rv = fgets (buffer, 1024, fp); + if (!rv) { + break; + } + + retval = sscanf (buffer, "%49s %x %x %x %u %u %u %x %u %u %u", + device, &ip, &gw, &flags, &ref, &use, &metric, + &mask, &mtu, &window, &irtt); + + if (retval != 11) continue; + + if (ip == 0 && !is_dummy_device (device)) { + fclose (fp); + return device; + } + } + fclose (fp); + return NULL; } /* Frees a DevInfo struct and all the stuff it contains @@ -175,13 +307,13 @@ get_ptp_info (DevInfo *devinfo) if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) return; - if (ioctl(fd, SIOCGIFDSTADDR, &request) >= 0) { + if (ioctl (fd, SIOCGIFDSTADDR, &request) >= 0) { struct sockaddr_in* addr; addr = (struct sockaddr_in*)&request.ifr_dstaddr; devinfo->ptpip = addr->sin_addr.s_addr; } - close(fd); + close (fd); } void @@ -192,7 +324,7 @@ get_device_info (const char *device, glibtop_netload netload; gboolean ptp = FALSE; - g_assert(device); + g_assert (device); *info = g_new0 (DevInfo, 1); devinfo = *info; @@ -211,11 +343,11 @@ get_device_info (const char *device, else if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_WIRELESS)) { devinfo->type = DEV_WIRELESS; } - else if(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_POINTOPOINT)) { - if (g_str_has_prefix(device, "plip")) { + else if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_POINTOPOINT)) { + if (g_str_has_prefix (device, "plip")) { devinfo->type = DEV_PLIP; } - else if (g_str_has_prefix(device, "sl")) { + else if (g_str_has_prefix (device, "sl")) { devinfo->type = DEV_SLIP; } else { @@ -247,7 +379,6 @@ get_device_info (const char *device, if (devinfo->running) { devinfo->ip = netload.address; devinfo->netmask = netload.subnet; - memcpy (devinfo->ipv6, netload.address6, 16); #if defined (HAVE_NL) if (devinfo->type != DEV_WIRELESS) { devinfo->tx = netload.bytes_out; @@ -261,70 +392,74 @@ get_device_info (const char *device, if (ptp) get_ptp_info (devinfo); #endif /* HAVE_NL */ - } + } } gboolean compare_device_info (const DevInfo *a, const DevInfo *b) { - g_assert(a && b); - g_assert(a->name && b->name); - - if (!g_str_equal(a->name, b->name)) return TRUE; - if (a->ip != b->ip) return TRUE; - /* Ignore hwaddr, ptpip and netmask... I think this is ok */ - if (a->up != b->up) return TRUE; - if (a->running != b->running) return TRUE; - - return FALSE; + g_assert (a && b); + g_assert (a->name && b->name); + + if (!g_str_equal (a->name, b->name)) + return TRUE; + if (a->ip != b->ip) + return TRUE; + /* Ignore hwaddr, ptpip and netmask... I think this is ok */ + if (a->up != b->up) + return TRUE; + if (a->running != b->running) + return TRUE; + + return FALSE; } #ifdef HAVE_IW void get_wireless_info (DevInfo *devinfo) { - int fd; - int newqual; - wireless_info info = {0}; + int fd; + int newqual; + wireless_info info = {0}; - fd = iw_sockets_open (); + fd = iw_sockets_open (); - if (fd < 0) - return; + if (fd < 0) + return; - if (iw_get_basic_config (fd, devinfo->name, &info.b) < 0) - goto out; + if (iw_get_basic_config (fd, devinfo->name, &info.b) < 0) + goto out; - if (info.b.has_essid) { - if ((!devinfo->essid) || (strcmp (devinfo->essid, info.b.essid) != 0)) { - devinfo->essid = g_strdup (info.b.essid); - } - } else { - devinfo->essid = NULL; - } + if (info.b.has_essid) { + if ((!devinfo->essid) || (strcmp (devinfo->essid, info.b.essid) != 0)) { + devinfo->essid = g_strdup (info.b.essid); + } + } else { + devinfo->essid = NULL; + } - if (iw_get_stats (fd, devinfo->name, &info.stats, &info.range, info.has_range) >= 0) - info.has_stats = 1; + if (iw_get_stats (fd, devinfo->name, &info.stats, &info.range, info.has_range) >= 0) + info.has_stats = 1; - if (info.has_stats) { - if ((iw_get_range_info(fd, devinfo->name, &info.range) >= 0) && (info.range.max_qual.qual > 0)) { - newqual = 0.5f + (100.0f * info.stats.qual.qual) / (1.0f * info.range.max_qual.qual); - } else { - newqual = info.stats.qual.qual; - } + if (info.has_stats) { + if ((iw_get_range_info (fd, devinfo->name, &info.range) >= 0) && (info.range.max_qual.qual > 0)) { + newqual = 0.5f + (100.0f * info.stats.qual.qual) / (1.0f * info.range.max_qual.qual); + } else { + newqual = info.stats.qual.qual; + } - newqual = CLAMP(newqual, 0, 100); - if (devinfo->qual != newqual) - devinfo->qual = newqual; + newqual = CLAMP (newqual, 0, 100); + if (devinfo->qual != newqual) + devinfo->qual = newqual; - } else { - devinfo->qual = 0; - } + } else { + devinfo->qual = 0; + } - goto out; + goto out; out: - if (fd != -1) - close (fd); + if (fd != -1) + close (fd); } #endif /* HAVE_IW */ @@ -369,7 +504,6 @@ out_handle_destroy: return err; } - static void nl80211_cleanup (struct nl80211_state *state) { @@ -408,10 +542,14 @@ scan_cb (struct nl_msg *msg, g_warning ("failed to parse nested attributes!"); return NL_SKIP; } - if (!bss[NL80211_BSS_BSSID]) return NL_SKIP; - if (!bss[NL80211_BSS_STATUS]) return NL_SKIP; + if (!bss[NL80211_BSS_BSSID]) + return NL_SKIP; + if (!bss[NL80211_BSS_STATUS]) + return NL_SKIP; + + if (nla_get_u32 (bss[NL80211_BSS_STATUS]) != NL80211_BSS_STATUS_ASSOCIATED) + return NL_SKIP; - if (nla_get_u32 (bss[NL80211_BSS_STATUS]) != NL80211_BSS_STATUS_ASSOCIATED) return NL_SKIP; memcpy (devinfo->station_mac_addr, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN); return NL_SKIP; @@ -472,10 +610,10 @@ parse_bitrate (struct nlattr *bitrate_attr, pos += snprintf (pos, buflen - (pos - buf), _(" HE-MCS %d"), nla_get_u8 (rinfo[NL80211_RATE_INFO_HE_MCS])); if (rinfo[NL80211_RATE_INFO_HE_NSS]) - pos += snprintf(pos, buflen - (pos - buf), + pos += snprintf (pos, buflen - (pos - buf), _(" HE-NSS %d"), nla_get_u8 (rinfo[NL80211_RATE_INFO_HE_NSS])); if (rinfo[NL80211_RATE_INFO_HE_GI]) - pos += snprintf(pos, buflen - (pos - buf), + pos += snprintf (pos, buflen - (pos - buf), _(" HE-GI %d"), nla_get_u8 (rinfo[NL80211_RATE_INFO_HE_GI])); if (rinfo[NL80211_RATE_INFO_HE_DCM]) snprintf (pos, buflen - (pos - buf), @@ -512,8 +650,8 @@ station_cb (struct nl_msg *msg, return NL_SKIP; } if (nla_parse_nested (sinfo, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], - stats_policy)) { + tb[NL80211_ATTR_STA_INFO], + stats_policy)) { g_warning ("failed to parse nested attributes!\n"); return NL_SKIP; } @@ -610,7 +748,7 @@ iface_cb (struct nl_msg *msg, struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; nla_parse (tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); + genlmsg_attrlen (gnlh, 0), NULL); if (tb_msg[NL80211_ATTR_MAC]) { memcpy (devinfo->hwaddr, nla_data (tb_msg[NL80211_ATTR_MAC]), ETH_ALEN); @@ -677,7 +815,7 @@ get_wireless_info (DevInfo *devinfo) ret = nl_recvmsgs_default (nlstate.sock); nlmsg_free (msg); if (ret < 0) { - g_warning ("failed to recive netlink message"); + g_warning ("failed to receive netlink message"); } if (!devinfo->running) @@ -701,7 +839,7 @@ get_wireless_info (DevInfo *devinfo) ret = nl_recvmsgs_default (nlstate.sock); nlmsg_free (msg); if (ret < 0) { - g_warning ("failed to recive netlink message"); + g_warning ("failed to receive netlink message"); goto cleanup; } @@ -727,7 +865,7 @@ get_wireless_info (DevInfo *devinfo) ret = nl_recvmsgs_default (nlstate.sock); nlmsg_free (msg); if (ret < 0) { - g_warning ("failed to recive netlink message"); + g_warning ("failed to receive netlink message"); } cleanup: |