diff --git a/ChangeLog b/ChangeLog index 55e099bcad9..1fc07dc19bd 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11172,4 +11172,7 @@ definition in the common network device structure defined in netdev.h where they can be accessed by network applications. All Ethernet drivers that collect statistics have been adapted to use these common - statistics (2015-11-26). \ No newline at end of file + statistics (2015-11-26). + * net/net_procfs.c: Add basic support for networking entries in the + procfs (2015-11-27). + diff --git a/TODO b/TODO index ff34eeb102d..b9ccb47afd9 100644 --- a/TODO +++ b/TODO @@ -453,6 +453,9 @@ o Kernel/Protected Build http://git.busybox.net/busybox/tree/util-linux/mkfs_vfat.c + ps, ifup, ifdown, ifconfig should be implemented using + extensions to the procfs file system. + Status: Open Priority: Medium/High -- the kernel build configuration is not fully fielded yet. @@ -1553,6 +1556,7 @@ o Graphics subsystem (graphics/) Status: Open Priority: Low, not a serious issue but worth noting. There is no plan to change this behavior. + o Pascal Add-On (pcode/) ^^^^^^^^^^^^^^^^^^^^^^ @@ -1795,7 +1799,7 @@ o NuttShell (NSH) (apps/nshlib) show status for the single interface on the command line; it will still show status for all interfaces. Status: Open - Priority: Low (multiple network interfaces not fully supported yet anyway). + Priority: Low Title: ARP COMMAND Description: Add an ARP command so that we can see and modify the contents of diff --git a/arch b/arch index 26a3df81693..7a800cc36f9 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 26a3df81693aa11a487fda52ee001792ed4212a6 +Subproject commit 7a800cc36f9078f59f3f19c6eb400701952cfb7c diff --git a/configs b/configs index b52f98b9c91..18c27d65356 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit b52f98b9c91f8d84e7484e818e065b1e63b1d469 +Subproject commit 18c27d653564ec78841d6912597155fde62467c7 diff --git a/fs/procfs/Kconfig b/fs/procfs/Kconfig index 9b6b433b107..2b4fe81af2b 100644 --- a/fs/procfs/Kconfig +++ b/fs/procfs/Kconfig @@ -39,6 +39,11 @@ config FS_PROCFS_EXCLUDE_MOUNTS default n depends on !DISABLE_MOUNTPOINT +config FS_PROCFS_EXCLUDE_NET + bool "Exclude network" + depends on NET + default n + config FS_PROCFS_EXCLUDE_MTD bool "Exclude mtd" depends on MTD diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 5b6786b2e62..951f3caa5d5 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -79,10 +79,13 @@ extern const struct procfs_operations proc_operations; extern const struct procfs_operations cpuload_operations; extern const struct procfs_operations uptime_operations; -/* This is not good. These are implemented in drivers/mtd. Having to - * deal with them here is not a good coupling. +/* This is not good. These are implemented in other sub-systems. Having to + * deal with them here is not a good coupling. What is really needed is a + * run-time procfs registration system vs. a build time, fixed procfs + * configuration. */ +extern const struct procfs_operations net_procfsoperations; extern const struct procfs_operations mtd_procfsoperations; extern const struct procfs_operations part_procfsoperations; extern const struct procfs_operations smartfs_procfsoperations; @@ -117,6 +120,11 @@ static const struct procfs_entry_s g_procfsentries[] = { "fs/smartfs**", &smartfs_procfsoperations }, #endif +#if defined(CONFIG_NET) && !defined(CONFIG_FS_PROCFS_EXCLUDE_NET) + { "net", &net_procfsoperations }, + { "net/**", &net_procfsoperations }, +#endif + #if defined(CONFIG_MTD) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MTD) { "mtd", &mtd_procfsoperations }, #endif @@ -483,7 +491,7 @@ static int procfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, level0->base.nentries = 0; #endif - /* Initialze lastread entries */ + /* Initialize lastread entries */ level0->lastread = ""; level0->lastlen = 0; @@ -533,7 +541,7 @@ static int procfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, /* Doing an intermediate directory search */ - /* The path refers to the top level directory. Allocate the level0 + /* The path refers to the top level directory. Allocate the level1 * dirent structure. */ @@ -756,8 +764,8 @@ static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) */ if (strncmp(g_procfsentries[level1->base.index].pathpattern, - g_procfsentries[level1->firstindex].pathpattern, - level1->subdirlen) == 0) + g_procfsentries[level1->firstindex].pathpattern, + level1->subdirlen) == 0) { /* This entry matches. Report the subdir entry */ diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index 62284797df4..0d4f3b9945a 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -125,9 +125,9 @@ struct proc_file_s struct proc_dir_s { - struct procfs_dir_priv_s base; /* Base directory private data */ + struct procfs_dir_priv_s base; /* Base directory private data */ FAR const struct proc_node_s *node; /* Directory node description */ - pid_t pid; /* ID of task/thread for attributes */ + pid_t pid; /* ID of task/thread for attributes */ }; /**************************************************************************** diff --git a/fs/procfs/fs_skeleton.c b/fs/procfs/fs_skeleton.c index 99ba5b4f18d..11bc567fd80 100644 --- a/fs/procfs/fs_skeleton.c +++ b/fs/procfs/fs_skeleton.c @@ -110,7 +110,8 @@ static ssize_t skel_read(FAR struct file *filep, FAR char *buffer, static int skel_dup(FAR const struct file *oldp, FAR struct file *newp); -static int skel_opendir(const char *relpath, FAR struct fs_dirent_s *dir); +static int skel_opendir(FAR const char *relpath, + FAR struct fs_dirent_s *dir); static int skel_closedir(FAR struct fs_dirent_s *dir); static int skel_readdir(FAR struct fs_dirent_s *dir); static int skel_rewinddir(FAR struct fs_dirent_s *dir); @@ -118,7 +119,7 @@ static int skel_rewinddir(FAR struct fs_dirent_s *dir); static int skel_stat(FAR const char *relpath, FAR struct stat *buf); /**************************************************************************** - * Private Variables + * Private Data ****************************************************************************/ /**************************************************************************** @@ -158,7 +159,7 @@ const struct procfs_operations skel_procfsoperations = ****************************************************************************/ static int skel_open(FAR struct file *filep, FAR const char *relpath, - int oflags, mode_t mode) + int oflags, mode_t mode) { FAR struct skel_file_s *priv; @@ -220,7 +221,7 @@ static int skel_close(FAR struct file *filep) ****************************************************************************/ static ssize_t skel_read(FAR struct file *filep, FAR char *buffer, - size_t buflen) + size_t buflen) { FAR struct skel_file_s *priv; ssize_t ret; @@ -356,11 +357,12 @@ static int skel_closedir(FAR struct fs_dirent_s *dir) * ****************************************************************************/ -static int skel_readdir(struct fs_dirent_s *dir) +static int skel_readdir(FAR struct fs_dirent_s *dir) { FAR struct skel_level1_s *level1; char filename[16]; - int ret, index; + int index; + int ret; DEBUGASSERT(dir && dir->u.procfs); level1 = dir->u.procfs; @@ -396,12 +398,13 @@ static int skel_readdir(struct fs_dirent_s *dir) /* TODO: Specify the type of entry */ dir->fd_dir.d_type = DTYPE_FILE; - strncpy(dir->fd_dir.d_name, filename, NAME_MAX+1); + strncpy(dir->fd_dir.d_name, filename, NAME_MAX + 1); /* Set up the next directory entry offset. NOTE that we could use the * standard f_pos instead of our own private index. */ + level1->base.index = index + 1; ret = OK; } @@ -415,7 +418,7 @@ static int skel_readdir(struct fs_dirent_s *dir) * ****************************************************************************/ -static int skel_rewinddir(struct fs_dirent_s *dir) +static int skel_rewinddir(FAR struct fs_dirent_s *dir) { FAR struct skel_level1_s *priv; @@ -433,7 +436,7 @@ static int skel_rewinddir(struct fs_dirent_s *dir) * ****************************************************************************/ -static int skel_stat(const char *relpath, struct stat *buf) +static int skel_stat(FAR const char *relpath, FAR truct stat *buf) { int ret = -ENOENT; diff --git a/net/Makefile b/net/Makefile index 0b3aea0a29f..30551d9c442 100644 --- a/net/Makefile +++ b/net/Makefile @@ -42,6 +42,12 @@ ifeq ($(CONFIG_NET),y) NET_ASRCS = NET_CSRCS = net_initialize.c +ifeq ($(CONFIG_FS_PROCFS),y) +ifneq ($(CONFIG_FS_PROCFS_EXCLUDE_NET),y) +NET_CSRCS += net_procfs.c +endif +endif + # Socket support SOCK_ASRCS = diff --git a/net/net_procfs.c b/net/net_procfs.c new file mode 100644 index 00000000000..7b9ff3f48a6 --- /dev/null +++ b/net/net_procfs.c @@ -0,0 +1,912 @@ +/**************************************************************************** + * net/net_procfs.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic. + */ + +#define NET_LINELEN 64 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This enumeration identifies all of the thread attributes that can be + * accessed via the procfs file system. + */ + +/* This structure describes one open "file" */ + +struct netprocfs_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + uint8_t lineno; /* Line number */ + uint8_t linesize; /* Number of valid characters in line[] */ + uint8_t offset; /* Offset to first valid character in line[] */ + char line[NET_LINELEN]; /* Pre-allocated buffer for formatted lines */ +}; + +/* Level 1 is the directory of attributes */ + +struct netprocfs_level1_s +{ + struct procfs_dir_priv_s base; /* Base directory private data */ +}; + +/* Line generating function type */ + +typedef int (*linegen_t)(FAR struct netprocfs_file_s *netfile); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* Line generating functions */ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_header(FAR struct netprocfs_file_s *netfile); +static int netprocfs_received(FAR struct netprocfs_file_s *netfile); +static int netprocfs_dropped(FAR struct netprocfs_file_s *netfile); +#ifdef CONFIG_NET_IPv4 +static int netprocfs_ipv4_dropped(FAR struct netprocfs_file_s *netfile); +#endif /* CONFIG_NET_IPv4 */ +#ifdef CONFIG_NET_IPv6 +static int netprocfs_ipv6_dropped(FAR struct netprocfs_file_s *netfile); +#endif /* CONFIG_NET_IPv4 */ +static int netprocfs_checksum(FAR struct netprocfs_file_s *netfile); +#ifdef CONFIG_NET_TCP +static int netprocfs_tcp_dropped_1(FAR struct netprocfs_file_s *netfile); +static int netprocfs_tcp_dropped_2(FAR struct netprocfs_file_s *netfile); +#endif /* CONFIG_NET_TCP */ +static int netprocfs_prototype(FAR struct netprocfs_file_s *netfile); +static int netprocfs_sent(FAR struct netprocfs_file_s *netfile); +#ifdef CONFIG_NET_TCP +static int netprocfs_retransmissions(FAR struct netprocfs_file_s *netfile); +#endif /* CONFIG_NET_TCP */ +#endif /* CONFIG_NET_STATISTICS */ + +/* File system methods */ + +static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int netprocfs_close(FAR struct file *filep); +static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); + +static int netprocfs_dup(FAR const struct file *oldp, + FAR struct file *newp); + +static int netprocfs_opendir(FAR const char *relpath, + FAR struct fs_dirent_s *dir); +static int netprocfs_closedir(FAR struct fs_dirent_s *dir); +static int netprocfs_readdir(FAR struct fs_dirent_s *dir); +static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir); + +static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Line generating functions */ + +#ifdef CONFIG_NET_STATISTICS +static const linegen_t g_linegen[] = +{ + netprocfs_header, + netprocfs_received, + netprocfs_dropped, + +#ifdef CONFIG_NET_IPv4 + netprocfs_ipv4_dropped, +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 + netprocfs_ipv6_dropped, +#endif /* CONFIG_NET_IPv4 */ + + netprocfs_checksum, + +#ifdef CONFIG_NET_TCP + netprocfs_tcp_dropped_1, + netprocfs_tcp_dropped_2, +#endif /* CONFIG_NET_TCP */ + + netprocfs_prototype, + netprocfs_sent + +#ifdef CONFIG_NET_TCP + , netprocfs_retransmissions +#endif /* CONFIG_NET_TCP */ +}; + +#define NSTAT_LINES (sizeof(g_linegen) / sizeof(linegen_t)) +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* See include/nutts/fs/procfs.h + * We use the old-fashioned kind of initializers so that this will compile + * with any compiler. + */ + +const struct procfs_operations net_procfsoperations = +{ + netprocfs_open, /* open */ + netprocfs_close, /* close */ + netprocfs_read, /* read */ + NULL, /* write */ + netprocfs_dup, /* dup */ + + netprocfs_opendir, /* opendir */ + netprocfs_closedir, /* closedir */ + netprocfs_readdir, /* readdir */ + netprocfs_rewinddir, /* rewinddir */ + + netprocfs_stat /* stat */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netprocfs_header + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_header(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, " "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " IPv4"); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " IPv6"); +#endif +#ifdef CONFIG_NET_TCP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " TCP"); +#endif +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " UDP"); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ICMP"); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ICMPv6"); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Name: netprocfs_received + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_received(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "Received "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv4.recv); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv6.recv); +#endif +#ifdef CONFIG_NET_TCP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.tcp.recv); +#endif +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.udp.recv); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmp.recv); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmpv6.recv); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Name: netprocfs_dropped + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_dropped(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "Dropped "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv4.drop); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv6.drop); +#endif +#ifdef CONFIG_NET_TCP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.tcp.drop); +#endif +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.udp.drop); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmp.drop); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmpv6.drop); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Name: netprocfs_ipv4_dropped + ****************************************************************************/ + +#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_IPv4) +static int netprocfs_ipv4_dropped(FAR struct netprocfs_file_s *netfile) +{ + return snprintf(netfile->line, NET_LINELEN, + " IPv4 VHL: %04x Frg: %04x\n", + g_netstats.ipv4.vhlerr, g_netstats.ipv4.fragerr); +} +#endif /* CONFIG_NET_STATISTICS && CONFIG_NET_IPv4 */ + +/**************************************************************************** + * Name: netprocfs_ipv6_dropped + ****************************************************************************/ + +#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_IPv6) +static int netprocfs_ipv6_dropped(FAR struct netprocfs_file_s *netfile) +{ + return snprintf(netfile->line, NET_LINELEN, + " IPv6 VHL: %04x\n", + g_netstats.ipv6.vhlerr); +} +#endif /* CONFIG_NET_STATISTICS && CONFIG_NET_IPv6 */ + +/**************************************************************************** + * Name: netprocfs_checksum + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_checksum(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, " Checksum "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv4.chkerr); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_TCP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.tcp.chkerr); +#endif +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.udp.chkerr); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Name: netprocfs_tcp_dropped_1 + ****************************************************************************/ + +#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_TCP) +static int netprocfs_tcp_dropped_1(FAR struct netprocfs_file_s *netfile) +{ + return snprintf(netfile->line, NET_LINELEN, + " TCP ACK: %04x SYN: %04x\n", + g_netstats.tcp.ackerr, g_netstats.tcp.syndrop); +} +#endif /* CONFIG_NET_STATISTICS && CONFIG_NET_TCP */ + +/**************************************************************************** + * Name: netprocfs_tcp_dropped_2 + ****************************************************************************/ + +#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_TCP) +static int netprocfs_tcp_dropped_2(FAR struct netprocfs_file_s *netfile) +{ + return snprintf(netfile->line, NET_LINELEN, + " RST: %04x %04x\n", + g_netstats.tcp.rst, g_netstats.tcp.synrst); +} +#endif /* CONFIG_NET_STATISTICS && CONFIG_NET_TCP */ + +/**************************************************************************** + * Name: netprocfs_prototype + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_prototype(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, " Type "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv4.protoerr); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv6.protoerr); +#endif +#ifdef CONFIG_NET_TCP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmp.typeerr); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmpv6.typeerr); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Name: netprocfs_sent + ****************************************************************************/ + +#ifdef CONFIG_NET_STATISTICS +static int netprocfs_sent(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "Sent "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv4.sent); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.ipv6.sent); +#endif +#ifdef CONFIG_NET_TCP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.tcp.sent); +#endif +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.udp.sent); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmp.sent); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.icmpv6.sent); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS */ + +/**************************************************************************** + * Name: netprocfs_retransmissions + ****************************************************************************/ + +#if defined(CONFIG_NET_STATISTICS) && defined(CONFIG_NET_TCP) +static int netprocfs_retransmissions(FAR struct netprocfs_file_s *netfile) +{ + int len = 0; + + len += snprintf(&netfile->line[len], NET_LINELEN - len, " Rexmit "); +#ifdef CONFIG_NET_IPv4 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_IPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif + len += snprintf(&netfile->line[len], NET_LINELEN - len, " %04x", + g_netstats.tcp.rexmit); +#ifdef CONFIG_NET_UDP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_ICMP + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif +#ifdef CONFIG_NET_ICMPv6 + len += snprintf(&netfile->line[len], NET_LINELEN - len, " ----"); +#endif + + len += snprintf(&netfile->line[len], NET_LINELEN - len, "\n"); + return len; +} +#endif /* CONFIG_NET_STATISTICS && CONFIG_NET_TCP */ + +/**************************************************************************** + * Name: netprocfs_open + ****************************************************************************/ + +static int netprocfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct netprocfs_file_s *priv; + + fvdbg("Open '%s'\n", relpath); + + /* PROCFS is read-only. Any attempt to open with any kind of write + * access is not permitted. + * + * REVISIT: Write-able proc files could be quite useful. + */ + + if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) && + (net_procfsoperations.write == NULL)) + { + fdbg("ERROR: Only O_RDONLY supported\n"); + return -EACCES; + } + + /* "net/stat" is the only acceptable value for the relpath */ + + if (strcmp(relpath, "net/stat") != 0) + { + fdbg("ERROR: relpath is '%s'\n", relpath); + return -ENOENT; + } + + /* Allocate a container to hold the task and attribute selection */ + + priv = (FAR struct netprocfs_file_s *)kmm_zalloc(sizeof(struct netprocfs_file_s)); + if (!priv) + { + fdbg("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* Save the index as the open-specific state in filep->f_priv */ + + filep->f_priv = (FAR void *)priv; + return OK; +} + +/**************************************************************************** + * Name: netprocfs_close + ****************************************************************************/ + +static int netprocfs_close(FAR struct file *filep) +{ + FAR struct netprocfs_file_s *priv; + + /* Recover our private data from the struct file instance */ + + priv = (FAR struct netprocfs_file_s *)filep->f_priv; + DEBUGASSERT(priv); + + /* Release the file attributes structure */ + + kmm_free(priv); + filep->f_priv = NULL; + return OK; +} + +/**************************************************************************** + * Name: netprocfs_read + ****************************************************************************/ + +static ssize_t netprocfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ +#ifdef CONFIG_NET_STATISTICS + FAR struct netprocfs_file_s *priv; + size_t xfrsize; + ssize_t nreturned; + + fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen); + + /* Recover our private data from the struct file instance */ + + priv = (FAR struct netprocfs_file_s *)filep->f_priv; + DEBUGASSERT(priv); + + /* Is there line data already buffered? */ + + nreturned = 0; + if (priv->linesize > 0) + { + /* Yes, how much can we transfer now? */ + + xfrsize = priv->linesize; + if (xfrsize > buflen) + { + xfrsize = buflen; + } + + /* Transfer the data to the user buffer */ + + memcpy(buffer, &priv->line[priv->offset], xfrsize); + + /* Update pointers, sizes, and offsets */ + + buffer += xfrsize; + buflen -= xfrsize; + + priv->linesize -= xfrsize; + priv->offset += xfrsize; + nreturned = xfrsize; + } + + /* Loop until the user buffer is full or until all of the network + * statistics have been transferred. At this point we know that + * either: + * + * 1. The user buffer is full, and/or + * 2. All of the current line data has been transferred. + */ + + while (buflen > 0 && priv->lineno < NSTAT_LINES) + { + int len; + + /* Read the next line into the working buffer */ + + len = g_linegen[priv->lineno](priv); + + /* Update line-related information */ + + priv->lineno++; + priv->linesize = len; + priv->offset = 0; + + /* Transfer data to the user buffer */ + + xfrsize = priv->linesize; + if (xfrsize > buflen) + { + xfrsize = buflen; + } + + memcpy(buffer, &priv->line[priv->offset], xfrsize); + + /* Update pointers, sizes, and offsets */ + + buffer += xfrsize; + buflen -= xfrsize; + + priv->linesize -= xfrsize; + priv->offset += xfrsize; + nreturned += xfrsize; + } + + /* Update the file offset */ + + if (nreturned > 0) + { + filep->f_pos += nreturned; + } + + return nreturned; +#else + return 0; +#endif +} + +/**************************************************************************** + * Name: netprocfs_dup + * + * Description: + * Duplicate open file data in the new file structure. + * + ****************************************************************************/ + +static int netprocfs_dup(FAR const struct file *oldp, FAR struct file *newp) +{ + FAR struct netprocfs_file_s *oldpriv; + FAR struct netprocfs_file_s *newpriv; + + fvdbg("Dup %p->%p\n", oldp, newp); + + /* Recover our private data from the old struct file instance */ + + oldpriv = (FAR struct netprocfs_file_s *)oldp->f_priv; + DEBUGASSERT(oldpriv); + + /* Allocate a new container to hold the task and attribute selection */ + + newpriv = (FAR struct netprocfs_file_s *)kmm_zalloc(sizeof(struct netprocfs_file_s)); + if (!newpriv) + { + fdbg("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* The copy the file attribtes from the old attributes to the new */ + + memcpy(newpriv, oldpriv, sizeof(struct netprocfs_file_s)); + + /* Save the new attributes in the new file structure */ + + newp->f_priv = (FAR void *)newpriv; + return OK; +} + +/**************************************************************************** + * Name: netprocfs_opendir + * + * Description: + * Open a directory for read access + * + ****************************************************************************/ + +static int netprocfs_opendir(FAR const char *relpath, + FAR struct fs_dirent_s *dir) +{ + FAR struct netprocfs_level1_s *level1; + + fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL"); + DEBUGASSERT(relpath && dir && !dir->u.procfs); + + /* The path refers to the 1st level sbdirectory. Allocate the level1 + * dirent structure. + */ + + level1 = (FAR struct netprocfs_level1_s *) + kmm_zalloc(sizeof(struct netprocfs_level1_s)); + + if (!level1) + { + fdbg("ERROR: Failed to allocate the level1 directory structure\n"); + return -ENOMEM; + } + + /* Initialze base structure components */ + + level1->base.level = 1; + level1->base.nentries = 1; + level1->base.index = 0; + + dir->u.procfs = (FAR void *) level1; + return OK; +} + +/**************************************************************************** + * Name: netprocfs_closedir + * + * Description: Close the directory listing + * + ****************************************************************************/ + +static int netprocfs_closedir(FAR struct fs_dirent_s *dir) +{ + FAR struct netprocfs_level1_s *priv; + + DEBUGASSERT(dir && dir->u.procfs); + priv = dir->u.procfs; + + if (priv) + { + kmm_free(priv); + } + + dir->u.procfs = NULL; + return OK; +} + +/**************************************************************************** + * Name: netprocfs_readdir + * + * Description: Read the next directory entry + * + ****************************************************************************/ + +static int netprocfs_readdir(FAR struct fs_dirent_s *dir) +{ + FAR struct netprocfs_level1_s *level1; + int index; + int ret; + + DEBUGASSERT(dir && dir->u.procfs); + level1 = dir->u.procfs; + + /* Have we reached the end of the directory */ + + index = level1->base.index; + if (index >= level1->base.nentries) + { + /* We signal the end of the directory by returning the special + * error -ENOENT + */ + + fvdbg("Entry %d: End of directory\n", index); + ret = -ENOENT; + } + + /* Currently only one element in the directory */ + + else + { + DEBUGASSERT(level1->base.level == 1); + DEBUGASSERT(level1->base.index <= 1); + + /* Copy the one supported directory entry */ + + dir->fd_dir.d_type = DTYPE_FILE; + strncpy(dir->fd_dir.d_name, "stat", NAME_MAX + 1); + + /* Set up the next directory entry offset. NOTE that we could use the + * standard f_pos instead of our own private index. + */ + + level1->base.index = index + 1; + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Name: netprocfs_rewindir + * + * Description: Reset directory read to the first entry + * + ****************************************************************************/ + +static int netprocfs_rewinddir(FAR struct fs_dirent_s *dir) +{ + FAR struct netprocfs_level1_s *priv; + + DEBUGASSERT(dir && dir->u.procfs); + priv = dir->u.procfs; + + priv->base.index = 0; + return OK; +} + +/**************************************************************************** + * Name: netprocfs_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int netprocfs_stat(FAR const char *relpath, FAR struct stat *buf) +{ + /* "net" and "net/stat" are the only acceptable values for the relpath */ + + if (strcmp(relpath, "net") == 0) + { + buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; + } + else if (strcmp(relpath, "net/stat") == 0) + { + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + } + else + { + fdbg("ERROR: relpath is '%s'\n", relpath); + return -ENOENT; + } + + /* File/directory size, access block size */ + + buf->st_size = 0; + buf->st_blksize = 512; + buf->st_blocks = 0; + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */