You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by da...@apache.org on 2020/09/29 19:26:37 UTC

[incubator-nuttx-apps] branch master updated: Add IPv4 Configuration File Access Helper

This is an automated email from the ASF dual-hosted git repository.

davids5 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new 5e1ba40  Add IPv4 Configuration File Access Helper
5e1ba40 is described below

commit 5e1ba408b4b88ff8958cfcac08df8a4b75197fa8
Author: Gregory Nutt <gn...@nuttx.org>
AuthorDate: Mon Sep 28 11:51:50 2020 -0600

    Add IPv4 Configuration File Access Helper
    
    This commit adds support to access an IPv4 Configuration file similar to the Linux dhpc.client ipfcg file.  This version, tailored for deeply embedded systems supports several options to tailor the file and file access to different environments.  It supports:
    
    - Writable as well as read-only configuration files.
    - ASCII human readable files as well as smaller binary files.
    - It supports using character driver access to constrained media (such as EEPROM).
    - Add examples/ipcfg to exercise IPv4 Configuration File support
---
 examples/ipcfg/Kconfig      |  30 +++
 examples/ipcfg/Make.defs    |  24 ++
 examples/ipcfg/Makefile     |  34 +++
 examples/ipcfg/ipcfg_main.c | 196 +++++++++++++++
 fsutils/ipcfg/Kconfig       |  71 ++++++
 fsutils/ipcfg/Make.defs     |  23 ++
 fsutils/ipcfg/Makefile      |  29 +++
 fsutils/ipcfg/ipcfg.c       | 575 ++++++++++++++++++++++++++++++++++++++++++++
 include/fsutils/ipcfg.h     | 136 +++++++++++
 9 files changed, 1118 insertions(+)

diff --git a/examples/ipcfg/Kconfig b/examples/ipcfg/Kconfig
new file mode 100644
index 0000000..3fbbfdd
--- /dev/null
+++ b/examples/ipcfg/Kconfig
@@ -0,0 +1,30 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config EXAMPLES_IPCFG
+	tristate "IPv4 Configuration file example"
+	default n
+	select FS_TMPFS
+	---help---
+		Enable the IPv4 Configuration file example
+
+if EXAMPLES_IPCFG
+
+config EXAMPLES_IPCFG_PROGNAME
+	string "IPCFG Program name"
+	default "ipcfg"
+	---help---
+		This is the name of the program that will be used when the NSH ELF
+		program is installed.
+
+config EXAMPLES_IPCFG_PRIORITY
+	int "IPCFG task priority"
+	default 100
+
+config EXAMPLES_IPCFG_STACKSIZE
+	int "IPCFG stack size"
+	default DEFAULT_TASK_STACKSIZE
+
+endif
diff --git a/examples/ipcfg/Make.defs b/examples/ipcfg/Make.defs
new file mode 100644
index 0000000..970271c
--- /dev/null
+++ b/examples/ipcfg/Make.defs
@@ -0,0 +1,24 @@
+############################################################################
+# apps/examples/ipcfg/Make.defs
+# Adds selected applications to apps/ build
+#
+# 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.
+#
+############################################################################
+
+ifneq ($(CONFIG_EXAMPLES_IPCFG),)
+CONFIGURED_APPS += $(APPDIR)/examples/ipcfg
+endif
diff --git a/examples/ipcfg/Makefile b/examples/ipcfg/Makefile
new file mode 100644
index 0000000..82c6b01
--- /dev/null
+++ b/examples/ipcfg/Makefile
@@ -0,0 +1,34 @@
+############################################################################
+# apps/examples/ipcfg/Makefile
+#
+# 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.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# IPv4 Configuration file example built-in application info
+
+PROGNAME  = $(CONFIG_EXAMPLES_IPCFG_PROGNAME)
+PRIORITY  = $(CONFIG_EXAMPLES_IPCFG_PRIORITY)
+STACKSIZE = $(CONFIG_EXAMPLES_IPCFG_STACKSIZE)
+MODULE    = $(CONFIG_EXAMPLES_IPCFG)
+
+# Pv4 Configuration file example
+
+MAINSRC = ipcfg_main.c
+
+include $(APPDIR)/Application.mk
diff --git a/examples/ipcfg/ipcfg_main.c b/examples/ipcfg/ipcfg_main.c
new file mode 100644
index 0000000..6107a50
--- /dev/null
+++ b/examples/ipcfg/ipcfg_main.c
@@ -0,0 +1,196 @@
+/****************************************************************************
+ * examples/ipcfg/ipcfg_main.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <sys/mount.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arpa/inet.h>
+
+#include "fsutils/ipcfg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_IPCFG_CHARDEV
+#  error This example will not work with a character device
+#endif
+
+#ifndef CONFIG_IPCFG_WRITABLE
+#  warning This example will not work with a without write support
+#endif
+
+#define DEVICE1       "eth0"
+#define DEVICE2       "eth1"
+#define BOOTPROTO_MAX BOOTPROTO_FALLBACK
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char *g_proto_name[] =
+{
+  "none",      /* BOOTPROTO_NONE */
+  "static",    /* BOOTPROTO_STATIC */
+  "dhcp",      /* BOOTPROTO_DHCP */
+  "fallback"   /* BOOTPROTO_FALLBACK */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_dump_addr
+ ****************************************************************************/
+
+static void ipcfg_dump_addr(FAR const char *variable, in_addr_t address)
+{
+  if (address == 0)
+    {
+      printf("%s[UNSPECIFIED]\n", variable);
+    }
+  else
+    {
+      struct in_addr saddr =
+      {
+        address
+      };
+
+      printf("%s%s\n", variable, inet_ntoa(saddr));
+    }
+}
+
+/****************************************************************************
+ * Name: ipcfg_dump_config
+ ****************************************************************************/
+
+static int ipcfg_dump_config(FAR const char *netdev)
+{
+  struct ipcfg_s ipcfg;
+  int ret;
+
+  ret = ipcfg_read(netdev, &ipcfg);
+  if (ret < 0)
+    {
+      fprintf(stderr, "ERROR: ipcfg_read() failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Dump the content in human readable form */
+
+  printf("%s:\n", netdev);
+
+  if (ipcfg.proto > BOOTPROTO_MAX)
+    {
+      printf("BOOTPROTO: %d [INVALID]\n", ipcfg.proto);
+    }
+  else
+    {
+      printf("BOOTPROTO: %s\n", g_proto_name[ipcfg.proto]);
+    }
+
+  ipcfg_dump_addr("IPADDR:     ",  ipcfg.ipaddr);
+  ipcfg_dump_addr("NETMASK:    ",  ipcfg.netmask);
+  ipcfg_dump_addr("ROUTER:     ",  ipcfg.router);
+  ipcfg_dump_addr("DNS:        ",  ipcfg.dnsaddr);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ipcfg_write_config
+ ****************************************************************************/
+
+static int ipcfg_write_config(FAR const char *netdev)
+{
+  struct ipcfg_s ipcfg;
+  int ret;
+
+  ipcfg.proto   = BOOTPROTO_DHCP;
+  ipcfg.ipaddr  = HTONL(0x0a000002);
+  ipcfg.netmask = HTONL(0xffffff00);
+  ipcfg.router  = HTONL(0x0a000001);
+  ipcfg.router  = HTONL(0x0a000003);
+
+  ret = ipcfg_write(netdev, &ipcfg);
+  if (ret < 0)
+    {
+      fprintf(stderr, "ERROR: ipcfg_read() ipcfg_write: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  int ret;
+
+  /* Mount the TMPFS file system at the expected location for the IPv4
+   * Configuration file directory.
+   */
+
+  ret = mount(NULL, CONFIG_IPCFG_PATH, "tmpfs", 0, NULL);
+  if (ret < 0)
+    {
+      int errcode = errno;
+      fprintf(stderr, "ERROR: Failed to open " CONFIG_IPCFG_PATH "\n: %d",
+              errcode);
+      return EXIT_FAILURE;
+    }
+
+  /* Dump files.  These should all fail. */
+
+  printf("\n1. Dump before creating configuration files\n\n");
+  ipcfg_dump_config(DEVICE1);
+  ipcfg_dump_config(DEVICE2);
+
+#ifdef CONFIG_IPCFG_WRITABLE
+  /* Create files */
+
+  printf("\n2. Create configuration files\n\n");
+  ipcfg_write_config(DEVICE1);
+  ipcfg_write_config(DEVICE2);
+
+  /* Dump the files again */
+
+  printf("\n3. Dump after creating configuration files\n\n");
+  ipcfg_dump_config(DEVICE1);
+  ipcfg_dump_config(DEVICE2);
+#endif
+
+  umount(CONFIG_IPCFG_PATH);
+  return EXIT_SUCCESS;
+}
diff --git a/fsutils/ipcfg/Kconfig b/fsutils/ipcfg/Kconfig
new file mode 100644
index 0000000..9979f6a
--- /dev/null
+++ b/fsutils/ipcfg/Kconfig
@@ -0,0 +1,71 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config FSUTILS_IPCFG
+	bool "IPv4 Configuration File Support"
+	default n
+	depends on NET_IPv4
+	---help---
+		Enables support for an IPv4 configuration file that holds IP
+		address and/or DHCP configuration information for a
+		specific network device
+
+		There is no dependency on IPv4 networking support so this
+		configuration may be used in testing without a network.
+
+if FSUTILS_IPCFG
+
+config IPCFG_WRITABLE
+	bool "Writable IPv4 Configuration"
+	default y
+	---help---
+		Can be used to disable writing to the IPv4 Configuration file.  This
+		would be necessary if, for example, the IPv4 Configuration file were
+		provided on a read-only file system.
+
+config IPCFG_BINARY
+	bool "Binary IPv4 Configuration File"
+	default n
+	---help---
+		By default, the IPv4 configuration file is an ASCII human readable
+		file with <varialble>=<value> pairs.  A Binary interface may be used
+		for more constrained media such as EEPROM.
+
+config IPCFG_PATH
+	string "IPv4 Configuration File Directory"
+	default "/etc/sysconfig/network-scripts"
+	---help---
+		Specifies the full path to the directory or mountpoint that holds
+		the IPv4 Configuration files.  Each individual configuration file
+		within this directory will have names like ipcfg-eth0.
+
+		If CONFIG_IPCFG_CHARDEV is select, this setting is interpreted
+		differently.  In this case, CONFIG_IPCFG_PATH is the full path
+		to the character driver.
+
+config IPCFG_CHARDEV
+	bool "Character Driver"
+	default n
+	depends on IPCFG_BINARY
+	---help---
+		In some use cases, where there is only a single network device and
+		only a single network device, a character driver on, perhaps, EEPROM
+		may be used.  In this case there is not file system and the
+		CONFIG_IPCFG_PATH will refer to that character driver.
+
+		NOTE that this configuration is only support with CONFIG_IPCFG_BINARY.
+
+config IPCFG_OFFSET
+	int "Data offset"
+	default 0
+	depends on IPCFG_CHARDEV
+	---help---
+		Seek to this offset before reading or writing the IPv4 Configuration.
+		This is only support for the character driver device.  This permits
+		some formatting of, say, EEPROM, so that multiple, different
+		configurations can be maintained at differnt offsets into the IPv4
+		Configuration File.
+
+endif # FSUTILS_IPCFG
diff --git a/fsutils/ipcfg/Make.defs b/fsutils/ipcfg/Make.defs
new file mode 100644
index 0000000..5e44ae6
--- /dev/null
+++ b/fsutils/ipcfg/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/fsutils/ipcfg/Make.defs
+#
+# 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_FSUTILS_IPCFG),y)
+CONFIGURED_APPS += $(APPDIR)/fsutils/ipcfg
+endif
diff --git a/fsutils/ipcfg/Makefile b/fsutils/ipcfg/Makefile
new file mode 100644
index 0000000..de6dcb2
--- /dev/null
+++ b/fsutils/ipcfg/Makefile
@@ -0,0 +1,29 @@
+############################################################################
+# apps/fsutils/ipcfg/Makefile
+#
+# 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.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# IPv4 Configuration file access library
+
+ifeq ($(CONFIG_FSUTILS_IPCFG),y)
+CSRCS += ipcfg.c
+endif
+
+include $(APPDIR)/Application.mk
diff --git a/fsutils/ipcfg/ipcfg.c b/fsutils/ipcfg/ipcfg.c
new file mode 100644
index 0000000..43a1842
--- /dev/null
+++ b/fsutils/ipcfg/ipcfg.c
@@ -0,0 +1,575 @@
+/****************************************************************************
+ * apps/fsutils/ipcfg/ipcfg.c
+ *
+ * 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 <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "fsutils/ipcfg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX_LINESIZE  80
+#define MAX_BOOTPROTO BOOTPROTO_FALLBACK
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && !defined(CONFIG_IPCFG_BINARY)
+static const char *g_proto_name[] =
+{
+  "none",      /* BOOTPROTO_NONE */
+  "static",    /* BOOTPROTO_STATIC */
+  "dhcp",      /* BOOTPROTO_DHCP */
+  "fallback"   /* BOOTPROTO_FALLBACK */
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_allocpath
+ *
+ * Description:
+ *   Allocate memory for and construct the full path to the IPv4
+ *   Configuration file.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *
+ * Returned Value:
+ *   A pointer to the allocated path is returned.  NULL is returned only on
+ *  on a failure to allocate.
+ *
+ ****************************************************************************/
+
+static inline FAR char *ipcfg_allocpath(FAR const char *netdev)
+{
+#ifndef CONFIG_IPCFG_CHARDEV
+  FAR char *path = NULL;
+  int ret;
+
+  /* Create the full path to the ipcfg file for the network device.
+   * the path of CONFIG_IPCFG_PATH returns to a directory containing
+   * multiple files of the form ipcfg-<dev> where <dev> is the network
+   * device name.  For example, ipcfg-eth0.
+   */
+
+  ret = asprintf(&path, CONFIG_IPCFG_PATH "/ipcfg-%s", netdev);
+  if (ret < 0 || path == NULL)
+    {
+      /* Assume that asprintf failed to allocate memory */
+
+      fprintf(stderr, "ERROR: Failed to create path to ipcfg file: %d\n",
+              ret);
+      return NULL;
+    }
+
+  return path;
+
+#else
+  /* In this case CONFIG_IPCFG_PATH is the full path to a character device
+   * that describes the configuration of a single network device.
+   *
+   * It is dup'ed to simplify typing (const vs non-const) and to make the
+   * free operation unconditional.
+   */
+
+  return strdup(CONFIG_IPCFG_PATH);
+#endif
+}
+
+/****************************************************************************
+ * Name: ipcfg_open (for ASCII mode)
+ *
+ * Description:
+ *   Form the complete path to the ipcfg file and open it.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *   stream - Location to return the opened stream
+ *   mode   - File fopen mode
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_IPCFG_BINARY
+static int ipcfg_open(FAR const char *netdev, FAR FILE **stream,
+                      FAR const char *mode)
+{
+  FAR char *path;
+  int ret;
+
+  /* Create the full path to the ipcfg file for the network device */
+
+  path = ipcfg_allocpath(netdev);
+  if (path == NULL)
+    {
+      /* Assume failure to allocate memory */
+
+      fprintf(stderr, "ERROR: Failed to create path to ipcfg file\n");
+      return -ENOMEM;
+    }
+
+  /* Now open the file */
+
+  *stream = fopen(path, mode);
+  ret     = OK;
+
+  if (*stream == NULL)
+    {
+      ret = -errno;
+      fprintf(stderr, "ERROR: Failed to open %s: %d\n", path, ret);
+    }
+
+  free(path);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_open (for binary mode)
+ *
+ * Description:
+ *   Form the complete path to the ipcfg file and open it.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *   oflags - File open flags
+ *   mode   - File creation mode
+ *
+ * Returned Value:
+ *   The open file descriptor is returned on success; a negated errno value
+ *   is returned on any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IPCFG_BINARY
+static int ipcfg_open(FAR const char *netdev, int oflags, mode_t mode)
+{
+  FAR char *path;
+  int fd;
+  int ret;
+
+  /* Create the full path to the ipcfg file for the network device */
+
+  path = ipcfg_allocpath(netdev);
+  if (path == NULL)
+    {
+      /* Assume failure to allocate memory */
+
+      fprintf(stderr, "ERROR: Failed to create path to ipcfg file\n");
+      return -ENOMEM;
+    }
+
+  /* Now open the file */
+
+  fd  = open(path, oflags, mode);
+  ret = OK;
+
+  if (fd < 0)
+    {
+      ret = -errno;
+      fprintf(stderr, "ERROR: Failed to open %s: %d\n", path, ret);
+      goto errout_with_path;
+    }
+
+#if defined(CONFIG_IPCFG_OFFSET) && CONFIG_IPCFG_OFFSET > 0
+  /* If the binary file is accessed on a character device as a binary
+   * file, then there is also an option to seek to a location on the
+   * media before reading or writing the file.
+   */
+
+  ret = lseek(fd, CONFIG_IPCFG_OFFSET, SEEK_SET);
+  if (ret < 0)
+    {
+      ret = -errno;
+      fprintf(stderr, "ERROR: Failed to seek to $ld: %d\n",
+              (long)CONFIG_IPCFG_OFFSET, ret);
+      close(fd);
+    }
+#endif
+
+errout_with_path:
+  free(path);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_trim
+ *
+ * Description:
+ *   Skip over any whitespace.
+ *
+ * Input Parameters:
+ *   line  - Pointer to line buffer
+ *   index - Current index into the line buffer
+ *
+ * Returned Value:
+ *   New value of index.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_IPCFG_BINARY
+static int ipcfg_trim(FAR char *line, int index)
+{
+  int ret;
+  while (line[index] != '\0' && isspace(line[index]))
+    {
+      index++;
+    }
+
+  ret = index;
+  while (line[index] != '\0')
+    {
+      if (!isprint(line[index]))
+        {
+          line[index] = '\0';
+          break;
+        }
+
+      index++;
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_putaddr
+ *
+ * Description:
+ *   Write a <variable>=<address> value pair to the stream.
+ *
+ * Input Parameters:
+ *   stream   - The output stream
+ *   variable - The variable namespace
+ *   address  - The IP address to write
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && !defined(CONFIG_IPCFG_BINARY)
+static void ipcfg_putaddr(FAR FILE *stream, FAR const char *variable,
+                          in_addr_t address)
+{
+  /* REVISIT:  inet_ntoa() is not thread safe. */
+
+  if (address != 0)
+    {
+      struct in_addr saddr =
+      {
+        address
+      };
+
+      fprintf(stream, "%s=%s\n", variable, inet_ntoa(saddr));
+    }
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_read
+ *
+ * Description:
+ *   Read and parse the IP configuration file for the specified network
+ *   device.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *   ipcfg  - Pointer to a user provided location to receive the IP
+ *            configuration.
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+int ipcfg_read(FAR const char *netdev, FAR struct ipcfg_s *ipcfg)
+{
+#ifdef CONFIG_IPCFG_BINARY
+  ssize_t nread;
+  int fd;
+  int ret;
+
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
+
+  /* Open the file */
+
+  fd = ipcfg_open(netdev, O_RDONLY, 0666);
+  if (fd < 0)
+    {
+      return fd;
+    }
+
+  /* Read the file content */
+
+  nread = read(fd, ipcfg, sizeof(struct ipcfg_s));
+  if (nread < 0)
+    {
+      ret = -errno;
+      fprintf(stderr, "ERROR: Failed to read file: %d\n", ret);
+    }
+  else if (nread != sizeof(struct ipcfg_s))
+    {
+      ret = -EIO;
+      fprintf(stderr, "ERROR: Bad read size: %ld\n", (long)nread);
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  close(fd);
+  return ret;
+
+#else
+  FAR FILE *stream;
+  char line[MAX_LINESIZE];
+  int index;
+  int ret;
+
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
+
+  /* Open the file */
+
+  ret = ipcfg_open(netdev, &stream, "r");
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Process each line in the file */
+
+  memset(ipcfg, 0, sizeof(FAR struct ipcfg_s));
+
+  while (fgets(line, MAX_LINESIZE, stream) != NULL)
+    {
+      /* Skip any leading whitespace */
+
+      index = ipcfg_trim(line, 0);
+
+      /* Check for a blank line or a comment */
+
+      if (line[index] != '\0' && line[index] != '#')
+        {
+          FAR char *variable = &line[index];
+          FAR char *value;
+
+          /* Expect <variable>=<value> pair */
+
+          value = strchr(variable, '=');
+          if (value == NULL)
+            {
+              fprintf(stderr, "ERROR: Skipping malformed line in file: %s\n",
+                      line);
+              continue;
+            }
+
+          /* NUL-terminate the variable string */
+
+          *value++ = '\0';
+
+          /* Process the variable assignment */
+
+          if (strcmp(variable, "DEVICE") == 0)
+            {
+              /* Just assure that it matches the filename */
+
+              if (strcmp(value, netdev) != 0)
+                {
+                  fprintf(stderr, "ERROR: Bad device in file: %s=%s\n",
+                          variable, value);
+                }
+            }
+          else if (strcmp(variable, "BOOTPROTO") == 0)
+            {
+              if (strcmp(value, "none") == 0)
+                {
+                  ipcfg->proto = BOOTPROTO_NONE;
+                }
+              else if (strcmp(value, "static") == 0)
+                {
+                  ipcfg->proto = BOOTPROTO_STATIC;
+                }
+              else if (strcmp(value, "dhcp") == 0)
+                {
+                  ipcfg->proto = BOOTPROTO_DHCP;
+                }
+              else if (strcmp(value, "fallback") == 0)
+                {
+                  ipcfg->proto = BOOTPROTO_FALLBACK;
+                }
+              else
+                {
+                  fprintf(stderr, "ERROR: Unrecognized BOOTPROTO: %s=%s\n",
+                          variable, value);
+                }
+            }
+          else if (strcmp(variable, "IPADDR") == 0)
+            {
+              ipcfg->ipaddr = inet_addr(value);
+            }
+          else if (strcmp(variable, "NETMASK") == 0)
+            {
+              ipcfg->netmask = inet_addr(value);
+            }
+          else if (strcmp(variable, "ROUTER") == 0)
+            {
+              ipcfg->router = inet_addr(value);
+            }
+          else if (strcmp(variable, "DNS") == 0)
+            {
+              ipcfg->dnsaddr = inet_addr(value);
+            }
+          else
+            {
+              fprintf(stderr, "ERROR: Unrecognized variable: %s=%s\n",
+                     variable, value);
+            }
+        }
+    }
+
+  /* Close the file and return */
+
+  fclose(stream);
+  return OK;
+#endif
+}
+
+/****************************************************************************
+ * Name: ipcfg_write
+ *
+ * Description:
+ *   Write the IP configuration file for the specified network device.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *   ipcfg  - The IP configuration to be written.
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IPCFG_WRITABLE
+int ipcfg_write(FAR const char *netdev, FAR const struct ipcfg_s *ipcfg)
+{
+#ifdef CONFIG_IPCFG_BINARY
+  ssize_t nwritten;
+  int fd;
+  int ret;
+
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
+
+  /* Open the file */
+
+  fd = ipcfg_open(netdev, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+  if (fd < 0)
+    {
+      return fd;
+    }
+
+  /* Write the file content */
+
+  nwritten = write(fd, ipcfg, sizeof(struct ipcfg_s));
+  if (nwritten < 0)
+    {
+      ret = -errno;
+      fprintf(stderr, "ERROR: Failed to write file: %d\n", ret);
+    }
+  else if (nwritten != sizeof(struct ipcfg_s))
+    {
+      ret = -EIO;
+      fprintf(stderr, "ERROR: Bad write size: %ld\n", (long)nwritten);
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  close(fd);
+  return ret;
+
+#else
+  FAR FILE *stream;
+  int ret;
+
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
+
+  /* Open the file */
+
+  ret = ipcfg_open(netdev, &stream, "w");
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Format and write the file */
+
+  if ((unsigned)ipcfg->proto == MAX_BOOTPROTO)
+    {
+      fprintf(stderr, "ERROR: Unrecognized BOOTPROTO value: %d\n",
+              ipcfg->proto);
+      return -EINVAL;
+    }
+
+  fprintf(stream, "DEVICE=%s\n", netdev);
+  fprintf(stream, "BOOTPROTO=%s\n", g_proto_name[ipcfg->proto]);
+
+  ipcfg_putaddr(stream, "IPADDR",  ipcfg->ipaddr);
+  ipcfg_putaddr(stream, "NETMASK", ipcfg->netmask);
+  ipcfg_putaddr(stream, "ROUTER",  ipcfg->router);
+  ipcfg_putaddr(stream, "DNS",     ipcfg->dnsaddr);
+
+  /* Close the file and return */
+
+  fclose(stream);
+  return OK;
+#endif
+}
+#endif
diff --git a/include/fsutils/ipcfg.h b/include/fsutils/ipcfg.h
new file mode 100644
index 0000000..e594871
--- /dev/null
+++ b/include/fsutils/ipcfg.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * apps/include/fsutils/ipcfg.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_FSUTILS_IPCFG_H
+#define __APPS_INCLUDE_FSUTILS_IPCFG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <netinet/in.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Values for the BOOTPROTO setting */
+
+enum ipcfg_bootproto_e
+{
+  BOOTPROTO_NONE     = 0, /* No protocol assigned */
+  BOOTPROTO_STATIC   = 1, /* Use static IP */
+  BOOTPROTO_DHCP     = 2, /* Use DHCP */
+  BOOTPROTO_FALLBACK = 3  /* Use DHCP with fall back static IP */
+};
+
+/* The structure contains the parsed content of the ipcfg-<dev> file.
+ * Summary of file content:
+ *
+ * DEVICE=name
+ *   where name is the name of the physical device.
+ *
+ * BOOTPROTO=protocol
+ *   where protocol is one of the following:
+ *
+ *     none     - No protocol selected
+ *     static   - Use static IP
+ *     dhcp     - The DHCP protocol should be used
+ *     fallback - Use DHCP with fall back static IP
+ *
+ * All of the following addresses are in network order.  The special value
+ * zero is used to indicate that the address is not available:
+ *
+ * IPADDR=address
+ *    where address is the IPv4 address.  Used only with static or fallback
+ *    protocols.
+ *
+ * NETMASK=address
+ *    where address is the netmask.  Used only with static or fallback
+ *    protocols.
+ *
+ * ROUTER=address
+ *    where address is the IPv4 default router address.  Used only with
+ *    static or fallback protocols.
+ *
+ * DNS=address
+ *   where address is a (optional) name server address.
+ */
+
+struct ipcfg_s
+{
+  enum ipcfg_bootproto_e proto; /* Configure for static and/or DHCP */
+
+  /* The following fields are required for static/fallback configurations */
+
+  in_addr_t ipaddr;             /* IPv4 address */
+  in_addr_t netmask;            /* Network mask */
+  in_addr_t router;             /* Default router */
+
+  /* The following fields are optional for dhcp and fallback configurations */
+
+  in_addr_t dnsaddr;            /* Name server address */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_read
+ *
+ * Description:
+ *   Read and parse the IP configuration file for the specified network
+ *   device.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *   ipcfg  - Pointer to a user provided location to receive the IP
+ *            configuration.
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+int ipcfg_read(FAR const char *netdev, FAR struct ipcfg_s *ipcfg);
+
+/****************************************************************************
+ * Name: ipcfg_write
+ *
+ * Description:
+ *   Write the IP configuration file for the specified network device.
+ *
+ * Input Parameters:
+ *   netdev - The network device.  For examplel "eth0"
+ *   ipcfg  - The IP configuration to be written.
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IPCFG_WRITABLE
+int ipcfg_write(FAR const char *netdev, FAR const struct ipcfg_s *ipcfg);
+#endif
+
+#endif /* __APPS_INCLUDE_FSUTILS_IPCFG_H */