/**************************************************************************** * net/procfs/netdev_statistics.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "inet/inet.h" #include "netdev/netdev.h" #include "utils/utils.h" #include "procfs/procfs.h" #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) && \ !defined(CONFIG_FS_PROCFS_EXCLUDE_NET) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #ifdef CONFIG_NET_IPv4 # define NETSTAT_IPv6_IDX 2 #else # define NETSTAT_IPv6_IDX 1 #endif /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile); #ifdef CONFIG_NET_IPv4 static int netprocfs_inet4addresses(FAR struct netprocfs_file_s *netfile); #endif #ifdef CONFIG_NET_IPv6 static int netprocfs_inet6address(FAR struct netprocfs_file_s *netfile); static int netprocfs_inet6draddress(FAR struct netprocfs_file_s *netfile); #endif #if !defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_IPv6) static int netprocfs_blank_line(FAR struct netprocfs_file_s *netfile); #endif #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_rxstatistics_header( FAR struct netprocfs_file_s *netfile); static int netprocfs_rxstatistics(FAR struct netprocfs_file_s *netfile); static int netprocfs_rxpackets_header(FAR struct netprocfs_file_s *netfile); static int netprocfs_rxpackets(FAR struct netprocfs_file_s *netfile); static int netprocfs_txstatistics_header( FAR struct netprocfs_file_s *netfile); static int netprocfs_txstatistics(FAR struct netprocfs_file_s *netfile); static int netprocfs_errors(FAR struct netprocfs_file_s *netfile); #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Private Data ****************************************************************************/ /* Line generating functions */ static const linegen_t g_netstat_linegen[] = { netprocfs_linklayer #ifdef CONFIG_NET_IPv4 , netprocfs_inet4addresses #endif #ifdef CONFIG_NET_IPv6 # if defined(CONFIG_NETDEV_MULTIPLE_IPv6) && \ defined(CONFIG_DESIGNATED_INITIALIZERS) , [NETSTAT_IPv6_IDX ... NETSTAT_IPv6_IDX + CONFIG_NETDEV_MAX_IPv6_ADDR - 1] = netprocfs_inet6address # else , netprocfs_inet6address # endif , netprocfs_inet6draddress #endif #if !defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_IPv6) , netprocfs_blank_line #endif #ifdef CONFIG_NETDEV_STATISTICS , netprocfs_rxstatistics_header, netprocfs_rxstatistics, netprocfs_rxpackets_header, netprocfs_rxpackets, netprocfs_txstatistics_header, netprocfs_txstatistics, netprocfs_errors #endif /* CONFIG_NETDEV_STATISTICS */ }; #define NSTAT_LINES (sizeof(g_netstat_linegen) / sizeof(linegen_t)) /**************************************************************************** * Private Functions ****************************************************************************/ #if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) static int netprocfs_radio_linklayer(FAR struct netprocfs_file_s *netfile, int len) { FAR struct netdev_varaddr_s *addr; FAR struct net_driver_s *dev; #if RADIO_MAX_ADDRLEN > 1 int i; #endif DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; addr = &dev->d_mac.radio; #ifdef CONFIG_NET_6LOWPAN len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:6LoWPAN HWaddr ", dev->d_ifname); #else len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:Raw HWaddr ", dev->d_ifname); #endif if (addr->nv_addrlen < 1 || addr->nv_addrlen > RADIO_MAX_ADDRLEN) { nwarn("WARNING: Bad or undefined node address: %u\n", addr->nv_addrlen); len += snprintf(&netfile->line[len], NET_LINELEN - len, "--"); } else { len += snprintf(&netfile->line[len], NET_LINELEN - len, "%02x", addr->nv_addr[0]); #if RADIO_MAX_ADDRLEN > 1 /* Avoids a warning */ for (i = 1; i < addr->nv_addrlen; i++) { len += snprintf(&netfile->line[len], NET_LINELEN - len, ":%02x", addr->nv_addr[i]); } #endif } return len; } #endif /**************************************************************************** * Name: netprocfs_linklayer ****************************************************************************/ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile) { FAR struct net_driver_s *dev; FAR const char *status; int len = 0; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; /* Get the interface status: RUNNING, UP, or DOWN */ if ((dev->d_flags & IFF_RUNNING) != 0) { status = "RUNNING"; } else if ((dev->d_flags & IFF_UP) != 0) { status = "UP"; } else { status = "DOWN"; } /* Select the output appropriate for the link type associated with * this device. */ switch (dev->d_lltype) { #if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_DRIVERS_IEEE80211) case NET_LL_ETHERNET: case NET_LL_IEEE80211: { char hwaddr[20]; len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:Ethernet HWaddr %s", dev->d_ifname, ether_ntoa_r(&dev->d_mac.ether, hwaddr)); } break; #endif #if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) case NET_LL_IEEE802154: case NET_LL_PKTRADIO: { len += netprocfs_radio_linklayer(netfile, len); } break; #endif /* CONFIG_NET_6LOWPAN || CONFIG_NET_IEEE802154 */ #ifdef CONFIG_NET_LOOPBACK case NET_LL_LOOPBACK: len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:Local Loopback", dev->d_ifname); break; #endif #ifdef CONFIG_NET_SLIP case NET_LL_SLIP: len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:SLIP", dev->d_ifname); break; #endif #ifdef CONFIG_NET_PPP case NET_LL_PPP: len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:P-t-P", dev->d_ifname); break; #endif #ifdef CONFIG_NET_TUN case NET_LL_TUN: len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:TUN", dev->d_ifname); break; #endif default: len += snprintf(&netfile->line[len], NET_LINELEN - len, "%s\tLink encap:UNSPEC", dev->d_ifname); } len += snprintf(&netfile->line[len], NET_LINELEN - len, " at %s", status); len += snprintf(&netfile->line[len], NET_LINELEN - len, " mtu %d\n", (dev->d_pktsize - dev->d_llhdrlen)); return len; } /**************************************************************************** * Name: netprocfs_inet4addresses ****************************************************************************/ #ifdef CONFIG_NET_IPv4 static int netprocfs_inet4addresses(FAR struct netprocfs_file_s *netfile) { FAR struct net_driver_s *dev; struct in_addr addr; int len = 0; char inetaddr[INET_ADDRSTRLEN]; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; /* Show the IPv4 address */ addr.s_addr = dev->d_ipaddr; len += snprintf(&netfile->line[len], NET_LINELEN - len, "\tinet addr:%s ", inet_ntoa_r(addr, inetaddr, sizeof(inetaddr))); #ifdef CONFIG_NET_ARP_ACD if (dev->d_acd.conflict_flag == ARP_ACD_ADDRESS_CONFLICT) { len += snprintf(&netfile->line[len], NET_LINELEN - len, "(conflict!) "); } #endif /* Show the IPv4 default router address */ addr.s_addr = dev->d_draddr; len += snprintf(&netfile->line[len], NET_LINELEN - len, "DRaddr:%s ", inet_ntoa_r(addr, inetaddr, sizeof(inetaddr))); /* Show the IPv4 network mask */ addr.s_addr = dev->d_netmask; len += snprintf(&netfile->line[len], NET_LINELEN - len, #ifdef CONFIG_NET_IPv6 "Mask:%s\n", /* IPv6 addresses will follow */ #else "Mask:%s\n\n", /* Double space at end of device description */ #endif inet_ntoa_r(addr, inetaddr, sizeof(inetaddr))); return len; } #endif /**************************************************************************** * Name: netprocfs_inet6address ****************************************************************************/ #ifdef CONFIG_NET_IPv6 static int netprocfs_inet6address(FAR struct netprocfs_file_s *netfile) { FAR struct net_driver_s *dev; char addrstr[INET6_ADDRSTRLEN]; uint8_t preflen; int idx = netfile->lineno - NETSTAT_IPv6_IDX; int len = 0; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; #ifdef CONFIG_NETDEV_MULTIPLE_IPv6 if (net_ipv6addr_cmp(dev->d_ipv6[idx].addr, g_ipv6_unspecaddr)) { return 0; } #endif /* Convert the 128 network mask to a human friendly prefix length */ preflen = net_ipv6_mask2pref(dev->d_ipv6[idx].mask); /* Show the assigned IPv6 address */ if (inet_ntop(AF_INET6, dev->d_ipv6[idx].addr, addrstr, INET6_ADDRSTRLEN)) { len += snprintf(&netfile->line[len], NET_LINELEN - len, "\tinet6 addr: %s/%d\n", addrstr, preflen); } return len; } #endif /**************************************************************************** * Name: netprocfs_inet6draddress ****************************************************************************/ #ifdef CONFIG_NET_IPv6 static int netprocfs_inet6draddress(FAR struct netprocfs_file_s *netfile) { FAR struct net_driver_s *dev; char addrstr[INET6_ADDRSTRLEN]; int len = 0; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; /* Show the IPv6 default router address */ if (inet_ntop(AF_INET6, dev->d_ipv6draddr, addrstr, INET6_ADDRSTRLEN)) { len += snprintf(&netfile->line[len], NET_LINELEN - len, "\tinet6 DRaddr: %s\n\n", addrstr); } return len; } #endif /**************************************************************************** * Name: netprocfs_blank_line ****************************************************************************/ #if !defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_IPv6) static int netprocfs_blank_line(FAR struct netprocfs_file_s *netfile) { netfile->line[0] = '\n'; netfile->line[1] = '\0'; return 1; } #endif /**************************************************************************** * Name: netprocfs_rxstatistics_header ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_rxstatistics_header( FAR struct netprocfs_file_s *netfile) { DEBUGASSERT(netfile != NULL); return snprintf(netfile->line, NET_LINELEN , "\tRX: %-8s %-8s %-8s %-8s\n", "Received", "Fragment", "Errors", "Bytes"); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Name: netprocfs_rxstatistics ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_rxstatistics(FAR struct netprocfs_file_s *netfile) { FAR struct netdev_statistics_s *stats; FAR struct net_driver_s *dev; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; stats = &dev->d_statistics; return snprintf(netfile->line, NET_LINELEN, \ "\t %08lx %08lx %08lx %-16llx\n", (unsigned long)stats->rx_packets, (unsigned long)stats->rx_fragments, (unsigned long)stats->rx_errors, (unsigned long long)stats->rx_bytes); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Name: netprocfs_rxpackets_header ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_rxpackets_header(FAR struct netprocfs_file_s *netfile) { FAR char *fmt; DEBUGASSERT(netfile != NULL); fmt = "\t " #ifdef CONFIG_NET_IPv4 "%-8s " #endif #ifdef CONFIG_NET_IPv6 "%-8s " #endif #ifdef CONFIG_NET_ARP "%-8s " #endif "%-8s\n"; return snprintf(netfile->line, NET_LINELEN, fmt #ifdef CONFIG_NET_IPv4 , "IPv4" #endif #ifdef CONFIG_NET_IPv6 , "IPv6" #endif #ifdef CONFIG_NET_ARP , "ARP" #endif , "Dropped"); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Name: netprocfs_rxpackets ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_rxpackets(FAR struct netprocfs_file_s *netfile) { FAR struct netdev_statistics_s *stats; FAR struct net_driver_s *dev; FAR char *fmt; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; stats = &dev->d_statistics; fmt = "\t " #ifdef CONFIG_NET_IPv4 "%08lx " #endif #ifdef CONFIG_NET_IPv6 "%08lx " #endif #ifdef CONFIG_NET_ARP "%08lx " #endif "%08lx\n"; return snprintf(netfile->line, NET_LINELEN, fmt #ifdef CONFIG_NET_IPv4 , (unsigned long)stats->rx_ipv4 #endif #ifdef CONFIG_NET_IPv6 , (unsigned long)stats->rx_ipv6 #endif #ifdef CONFIG_NET_ARP , (unsigned long)stats->rx_arp #endif , (unsigned long)stats->rx_dropped); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Name: netprocfs_txstatistics_header ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_txstatistics_header( FAR struct netprocfs_file_s *netfile) { DEBUGASSERT(netfile != NULL); return snprintf(netfile->line, NET_LINELEN, "\tTX: %-8s %-8s %-8s %-8s %-8s\n", "Queued", "Sent", "Errors", "Timeouts", "Bytes"); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Name: netprocfs_txstatistics ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_txstatistics(FAR struct netprocfs_file_s *netfile) { FAR struct netdev_statistics_s *stats; FAR struct net_driver_s *dev; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; stats = &dev->d_statistics; return snprintf(netfile->line, NET_LINELEN, "\t %08lx %08lx %08lx %08lx %-16llx \n", (unsigned long)stats->tx_packets, (unsigned long)stats->tx_done, (unsigned long)stats->tx_errors, (unsigned long)stats->tx_timeouts, (unsigned long long)stats->tx_bytes); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Name: netprocfs_errors ****************************************************************************/ #ifdef CONFIG_NETDEV_STATISTICS static int netprocfs_errors(FAR struct netprocfs_file_s *netfile) { FAR struct netdev_statistics_s *stats; FAR struct net_driver_s *dev; DEBUGASSERT(netfile != NULL && netfile->dev != NULL); dev = netfile->dev; stats = &dev->d_statistics; return snprintf(netfile->line, NET_LINELEN, "\tTotal Errors: %08" PRIx32 "\n\n", stats->errors); } #endif /* CONFIG_NETDEV_STATISTICS */ /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: netprocfs_read_devstats * * Description: * Read and format network device statistics. * * Input Parameters: * priv - A reference to the network procfs file structure * buffer - The user-provided buffer into which device status will be * returned. * bulen - The size in bytes of the user provided buffer. * * Returned Value: * Zero (OK) is returned on success; a negated errno value is returned * on failure. * ****************************************************************************/ ssize_t netprocfs_read_devstats(FAR struct netprocfs_file_s *priv, FAR char *buffer, size_t buflen) { return netprocfs_read_linegen(priv, buffer, buflen, g_netstat_linegen, NSTAT_LINES); } #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS && * !CONFIG_FS_PROCFS_EXCLUDE_NET */