1
0
Fork 0
forked from nuttx/nuttx-update

net/net_procfs.c: Add basic support for networking procfs entries

This commit is contained in:
Gregory Nutt 2015-11-27 12:33:58 -06:00
parent 5d1557b28d
commit e4236941c6
10 changed files with 962 additions and 21 deletions

View file

@ -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).
statistics (2015-11-26).
* net/net_procfs.c: Add basic support for networking entries in the
procfs (2015-11-27).

6
TODO
View file

@ -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

2
arch

@ -1 +1 @@
Subproject commit 26a3df81693aa11a487fda52ee001792ed4212a6
Subproject commit 7a800cc36f9078f59f3f19c6eb400701952cfb7c

@ -1 +1 @@
Subproject commit b52f98b9c91f8d84e7484e818e065b1e63b1d469
Subproject commit 18c27d653564ec78841d6912597155fde62467c7

View file

@ -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

View file

@ -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 */

View file

@ -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 */
};
/****************************************************************************

View file

@ -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;

View file

@ -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 =

912
net/net_procfs.c Normal file
View file

@ -0,0 +1,912 @@
/****************************************************************************
* net/net_procfs.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <sys/statfs.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/procfs.h>
#include <nuttx/fs/dirent.h>
#include <nuttx/net/netstats.h>
#include <arch/irq.h>
#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 */