You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2020/10/04 16:07:13 UTC

[incubator-nuttx-apps] branch master updated: apps/fsutils/ipcfg: Add support for IPv6

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

xiaoxiang 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 a627561  apps/fsutils/ipcfg:  Add support for IPv6
a627561 is described below

commit a627561c8f8b6cd72ffe45ed8574411929342040
Author: Gregory Nutt <gn...@nuttx.org>
AuthorDate: Fri Oct 2 15:43:24 2020 -0600

    apps/fsutils/ipcfg:  Add support for IPv6
---
 examples/ipcfg/Kconfig       |   5 +-
 examples/ipcfg/ipcfg_main.c  | 442 ++++++++++++++++++++++--
 fsutils/ipcfg/Kconfig        |  27 +-
 fsutils/ipcfg/Makefile       |   7 +-
 fsutils/ipcfg/ipcfg.c        | 552 ++++++-----------------------
 fsutils/ipcfg/ipcfg.h        | 238 +++++++++++++
 fsutils/ipcfg/ipcfg_binary.c | 568 ++++++++++++++++++++++++++++++
 fsutils/ipcfg/ipcfg_text.c   | 805 +++++++++++++++++++++++++++++++++++++++++++
 include/fsutils/ipcfg.h      |   9 +-
 9 files changed, 2160 insertions(+), 493 deletions(-)

diff --git a/examples/ipcfg/Kconfig b/examples/ipcfg/Kconfig
index 3fbbfdd..6de9875 100644
--- a/examples/ipcfg/Kconfig
+++ b/examples/ipcfg/Kconfig
@@ -4,11 +4,12 @@
 #
 
 config EXAMPLES_IPCFG
-	tristate "IPv4 Configuration file example"
+	tristate "IP Configuration file example"
 	default n
 	select FS_TMPFS
+	depends on FSUTILS_IPCFG
 	---help---
-		Enable the IPv4 Configuration file example
+		Enable the IP Configuration file example
 
 if EXAMPLES_IPCFG
 
diff --git a/examples/ipcfg/ipcfg_main.c b/examples/ipcfg/ipcfg_main.c
index c899b2d..bf42b43 100644
--- a/examples/ipcfg/ipcfg_main.c
+++ b/examples/ipcfg/ipcfg_main.c
@@ -27,6 +27,8 @@
 #include <sys/mount.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <fcntl.h>
+#include <debug.h>
 
 #include <arpa/inet.h>
 
@@ -46,12 +48,17 @@
 
 #define DEVICE1       "eth0"
 #define DEVICE2       "eth1"
+#define PATH1         CONFIG_IPCFG_PATH "/ipcfg-" DEVICE1
+#define PATH2         CONFIG_IPCFG_PATH "/ipcfg-" DEVICE2
 #define IPv4PROTO_MAX IPv4PROTO_FALLBACK
+#define IPv6PROTO_MAX IPv6PROTO_FALLBACK
+#define IOBUFFERSIZE  1024
 
 /****************************************************************************
  * Private Data
  ****************************************************************************/
 
+#ifdef CONFIG_NET_IPv4
 static const char *g_ipv4proto_name[] =
 {
   "none",      /* IPv4PROTO_NONE */
@@ -59,23 +66,217 @@ static const char *g_ipv4proto_name[] =
   "dhcp",      /* IPv4PROTO_DHCP */
   "fallback"   /* IPv4PROTO_FALLBACK */
 };
+#endif
+
+#ifdef CONFIG_NET_IPv6
+static const char *g_ipv6proto_name[] =
+{
+  "none",      /* IPv6PROTO_NONE */
+  "static",    /* IPv6PROTO_STATIC */
+  "autoconf",  /* IPv6PROTO_AUTOCONF */
+  "fallback"   /* IPv6PROTO_FALLBACK */
+};
+
+static const uint16_t g_ipv6_ipaddr[8] =
+{
+  HTONS(0xfc00),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0002),
+};
+
+static const uint16_t g_ipv6_netmask[8] =
+{
+  HTONS(0xffff),
+  HTONS(0xffff),
+  HTONS(0xffff),
+  HTONS(0xffff),
+  HTONS(0xffff),
+  HTONS(0xffff),
+  HTONS(0x0000),
+  HTONS(0x0000),
+};
+
+static const uint16_t g_ipv6_router[8] =
+{
+  HTONS(0xfc00),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0000),
+  HTONS(0x0001),
+};
+#endif
 
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: ipcfg_dump_addr
+ * Name: ipcfg_nibble
+ *
+ * Description:
+ *  Convert a binary nibble to a hexadecimal character.
+ *
  ****************************************************************************/
 
-static void ipcfg_dump_addr(FAR const char *variable, in_addr_t address)
+#ifdef CONFIG_IPCFG_BINARY
+static char ipcfg_nibble(unsigned char nibble)
 {
-  if (address == 0)
+  if (nibble < 10)
     {
-      printf("%s[UNSPECIFIED]\n", variable);
+      return '0' + nibble;
     }
   else
     {
+      return 'a' + nibble - 10;
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_dump_file
+ *
+ * Description:
+ *   Dump the contents of a file to stdout.
+ *
+ * Input Paratemets:
+ *   filepath - The full path to the file to be dumped
+ *
+ * Returned Value:
+ *   Zero (OK) on success; -1 (ERROR) on failure.
+ *
+ ****************************************************************************/
+
+int ipcfg_dump_file(FAR const char *filepath)
+{
+  FAR char *buffer;
+#ifdef CONFIG_IPCFG_BINARY
+  int nbytes = 0;
+#endif
+  int fd;
+  int ret = OK;
+
+  /* Open the file for reading */
+
+  fd = open(filepath, O_RDONLY);
+  if (fd < 0)
+    {
+      ret = -errno;
+      fprintf(stderr, "ERROR: Failed to open %s: %d\n", filepath, ret);
+      return ret;
+    }
+
+  buffer = (FAR char *)malloc(IOBUFFERSIZE);
+  if (buffer == NULL)
+    {
+      ret = -ENOMEM;
+      fprintf(stderr, "ERROR: Failed to allocate buffer\n");
+      goto errout_with_fd;
+    }
+
+  /* And just dump it byte for byte into stdout */
+
+  for (; ; )
+    {
+      ssize_t nbytesread = read(fd, buffer, IOBUFFERSIZE);
+
+      /* Check for read errors */
+
+      if (nbytesread < 0)
+        {
+          ret = -errno;
+          fprintf(stderr, "ERROR: Read failed: %d\n", ret);
+          goto errout_with_buffer;
+        }
+
+      /* Check for data successfully read */
+
+      else if (nbytesread > 0)
+        {
+#ifndef CONFIG_IPCFG_BINARY
+          int nbyteswritten = 0;
+
+          while (nbyteswritten < nbytesread)
+            {
+              ssize_t n = write(1, buffer + nbyteswritten,
+                                nbytesread - nbyteswritten);
+              if (n < 0)
+                {
+                  ret = -errno;
+                  fprintf(stderr, "ERROR: Write failed: %d\n", ret);
+                  goto errout_with_buffer;
+                }
+              else
+                {
+                  nbyteswritten += n;
+                }
+            }
+#else
+          int i;
+
+          for (i = 0; i < nbytesread; i++)
+            {
+              uint8_t byte = buffer[i];
+
+              if (nbytes == 0)
+                {
+                  printf("  ");
+                }
+
+              putchar(ipcfg_nibble(byte >> 4));
+              putchar(ipcfg_nibble(byte & 0x0f));
+
+              if (++nbytes == 16)
+                {
+                  putchar(' ');
+                }
+
+              if (nbytes == 32)
+                {
+                  putchar('\n');
+                  nbytes = 0;
+                }
+            }
+#endif
+        }
+
+      /* Otherwise, it is the end of file */
+
+      else
+        {
+#ifdef CONFIG_IPCFG_BINARY
+          putchar('\n');
+#endif
+          break;
+        }
+    }
+
+  /* Close the input file and return the result */
+
+errout_with_buffer:
+  free(buffer);
+
+errout_with_fd:
+  close(fd);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ipcfg_dump_ipv4addr
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+static void ipcfg_dump_ipv4addr(FAR const char *variable, in_addr_t address)
+{
+  if (address != 0)
+    {
       struct in_addr saddr =
       {
         address
@@ -84,12 +285,65 @@ static void ipcfg_dump_addr(FAR const char *variable, in_addr_t address)
       printf("%s%s\n", variable, inet_ntoa(saddr));
     }
 }
+#endif
 
 /****************************************************************************
- * Name: ipcfg_dump_config
+ * Name: ipcfg_check_ipv6addr
  ****************************************************************************/
 
-static int ipcfg_dump_config(FAR const char *netdev)
+#ifdef CONFIG_NET_IPv6
+static int ipcfg_check_ipv6addr(FAR const struct in6_addr *address)
+{
+  int i;
+
+  for (i = 0; i < 4; i++)
+    {
+      if (address->s6_addr32[i] != 0)
+        {
+          return OK;
+        }
+    }
+
+  return -ENXIO;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_dump_ipv6addr
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+static void ipcfg_dump_ipv6addr(FAR const char *variable,
+                                FAR const struct in6_addr *address)
+{
+  int ret;
+
+  ret = ipcfg_check_ipv6addr(address);
+  if (ret == OK)
+    {
+      char converted[INET6_ADDRSTRLEN];
+
+      /* Convert the address to ASCII text */
+
+      if (inet_ntop(AF_INET6, address, converted, INET6_ADDRSTRLEN) == NULL)
+        {
+          ret = -errno;
+          fprintf(stderr, "ERROR: inet_ntop() failed: %d\n", ret);
+        }
+      else
+        {
+          printf("%s%s\n", variable, converted);
+        }
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_dump_ipv4config
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+static int ipcfg_dump_ipv4config(FAR const char *netdev)
 {
   struct ipv4cfg_s ipv4cfg;
   int ret;
@@ -103,35 +357,112 @@ static int ipcfg_dump_config(FAR const char *netdev)
 
   /* Dump the content in human readable form */
 
-  printf("%s:\n", netdev);
-
   if (ipv4cfg.proto > IPv4PROTO_MAX)
     {
-      printf("BOOTPROTO: %d [INVALID]\n", ipv4cfg.proto);
+      printf("\n  IPv4BOOTPROTO:  %d [INVALID]\n", ipv4cfg.proto);
+      return -EINVAL;
     }
   else
     {
-      printf("BOOTPROTO: %s\n", g_ipv4proto_name[ipv4cfg.proto]);
+      printf("\n  IPv4BOOTPROTO:  %s\n", g_ipv4proto_name[ipv4cfg.proto]);
     }
 
-  ipcfg_dump_addr("IPADDR:     ",  ipv4cfg.ipaddr);
-  ipcfg_dump_addr("NETMASK:    ",  ipv4cfg.netmask);
-  ipcfg_dump_addr("ROUTER:     ",  ipv4cfg.router);
-  ipcfg_dump_addr("DNS:        ",  ipv4cfg.dnsaddr);
+  if (ipv4cfg.proto == IPv4PROTO_STATIC ||
+      ipv4cfg.proto == IPv4PROTO_FALLBACK)
+    {
+      ipcfg_dump_ipv4addr("  IPv4IPADDR:     ",  ipv4cfg.ipaddr);
+      ipcfg_dump_ipv4addr("  IPv4NETMASK:    ",  ipv4cfg.netmask);
+      ipcfg_dump_ipv4addr("  IPv4ROUTER:     ",  ipv4cfg.router);
+      ipcfg_dump_ipv4addr("  IPv4DNS:        ",  ipv4cfg.dnsaddr);
+    }
 
   return OK;
 }
+#endif
 
 /****************************************************************************
- * Name: ipcfg_write_config
+ * Name: ipcfg_dump_ipv6config
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+static int ipcfg_dump_ipv6config(FAR const char *netdev)
+{
+  struct ipv6cfg_s ipv6cfg;
+  int ret;
+
+  ret = ipcfg_read(netdev, (FAR struct ipcfg_s *)&ipv6cfg, AF_INET6);
+  if (ret < 0)
+    {
+      fprintf(stderr, "ERROR: ipcfg_read() failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Dump the content in human readable form */
+
+  if (ipv6cfg.proto > IPv6PROTO_MAX)
+    {
+      printf("\n  IPv6BOOTPROTO:  %d [INVALID]\n", ipv6cfg.proto);
+      return -EINVAL;
+    }
+  else
+    {
+      printf("\n  IPv6BOOTPROTO:  %s\n", g_ipv6proto_name[ipv6cfg.proto]);
+    }
+
+  if (ipv6cfg.proto == IPv6PROTO_STATIC ||
+      ipv6cfg.proto == IPv6PROTO_FALLBACK)
+    {
+      ipcfg_dump_ipv6addr("  IPv6IPADDR:     ", &ipv6cfg.ipaddr);
+      ipcfg_dump_ipv6addr("  IPv6NETMASK:    ", &ipv6cfg.netmask);
+      ipcfg_dump_ipv6addr("  IPv6ROUTER:     ", &ipv6cfg.router);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_dump_config
+ ****************************************************************************/
+
+static int ipcfg_dump_config(FAR const char *netdev)
+{
+  int ret;
+
+  printf("\n%s:\n", netdev);
+
+#ifdef CONFIG_NET_IPv4
+  ret = ipcfg_dump_ipv4config(netdev);
+  if (ret < 0)
+    {
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_NET_IPv6
+  ret = ipcfg_dump_ipv6config(netdev);
+  if (ret < 0)
+    {
+      return ret;
+    }
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ipcfg_write_ipv4
  ****************************************************************************/
 
-static int ipcfg_write_config(FAR const char *netdev)
+#ifdef CONFIG_NET_IPv4
+static int ipcfg_write_ipv4(FAR const char *netdev)
 {
   struct ipv4cfg_s ipv4cfg;
   int ret;
 
-  ipv4cfg.proto   = IPv4PROTO_DHCP;
+  memset(&ipv4cfg, 0, sizeof(struct ipv4cfg_s));
+
+  ipv4cfg.proto   = IPv4PROTO_FALLBACK;
   ipv4cfg.ipaddr  = HTONL(0x0a000002);
   ipv4cfg.netmask = HTONL(0xffffff00);
   ipv4cfg.router  = HTONL(0x0a000001);
@@ -145,6 +476,73 @@ static int ipcfg_write_config(FAR const char *netdev)
 
   return ret;
 }
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_ipv6
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+static int ipcfg_write_ipv6(FAR const char *netdev)
+{
+  struct ipv6cfg_s ipv6cfg;
+  int ret;
+
+  memset(&ipv6cfg, 0, sizeof(struct ipv6cfg_s));
+
+  ipv6cfg.proto = IPv6PROTO_FALLBACK;
+
+  memcpy(ipv6cfg.ipaddr.s6_addr16, g_ipv6_ipaddr,
+         sizeof(struct in6_addr));
+  memcpy(ipv6cfg.netmask.s6_addr16, g_ipv6_netmask,
+         sizeof(struct in6_addr));
+  memcpy(ipv6cfg.router.s6_addr16, g_ipv6_router,
+         sizeof(struct in6_addr));
+
+  ret = ipcfg_write(netdev, (FAR struct ipcfg_s *)&ipv6cfg, AF_INET6);
+  if (ret < 0)
+    {
+      fprintf(stderr, "ERROR: ipcfg_write() ipcfg_write: %d\n", ret);
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_config
+ ****************************************************************************/
+
+static int ipcfg_write_config(FAR const char *netdev, FAR const char *path)
+{
+  int ret;
+
+  /* Write IPv6 first which might cause re-organization of file */
+
+#ifdef CONFIG_NET_IPv6
+  ret = ipcfg_write_ipv6(netdev);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  printf("\n  %s after IPv6 Update:\n", path);
+  ipcfg_dump_file(path);
+#endif
+
+#ifdef CONFIG_NET_IPv4
+  ret = ipcfg_write_ipv4(netdev);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  printf("\n  %s after IPv4 Update:\n", path);
+  ipcfg_dump_file(path);
+#endif
+
+  return OK;
+}
 
 /****************************************************************************
  * Public Functions
@@ -166,14 +564,14 @@ int main(int argc, FAR char *argv[])
   if (ret < 0)
     {
       int errcode = errno;
-      fprintf(stderr, "ERROR: Failed to open " CONFIG_IPCFG_PATH "\n: %d",
+      fprintf(stderr, "ERROR: Failed to mount " CONFIG_IPCFG_PATH "\n: %d",
               errcode);
       return EXIT_FAILURE;
     }
 
   /* Dump files.  These should all fail. */
 
-  printf("\n1. Dump before creating configuration files\n\n");
+  printf("\n1. Dump before creating configuration files\n");
   ipcfg_dump_config(DEVICE1);
   ipcfg_dump_config(DEVICE2);
 
@@ -181,12 +579,12 @@ int main(int argc, FAR char *argv[])
   /* Create files */
 
   printf("\n2. Create configuration files\n\n");
-  ipcfg_write_config(DEVICE1);
-  ipcfg_write_config(DEVICE2);
+  ipcfg_write_config(DEVICE1, PATH1);
+  ipcfg_write_config(DEVICE2, PATH2);
 
   /* Dump the files again */
 
-  printf("\n3. Dump after creating configuration files\n\n");
+  printf("\n3. Dump after creating configuration files\n");
   ipcfg_dump_config(DEVICE1);
   ipcfg_dump_config(DEVICE2);
 #endif
diff --git a/fsutils/ipcfg/Kconfig b/fsutils/ipcfg/Kconfig
index 9979f6a..77696a1 100644
--- a/fsutils/ipcfg/Kconfig
+++ b/fsutils/ipcfg/Kconfig
@@ -4,41 +4,38 @@
 #
 
 config FSUTILS_IPCFG
-	bool "IPv4 Configuration File Support"
+	bool "IP Configuration File Support"
 	default n
-	depends on NET_IPv4
+	depends on NET_IPv4 || NET_IPv6
 	---help---
-		Enables support for an IPv4 configuration file that holds IP
+		Enables support for an IP 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"
+	bool "Writable IP 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
+		Can be used to disable writing to the IP Configuration file.  This
+		would be necessary if, for example, the IP Configuration file were
 		provided on a read-only file system.
 
 config IPCFG_BINARY
-	bool "Binary IPv4 Configuration File"
+	bool "Binary IP Configuration File"
 	default n
 	---help---
-		By default, the IPv4 configuration file is an ASCII human readable
+		By default, the IP 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"
+	string "IP 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
+		the IP 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
@@ -62,10 +59,10 @@ config IPCFG_OFFSET
 	default 0
 	depends on IPCFG_CHARDEV
 	---help---
-		Seek to this offset before reading or writing the IPv4 Configuration.
+		Seek to this offset before reading or writing the IP 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
+		configurations can be maintained at differnt offsets into the IP
 		Configuration File.
 
 endif # FSUTILS_IPCFG
diff --git a/fsutils/ipcfg/Makefile b/fsutils/ipcfg/Makefile
index de6dcb2..7b63d6e 100644
--- a/fsutils/ipcfg/Makefile
+++ b/fsutils/ipcfg/Makefile
@@ -20,10 +20,15 @@
 
 include $(APPDIR)/Make.defs
 
-# IPv4 Configuration file access library
+# IP Configuration file access library
 
 ifeq ($(CONFIG_FSUTILS_IPCFG),y)
 CSRCS += ipcfg.c
+ifeq ($(CONFIG_IPCFG_BINARY),y)
+CSRCS += ipcfg_binary.c
+else
+CSRCS += ipcfg_text.c
+endif
 endif
 
 include $(APPDIR)/Application.mk
diff --git a/fsutils/ipcfg/ipcfg.c b/fsutils/ipcfg/ipcfg.c
index 34e62e3..d1f00b3 100644
--- a/fsutils/ipcfg/ipcfg.c
+++ b/fsutils/ipcfg/ipcfg.c
@@ -26,49 +26,10 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
+#include <debug.h>
 
 #include "fsutils/ipcfg.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#define MAX_LINESIZE  80
-#define MAX_IPv4PROTO IPv4PROTO_FALLBACK
-
-/* Values for the record type field */
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* IP Configuration record header. */
-
-struct ipcfg_header_s
-{
-  uint8_t next;         /* Offset to the next IP configuration record */
-  sa_family_t type;     /* Must be AF_INET */
-};
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-#if defined(CONFIG_IPCFG_WRITABLE) && !defined(CONFIG_IPCFG_BINARY)
-static const char *g_ipv4proto_name[] =
-{
-  "none",      /* IPv4PROTO_NONE */
-  "static",    /* IPv4PROTO_STATIC */
-  "dhcp",      /* IPv4PROTO_DHCP */
-  "fallback"   /* IPv4PROTO_FALLBACK */
-};
-#endif
+#include "ipcfg.h"
 
 /****************************************************************************
  * Private Functions
@@ -107,8 +68,7 @@ static inline FAR char *ipcfg_allocpath(FAR const char *netdev)
     {
       /* Assume that asprintf failed to allocate memory */
 
-      fprintf(stderr, "ERROR: Failed to create path to ipcfg file: %d\n",
-              ret);
+      ferr("ERROR: Failed to create path to ipcfg file: %d\n", ret);
       return NULL;
     }
 
@@ -127,201 +87,6 @@ static inline FAR char *ipcfg_allocpath(FAR const char *netdev)
 }
 
 /****************************************************************************
- * 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);
-  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;
-      close(fd);
-      fprintf(stderr, "ERROR: Failed to seek to $ld: %d\n",
-              (long)CONFIG_IPCFG_OFFSET, ret);
-      goto errout_with_path;
-    }
-
-#endif
-  ret = fd;
-
-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
  ****************************************************************************/
 
@@ -349,182 +114,84 @@ static void ipcfg_putaddr(FAR FILE *stream, FAR const char *variable,
 int ipcfg_read(FAR const char *netdev, FAR void *ipcfg, sa_family_t af)
 {
 #ifdef CONFIG_IPCFG_BINARY
-  FAR struct ipv4cfg_s *ipv4cfg = (FAR struct ipv4cfg_s *)ipcfg;
-  struct ipcfg_header_s hdr;
-  ssize_t nread;
-  int fd;
+  FAR char *path;
   int ret;
 
-  DEBUGASSERT(netdev != NULL && ipv4cfg != NULL && af == AF_INET);
-
-  /* Open the file */
-
-  fd = ipcfg_open(netdev, O_RDONLY, 0666);
-  if (fd < 0)
-    {
-      return fd;
-    }
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
 
-  /* Read the header */
+  /* Create the full path to the ipcfg file for the network device */
 
-  nread = read(fd, &hdr, sizeof(struct ipcfg_header_s));
-  if (nread < 0)
-    {
-      ret = -errno;
-      fprintf(stderr, "ERROR: Failed to read file: %d\n", ret);
-      goto errout_with_fd;
-    }
-  else if (nread != sizeof(struct ipcfg_header_s))
+  path = ipcfg_allocpath(netdev);
+  if (path == NULL)
     {
-      ret = -EIO;
-      fprintf(stderr, "ERROR: Bad read size: %ld\n", (long)nread);
-      goto errout_with_fd;
-    }
-
-  /* Verify the header.  Only a single IPv4 header is anticipated */
+      /* Assume failure to allocate memory */
 
-  if (hdr.next != 0 || hdr.type != AF_INET)
-    {
-      ret = -EINVAL;
-      fprintf(stderr, "ERROR: Bad header: {%u,%u}\n",
-              hdr.next, hdr.type);
-      goto errout_with_fd;
+      ferr("ERROR: Failed to create path to ipcfg file\n");
+      return -ENOMEM;
     }
 
-  /* Read the file content */
-
-  nread = read(fd, ipv4cfg, sizeof(struct ipv4cfg_s));
-  if (nread < 0)
+#ifdef CONFIG_NET_IPv4
+  if (af == AF_INET)
     {
-      ret = -errno;
-      fprintf(stderr, "ERROR: Failed to read file: %d\n", ret);
+      ret = ipcfg_read_binary_ipv4(path, (FAR struct ipv4cfg_s *)ipcfg);
     }
-  else if (nread != sizeof(struct ipv4cfg_s))
+  else
+#endif
+#ifdef CONFIG_NET_IPv6
+  if (af == AF_INET6)
     {
-      ret = -EIO;
-      fprintf(stderr, "ERROR: Bad read size: %ld\n", (long)nread);
+      ret = ipcfg_read_binary_ipv6(path, (FAR struct ipv6cfg_s *)ipcfg);
     }
   else
+#endif
     {
-      ret = OK;
+      ferr("ERROR: Unsupported address family: %d\n", af);
+      ret = -EAFNOSUPPORT;
     }
 
-errout_with_fd:
-  close(fd);
+  free(path);
   return ret;
 
 #else
-  FAR struct ipv4cfg_s *ipv4cfg = (FAR struct ipv4cfg_s *)ipcfg;
-  FAR FILE *stream;
-  char line[MAX_LINESIZE];
-  int index;
+  FAR char *path;
   int ret;
 
-  DEBUGASSERT(netdev != NULL && ipv4cfg != NULL && af == AF_INET);
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
 
-  /* Open the file */
+  /* Create the full path to the ipcfg file for the network device */
 
-  ret = ipcfg_open(netdev, &stream, "r");
-  if (ret < 0)
+  path = ipcfg_allocpath(netdev);
+  if (path == NULL)
     {
-      return ret;
-    }
-
-  /* Process each line in the file */
+      /* Assume failure to allocate memory */
 
-  memset(ipv4cfg, 0, sizeof(FAR struct ipv4cfg_s));
+      ferr("ERROR: Failed to create path to ipcfg file\n");
+      return -ENOMEM;
+    }
 
-  while (fgets(line, MAX_LINESIZE, stream) != NULL)
+#ifdef CONFIG_NET_IPv4
+  if (af == AF_INET)
     {
-      /* 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, "IPv4PROTO") == 0)
-            {
-              if (strcmp(value, "none") == 0)
-                {
-                  ipv4cfg->proto = IPv4PROTO_NONE;
-                }
-              else if (strcmp(value, "static") == 0)
-                {
-                  ipv4cfg->proto = IPv4PROTO_STATIC;
-                }
-              else if (strcmp(value, "dhcp") == 0)
-                {
-                  ipv4cfg->proto = IPv4PROTO_DHCP;
-                }
-              else if (strcmp(value, "fallback") == 0)
-                {
-                  ipv4cfg->proto = IPv4PROTO_FALLBACK;
-                }
-              else
-                {
-                  fprintf(stderr, "ERROR: Unrecognized IPv4PROTO: %s=%s\n",
-                          variable, value);
-                }
-            }
-          else if (strcmp(variable, "IPv4IPADDR") == 0)
-            {
-              ipv4cfg->ipaddr = inet_addr(value);
-            }
-          else if (strcmp(variable, "IPv4NETMASK") == 0)
-            {
-              ipv4cfg->netmask = inet_addr(value);
-            }
-          else if (strcmp(variable, "IPv4ROUTER") == 0)
-            {
-              ipv4cfg->router = inet_addr(value);
-            }
-          else if (strcmp(variable, "IPv4DNS") == 0)
-            {
-              ipv4cfg->dnsaddr = inet_addr(value);
-            }
-          else
-            {
-              fprintf(stderr, "ERROR: Unrecognized variable: %s=%s\n",
-                     variable, value);
-            }
-        }
+      ret = ipcfg_read_text_ipv4(path, netdev,
+                                 (FAR struct ipv4cfg_s *)ipcfg);
+    }
+  else
+#endif
+#ifdef CONFIG_NET_IPv6
+  if (af == AF_INET6)
+    {
+      ret = ipcfg_read_text_ipv6(path, netdev,
+                                 (FAR struct ipv6cfg_s *)ipcfg);
+    }
+  else
+#endif
+    {
+      ferr("ERROR: Unsupported address family: %d\n", af);
+      ret = -EAFNOSUPPORT;
     }
 
-  /* Close the file and return */
-
-  fclose(stream);
-  return OK;
+  free(path);
+  return ret;
 #endif
 }
 
@@ -552,99 +219,86 @@ int ipcfg_write(FAR const char *netdev, FAR const void *ipcfg,
                 sa_family_t af)
 {
 #ifdef CONFIG_IPCFG_BINARY
-  FAR struct ipv4cfg_s *ipv4cfg = (FAR struct ipv4cfg_s *)ipcfg;
-  struct ipcfg_header_s hdr;
-  ssize_t nwritten;
-  int fd;
+  FAR char *path;
   int ret;
 
-  DEBUGASSERT(netdev != NULL && ipv4cfg != NULL && af == AF_INET);
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
 
-  /* Open the file */
+  /* Create the full path to the ipcfg file for the network device */
 
-  fd = ipcfg_open(netdev, O_WRONLY | O_TRUNC | O_CREAT, 0666);
-  if (fd < 0)
+  path = ipcfg_allocpath(netdev);
+  if (path == NULL)
     {
-      return fd;
-    }
-
-  /* Write the file header */
-
-  hdr.next = 0;
-  hdr.type = AF_INET;
+      /* Assume failure to allocate memory */
 
-  nwritten = write(fd, &hdr, sizeof(struct ipcfg_header_s));
-  if (nwritten < 0)
-    {
-      ret = -errno;
-      fprintf(stderr, "ERROR: Failed to write to file: %d\n", ret);
-      goto errout_with_fd;
-    }
-  else if (nwritten != sizeof(struct ipcfg_header_s))
-    {
-      ret = -EIO;
-      fprintf(stderr, "ERROR: Bad write size: %ld\n", (long)nwritten);
-      goto errout_with_fd;
+      ferr("ERROR: Failed to create path to ipcfg file\n");
+      return -ENOMEM;
     }
 
-  /* Write the file content */
-
-  nwritten = write(fd, ipv4cfg, sizeof(struct ipv4cfg_s));
-  if (nwritten < 0)
+#ifdef CONFIG_NET_IPv4
+  if (af == AF_INET)
     {
-      ret = -errno;
-      fprintf(stderr, "ERROR: Failed to write file: %d\n", ret);
+      ret = ipcfg_write_binary_ipv4(path,
+                                    (FAR const struct ipv4cfg_s *)ipcfg);
     }
-  else if (nwritten != sizeof(struct ipv4cfg_s))
+  else
+#endif
+#ifdef CONFIG_NET_IPv6
+  if (af == AF_INET6)
     {
-      ret = -EIO;
-      fprintf(stderr, "ERROR: Bad write size: %ld\n", (long)nwritten);
+      ret = ipcfg_write_binary_ipv6(path,
+                                    (FAR const struct ipv6cfg_s *)ipcfg);
     }
   else
+#endif
     {
-      ret = OK;
+      ferr("ERROR: Unsupported address family: %d\n", af);
+      ret = -EAFNOSUPPORT;
     }
 
-errout_with_fd:
-  close(fd);
+  free(path);
   return ret;
 
 #else
-  FAR struct ipv4cfg_s *ipv4cfg = (FAR struct ipv4cfg_s *)ipcfg;
-  FAR FILE *stream;
+  FAR char *path;
   int ret;
 
-  DEBUGASSERT(netdev != NULL && ipv4cfg != NULL && af == AF_INET);
+  DEBUGASSERT(netdev != NULL && ipcfg != NULL);
 
-  /* Open the file */
+  /* Create the full path to the ipcfg file for the network device */
 
-  ret = ipcfg_open(netdev, &stream, "w");
-  if (ret < 0)
+  path = ipcfg_allocpath(netdev);
+  if (path == NULL)
     {
-      return ret;
-    }
+      /* Assume failure to allocate memory */
 
-  /* Format and write the file */
+      ferr("ERROR: Failed to create path to ipcfg file\n");
+      return -ENOMEM;
+    }
 
-  if ((unsigned)ipv4cfg->proto > MAX_IPv4PROTO)
+#ifdef CONFIG_NET_IPv4
+  if (af == AF_INET)
     {
-      fprintf(stderr, "ERROR: Unrecognized IPv4PROTO value: %d\n",
-              ipv4cfg->proto);
-      return -EINVAL;
+      ret = ipcfg_write_text_ipv4(path, netdev,
+                                  (FAR const struct ipv4cfg_s *)ipcfg);
+    }
+  else
+#endif
+#ifdef CONFIG_NET_IPv6
+  if (af == AF_INET6)
+    {
+      ret = ipcfg_write_text_ipv6(path, netdev,
+                                  (FAR const struct ipv6cfg_s *)ipcfg);
+    }
+  else
+#endif
+    {
+      ferr("ERROR: Unsupported address family: %d\n", af);
+      ret = -EAFNOSUPPORT;
     }
 
-  fprintf(stream, "DEVICE=%s\n", netdev);
-  fprintf(stream, "IPv4PROTO=%s\n", g_ipv4proto_name[ipv4cfg->proto]);
-
-  ipcfg_putaddr(stream, "IPv4IPADDR",  ipv4cfg->ipaddr);
-  ipcfg_putaddr(stream, "IPv4NETMASK", ipv4cfg->netmask);
-  ipcfg_putaddr(stream, "IPv4ROUTER",  ipv4cfg->router);
-  ipcfg_putaddr(stream, "IPv4DNS",     ipv4cfg->dnsaddr);
-
-  /* Close the file and return */
-
-  fclose(stream);
-  return OK;
+  free(path);
+  return ret;
 #endif
 }
 #endif
diff --git a/fsutils/ipcfg/ipcfg.h b/fsutils/ipcfg/ipcfg.h
new file mode 100644
index 0000000..a2c1a63
--- /dev/null
+++ b/fsutils/ipcfg/ipcfg.h
@@ -0,0 +1,238 @@
+/****************************************************************************
+ * apps/fsutils/ipcfg/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_FSUTILS_IPCFG_IPCFG_H
+#define __APPS_FSUTILS_IPCFG_IPCFG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include <netinet/in.h>
+
+#include "fsutils/ipcfg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX_LINESIZE  80
+#define MAX_IPv4PROTO IPv4PROTO_FALLBACK
+#define MAX_IPv6PROTO IPv6PROTO_FALLBACK
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* IP Configuration record header. */
+
+struct ipcfg_header_s
+{
+  uint8_t next;         /* Offset to the next IP configuration record */
+  sa_family_t type;     /* Either AF_INET or AF_INET6 */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_read_binary_ipv4
+ *
+ * Description:
+ *   Read IPv4 configuration from a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv4cfg - Location to read IPv4 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_BINARY) && defined(CONFIG_NET_IPv4)
+int ipcfg_read_binary_ipv4(FAR const char *path,
+                           FAR struct ipv4cfg_s *ipv4cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_read_binary_ipv6
+ *
+ * Description:
+ *   Read IPv6 configuration from a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv6cfg - Location to read IPv6 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_BINARY) && defined(CONFIG_NET_IPv6)
+int ipcfg_read_binary_ipv6(FAR const char *path,
+                           FAR struct ipv6cfg_s *ipv6cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_binary_ipv4
+ *
+ * Description:
+ *   Write the IPv4 configuration to a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv4cfg - The IPv4 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_IPCFG_BINARY) && \
+    defined(CONFIG_NET_IPv4)
+int ipcfg_write_binary_ipv4(FAR const char *path,
+                            FAR const struct ipv4cfg_s *ipv4cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_binary_ipv6
+ *
+ * Description:
+ *   Write the IPv6 configuration to a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv6cfg - The IPv6 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_IPCFG_BINARY) && \
+    defined(CONFIG_NET_IPv6)
+int ipcfg_write_binary_ipv6(FAR const char *path,
+                            FAR const struct ipv6cfg_s *ipv6cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_read_text_ipv4
+ *
+ * Description:
+ *   Read IPv4 configuration from a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv4cfg - Location to read IPv4 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+int ipcfg_read_text_ipv4(FAR const char *path, FAR const char *netdev,
+                         FAR struct ipv4cfg_s *ipv4cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_read_text_ipv6
+ *
+ * Description:
+ *   Read IPv6 configuration from a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv6cfg - Location to read IPv6 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int ipcfg_read_text_ipv6(FAR const char *path, FAR const char *netdev,
+                         FAR struct ipv6cfg_s *ipv6cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_text_ipv4
+ *
+ * Description:
+ *   Write the IPv4 configuration to a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv4cfg - The IPv4 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
+int ipcfg_write_text_ipv4(FAR const char *path, FAR const char *netdev,
+                          FAR const struct ipv4cfg_s *ipv4cfg);
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_text_ipv6
+ *
+ * Description:
+ *   Write the IPv6 configuration to a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv6cfg - The IPv6 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
+int ipcfg_write_text_ipv6(FAR const char *path, FAR const char *netdev,
+                          FAR const struct ipv6cfg_s *ipv6cfg);
+#endif
+
+#endif /* __APPS_FSUTILS_IPCFG_IPCFG_H */
diff --git a/fsutils/ipcfg/ipcfg_binary.c b/fsutils/ipcfg/ipcfg_binary.c
new file mode 100644
index 0000000..9af3386
--- /dev/null
+++ b/fsutils/ipcfg/ipcfg_binary.c
@@ -0,0 +1,568 @@
+/****************************************************************************
+ * apps/fsutils/ipcfg/ipcfg_binary.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 <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <debug.h>
+
+#include "fsutils/ipcfg.h"
+#include "ipcfg.h"
+
+#ifdef CONFIG_IPCFG_BINARY
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_open (for binary mode)
+ *
+ * Description:
+ *   Form the complete path to the ipcfg file and open it.
+ *
+ * Input Parameters:
+ *   path   - The full path to the IP configuration file
+ *   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 *path, int oflags, mode_t mode)
+{
+  int fd;
+  int ret;
+
+  /* Now open the file */
+
+  fd  = open(path, oflags, mode);
+  if (fd < 0)
+    {
+      ret = -errno;
+      if (ret != -ENOENT)
+        {
+          ferr("ERROR: Failed to open %s: %d\n", path, ret);
+        }
+
+      return ret;
+    }
+
+#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;
+      ferr("ERROR: Failed to seek to $ld: %d\n",
+           (long)CONFIG_IPCFG_OFFSET, ret);
+
+      close(fd);
+      return ret;
+    }
+
+#endif
+
+  return fd;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_read_binary
+ *
+ * Description:
+ *   Read from a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   fd     - File descriptor of the open file to read from
+ *   buffer - Location to read from
+ *   nbytes - Number of bytes to read
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ipcfg_read_binary(int fd, FAR void *buffer, size_t nbytes)
+{
+  ssize_t nread;
+  int ret;
+
+  /* Read from the file */
+
+  nread = read(fd, buffer, nbytes);
+  if (nread < 0)
+    {
+      ret = -errno;
+      ferr("ERROR: Failed to read from file: %d\n", ret);
+    }
+  else if (nread != nbytes)
+    {
+      ret = -EIO;
+      ferr("ERROR: Bad read size: %ld\n", (long)nread);
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ipcfg_write_binary
+ *
+ * Description:
+ *   Write to a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   fd     - File descriptor of the open file to write to
+ *   buffer - Location to write to
+ *   nbytes - Number of bytes to wrtie
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IPCFG_WRITABLE
+static int ipcfg_write_binary(int fd, FAR const void *buffer, size_t nbytes)
+{
+  ssize_t nwritten;
+  int ret;
+
+  /* Read from the file */
+
+  nwritten = write(fd, buffer, nbytes);
+  if (nwritten < 0)
+    {
+      ret = -errno;
+      ferr("ERROR: Failed to write to file: %d\n", ret);
+    }
+  else if (nwritten != nbytes)
+    {
+      ret = -EIO;
+      ferr("ERROR: Bad write size: %ld\n", (long)nwritten);
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_find_binary
+ *
+ * Description:
+ *   Read the location of IPv4 data in a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   fd     - File descriptor of the open file to read from
+ *   af     - Identifies the address family whose IP configuration is
+ *            requested.  May be either AF_INET or AF_INET6.
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ipcfg_find_binary(int fd, sa_family_t af)
+{
+  struct ipcfg_header_s hdr;
+  off_t pos;
+  int ret;
+
+  for (; ; )
+    {
+      /* Read the header (careful.. could be uninitialized in the case of a
+       * character driver).
+       */
+
+      ret = ipcfg_read_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
+      if (ret < 0)
+        {
+          /* Return on any read error */
+
+          return (int)ret;
+        }
+      else if (hdr.type == af)
+        {
+          return OK;
+        }
+      else if (hdr.type != AF_INET && hdr.type != AF_INET6)
+        {
+          return -EINVAL;
+        }
+      else if (hdr.next == 0)
+        {
+          ferr("ERROR: IP configuration not found\n");
+          return -ENOENT;
+        }
+
+      /* Skip to the next IP configuration record */
+
+      pos = lseek(fd, hdr.next, SEEK_CUR);
+      if (pos < 0)
+        {
+          ret = -errno;
+          ferr("ERROR: lseek failed: %d\n", ret);
+          return ret;
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_read_binary_ipv4
+ *
+ * Description:
+ *   Read IPv4 configuration from a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv4cfg - Location to read IPv4 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+int ipcfg_read_binary_ipv4(FAR const char *path,
+                           FAR struct ipv4cfg_s *ipv4cfg)
+{
+  int fd;
+  int ret;
+
+  DEBUGASSERT(path != NULL && ipv4cfg != NULL);
+
+  /* Open the file for reading */
+
+  fd = ipcfg_open(path, O_RDONLY, 0666);
+  if (fd < 0)
+    {
+      return fd;
+    }
+
+  /* Find the IPv4 binary in the IP configuration file */
+
+  ret = ipcfg_find_binary(fd, AF_INET);
+  if (ret < 0)
+    {
+      goto errout_with_fd;
+    }
+
+  /* Read the IPv4 Configuration */
+
+  ret = ipcfg_read_binary(fd, ipv4cfg, sizeof(struct ipv4cfg_s));
+
+errout_with_fd:
+  close(fd);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_read_binary_ipv6
+ *
+ * Description:
+ *   Read IPv6 configuration from a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv6cfg - Location to read IPv6 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int ipcfg_read_binary_ipv6(FAR const char *path,
+                           FAR struct ipv6cfg_s *ipv6cfg)
+{
+  int fd;
+  int ret;
+
+  DEBUGASSERT(fd >= 0 && ipv6cfg != NULL);
+
+  /* Open the file for reading */
+
+  fd = ipcfg_open(path, O_RDONLY, 0666);
+  if (fd < 0)
+    {
+      return fd;
+    }
+
+  /* Find the IPv6 binary in the IP configuration file */
+
+  ret = ipcfg_find_binary(fd, AF_INET6);
+  if (ret < 0)
+    {
+      goto errout_with_fd;
+    }
+
+  /* Read the IPv6 Configuration */
+
+  ret = ipcfg_read_binary(fd, ipv6cfg, sizeof(struct ipv6cfg_s));
+
+errout_with_fd:
+  close(fd);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_binary_ipv4
+ *
+ * Description:
+ *   Write the IPv4 configuration to a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv4cfg - The IPv4 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
+int ipcfg_write_binary_ipv4(FAR const char *path,
+                            FAR const struct ipv4cfg_s *ipv4cfg)
+{
+#ifdef CONFIG_NET_IPv6
+  struct ipv6cfg_s ipv6cfg;
+#endif
+  struct ipcfg_header_s hdr;
+  bool ipv6 = false;
+  int fd;
+  int ret;
+
+  DEBUGASSERT(fd >= 0 && ipv4cfg != NULL);
+
+#ifdef CONFIG_NET_IPv6
+  /* Read any IPv6 data in the file */
+
+  ret = ipcfg_read_binary_ipv6(path, &ipv6cfg);
+  if (ret < 0)
+    {
+      /* -ENOENT is not an error.  It simply means that there is no IPv6
+       * configuration in the file.
+       */
+
+      if (ret != -ENOENT)
+        {
+          return ret;
+        }
+    }
+  else
+    {
+      ipv6 = true;
+    }
+#endif
+
+  /* Open the file for writing (truncates) */
+
+  fd = ipcfg_open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+  if (fd < 0)
+    {
+      return fd;
+    }
+
+  /* Write the IPv4 file header */
+
+  hdr.next = ipv6 ? sizeof(struct ipv4cfg_s) : 0;
+  hdr.type = AF_INET;
+
+  ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
+  if (ret < 0)
+    {
+      goto errout_with_fd;
+    }
+
+  /* Write the IPv4 configuration */
+
+  ret = ipcfg_write_binary(fd, ipv4cfg, sizeof(struct ipv4cfg_s));
+  if (ret < 0)
+    {
+      goto errout_with_fd;
+    }
+
+#ifdef CONFIG_NET_IPv6
+  /* Followed by any IPv6 data in the file */
+
+  if (ipv6)
+    {
+      /* Write the IPv6 header */
+
+      hdr.next = 0;
+      hdr.type = AF_INET6;
+
+      ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
+      if (ret >= 0)
+        {
+          /* Write the IPv6 configuration */
+
+          ret = ipcfg_write_binary(fd, &ipv6cfg, sizeof(struct ipv6cfg_s));
+        }
+    }
+#endif
+
+errout_with_fd:
+  close(fd);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_binary_ipv6
+ *
+ * Description:
+ *   Write the IPv6 configuration to a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   ipv6cfg - The IPv6 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
+int ipcfg_write_binary_ipv6(FAR const char *path,
+                            FAR const struct ipv6cfg_s *ipv6cfg)
+{
+#ifdef CONFIG_NET_IPv4
+  struct ipv4cfg_s ipv4cfg;
+  bool ipv4 = false;
+#endif
+  struct ipcfg_header_s hdr;
+  int fd;
+  int ret;
+
+  DEBUGASSERT(path != NULL && ipv6cfg != NULL);
+
+#ifdef CONFIG_NET_IPv4
+  /* Read any IPv4 data in the file */
+
+  ret = ipcfg_read_binary_ipv4(path, &ipv4cfg);
+  if (ret < 0)
+    {
+      /* -ENOENT is not an error.  It simply means that there is no IPv4
+       * configuration in the file.
+       */
+
+      if (ret != -ENOENT)
+        {
+          return ret;
+        }
+    }
+  else
+    {
+      ipv4 = true;
+    }
+#endif
+
+  /* Open the file for writing (truncates) */
+
+  fd = ipcfg_open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+  if (fd < 0)
+    {
+      return fd;
+    }
+
+#ifdef CONFIG_NET_IPv4
+  if (ipv4)
+    {
+      /* Write the IPv4 header */
+
+      hdr.next = sizeof(struct ipv4cfg_s);
+      hdr.type = AF_INET;
+
+      ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
+      if (ret < 0)
+        {
+          goto errout_with_fd;
+        }
+
+      /* Write the IPv4 configuration.  This is really unnecessary in most
+       * cases since the IPv4 data should already be in place.
+       */
+
+      ret = ipcfg_write_binary(fd, &ipv4cfg, sizeof(struct ipv4cfg_s));
+      if (ret < 0)
+        {
+          goto errout_with_fd;
+        }
+    }
+#endif
+
+  /* Write the IPv6 file header */
+
+  hdr.next = 0;
+  hdr.type = AF_INET6;
+
+  ret = ipcfg_write_binary(fd, &hdr, sizeof(struct ipcfg_header_s));
+  if (ret >= 0)
+    {
+      /* Write the IPv6 configuration */
+
+      ret = ipcfg_write_binary(fd, ipv6cfg, sizeof(struct ipv6cfg_s));
+    }
+
+#ifdef CONFIG_NET_IPv4
+errout_with_fd:
+#endif
+  close(fd);
+  return ret;
+}
+#endif
+
+#endif /* CONFIG_IPCFG_BINARY */
diff --git a/fsutils/ipcfg/ipcfg_text.c b/fsutils/ipcfg/ipcfg_text.c
new file mode 100644
index 0000000..ca0944e
--- /dev/null
+++ b/fsutils/ipcfg/ipcfg_text.c
@@ -0,0 +1,805 @@
+/****************************************************************************
+ * apps/fsutils/ipcfg/ipcfg_text.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 <stdbool.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <debug.h>
+
+#include <arpa/inet.h>
+
+#include "fsutils/ipcfg.h"
+#include "ipcfg.h"
+
+#ifndef CONFIG_IPCFG_BINARY
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
+static const char *g_ipv4proto_name[] =
+{
+  "none",      /* IPv4PROTO_NONE */
+  "static",    /* IPv4PROTO_STATIC */
+  "dhcp",      /* IPv4PROTO_DHCP */
+  "fallback"   /* IPv4PROTO_FALLBACK */
+};
+#endif
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
+static const char *g_ipv6proto_name[] =
+{
+  "none",      /* IPv6PROTO_NONE */
+  "static",    /* IPv6PROTO_STATIC */
+  "autoconf",  /* IPv6PROTO_AUTOCONF */
+  "fallback"   /* IPv6PROTO_FALLBACK */
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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_put_ipv4addr
+ *
+ * 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:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
+static int ipcfg_put_ipv4addr(FAR FILE *stream, FAR const char *variable,
+                              in_addr_t address)
+{
+  if (address != 0)
+    {
+      struct in_addr saddr =
+      {
+        address
+      };
+
+      char converted[INET_ADDRSTRLEN];
+
+      /* Convert the address to ASCII text */
+
+      if (inet_ntop(AF_INET, &saddr, converted, INET_ADDRSTRLEN) == NULL)
+        {
+          int ret = -errno;
+          ferr("ERROR: inet_ntop() failed: %d\n", ret);
+          return ret;
+        }
+
+      fprintf(stream, "%s=%s\n", variable, converted);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_check_ipv6addr
+ *
+ * Description:
+ *   Check for a valid IPv6 address, i.e., not all zeroes.
+ *
+ * Input Parameters:
+ *   address - A pointer to the address to check.
+ *
+ * Returned value:
+ *   Zero (OK) is returned if the address is non-zero.  -ENXIO is returned if
+ *   the address is zero.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+static int ipcfg_check_ipv6addr(FAR const struct in6_addr *address)
+{
+  int i;
+
+  for (i = 0; i < 4; i++)
+    {
+      if (address->s6_addr32[i] != 0)
+        {
+          return OK;
+        }
+    }
+
+  return -ENXIO;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_put_ipv6addr
+ *
+ * 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:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
+static int ipcfg_put_ipv6addr(FAR FILE *stream, FAR const char *variable,
+                              FAR const struct in6_addr *address)
+{
+  /* If the address is all zero, then omit it */
+
+  if (ipcfg_check_ipv6addr(address) == OK)
+    {
+      char converted[INET6_ADDRSTRLEN];
+
+      /* Convert the address to ASCII text */
+
+      if (inet_ntop(AF_INET6, address, converted, INET6_ADDRSTRLEN) == NULL)
+        {
+          int ret = -errno;
+          ferr("ERROR: inet_ntop() failed: %d\n", ret);
+          return ret;
+        }
+
+      fprintf(stream, "%s=%s\n", variable, converted);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_ipv4
+ *
+ * Description:
+ *   Write the IPv4 configuration to a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   stream  - Stream of the open file to write to
+ *   ipv4cfg - The IPv4 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
+static int ipcfg_write_ipv4(FAR FILE *stream,
+                            FAR const struct ipv4cfg_s *ipv4cfg)
+{
+  /* Format and write the file */
+
+  if ((unsigned)ipv4cfg->proto > MAX_IPv4PROTO)
+    {
+      ferr("ERROR: Unrecognized IPv4PROTO value: %d\n", ipv4cfg->proto);
+      return -EINVAL;
+    }
+
+  fprintf(stream, "IPv4PROTO=%s\n", g_ipv4proto_name[ipv4cfg->proto]);
+
+  ipcfg_put_ipv4addr(stream, "IPv4IPADDR",  ipv4cfg->ipaddr);
+  ipcfg_put_ipv4addr(stream, "IPv4NETMASK", ipv4cfg->netmask);
+  ipcfg_put_ipv4addr(stream, "IPv4ROUTER",  ipv4cfg->router);
+  ipcfg_put_ipv4addr(stream, "IPv4DNS",     ipv4cfg->dnsaddr);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_ipv6
+ *
+ * Description:
+ *   Write the IPv6 configuration to a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   stream  - Stream of the open file to write to
+ *   ipv6cfg - The IPv6 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
+static int ipcfg_write_ipv6(FAR FILE *stream,
+                            FAR const struct ipv6cfg_s *ipv6cfg)
+{
+  /* Format and write the file */
+
+  if ((unsigned)ipv6cfg->proto > MAX_IPv6PROTO)
+    {
+      ferr("ERROR: Unrecognized IPv6PROTO value: %d\n", ipv6cfg->proto);
+      return -EINVAL;
+    }
+
+  fprintf(stream, "IPv6PROTO=%s\n", g_ipv6proto_name[ipv6cfg->proto]);
+
+  ipcfg_put_ipv6addr(stream, "IPv6IPADDR",  &ipv6cfg->ipaddr);
+  ipcfg_put_ipv6addr(stream, "IPv6NETMASK", &ipv6cfg->netmask);
+  ipcfg_put_ipv6addr(stream, "IPv6ROUTER",  &ipv6cfg->router);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipcfg_read_text_ipv4
+ *
+ * Description:
+ *   Read IPv4 configuration from a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv4cfg - Location to read IPv4 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+int ipcfg_read_text_ipv4(FAR const char *path, FAR const char *netdev,
+                         FAR struct ipv4cfg_s *ipv4cfg)
+{
+  char line[MAX_LINESIZE];
+  FAR FILE *stream;
+  int index;
+  int ret = -ENOENT;
+
+  DEBUGASSERT(stream != NULL && ipv4cfg != NULL);
+
+  /* Open the file for reading */
+
+  stream = fopen(path, "r");
+  if (stream == NULL)
+    {
+      ret = -errno;
+      if (ret != -ENOENT)
+        {
+          ferr("ERROR: Failed to open %s: %d\n", path, ret);
+        }
+
+      return ret;
+    }
+
+  /* Process each line in the file */
+
+  memset(ipv4cfg, 0, sizeof(FAR struct ipv4cfg_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)
+            {
+              ferr("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)
+                {
+                  ferr("ERROR: Bad device in file: %s=%s\n",
+                       variable, value);
+                }
+            }
+          else if (strcmp(variable, "IPv4PROTO") == 0)
+            {
+              if (strcmp(value, "none") == 0)
+                {
+                  ipv4cfg->proto = IPv4PROTO_NONE;
+                }
+              else if (strcmp(value, "static") == 0)
+                {
+                  ipv4cfg->proto = IPv4PROTO_STATIC;
+                }
+              else if (strcmp(value, "dhcp") == 0)
+                {
+                  ipv4cfg->proto = IPv4PROTO_DHCP;
+                }
+              else if (strcmp(value, "fallback") == 0)
+                {
+                  ipv4cfg->proto = IPv4PROTO_FALLBACK;
+                }
+              else
+                {
+                  ferr("ERROR: Unrecognized IPv4PROTO: %s=%s\n",
+                       variable, value);
+                }
+
+              /* Assume IPv4 settings are present if the IPv4BOOTPROTO
+               * setting is encountered.
+               */
+
+              ret = OK;
+            }
+          else if (strcmp(variable, "IPv4IPADDR") == 0)
+            {
+              ipv4cfg->ipaddr = inet_addr(value);
+            }
+          else if (strcmp(variable, "IPv4NETMASK") == 0)
+            {
+              ipv4cfg->netmask = inet_addr(value);
+            }
+          else if (strcmp(variable, "IPv4ROUTER") == 0)
+            {
+              ipv4cfg->router = inet_addr(value);
+            }
+          else if (strcmp(variable, "IPv4DNS") == 0)
+            {
+              ipv4cfg->dnsaddr = inet_addr(value);
+            }
+
+          /* Anything other than some IPv6 settings would be an error.
+           * This is a sloppy check because it does not detect invalid
+           * names variables that begin with "IPv6".
+           */
+
+          else if (strncmp(variable, "IPv6", 4) != 0)
+            {
+              ferr("ERROR: Unrecognized variable: %s=%s\n", variable, value);
+            }
+        }
+    }
+
+  /* Close the file and return */
+
+  fclose(stream);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_read_text_ipv6
+ *
+ * Description:
+ *   Read IPv6 configuration from a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv6cfg - Location to read IPv6 configration to
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int ipcfg_read_text_ipv6(FAR const char *path, FAR const char *netdev,
+                         FAR struct ipv6cfg_s *ipv6cfg)
+{
+  char line[MAX_LINESIZE];
+  FAR FILE *stream;
+  bool found = false;
+  int index;
+  int ret;
+
+  DEBUGASSERT(path != NULL && netdev != NULL && ipv6cfg != NULL);
+
+  /* Open the file for reading */
+
+  stream = fopen(path, "r");
+  if (stream == NULL)
+    {
+      ret = -errno;
+      if (ret != -ENOENT)
+        {
+          ferr("ERROR: Failed to open %s: %d\n", path, ret);
+        }
+
+      return ret;
+    }
+
+  /* Process each line in the file */
+
+  memset(ipv6cfg, 0, sizeof(FAR struct ipv6cfg_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)
+            {
+              ferr("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)
+                {
+                  ferr("ERROR: Bad device in file: %s=%s\n",
+                       variable, value);
+                }
+            }
+          else if (strcmp(variable, "IPv6PROTO") == 0)
+            {
+              if (strcmp(value, "none") == 0)
+                {
+                  ipv6cfg->proto = IPv6PROTO_NONE;
+                }
+              else if (strcmp(value, "static") == 0)
+                {
+                  ipv6cfg->proto = IPv6PROTO_STATIC;
+                }
+              else if (strcmp(value, "autoconf") == 0)
+                {
+                  ipv6cfg->proto = IPv6PROTO_AUTOCONF;
+                }
+              else if (strcmp(value, "fallback") == 0)
+                {
+                  ipv6cfg->proto = IPv6PROTO_FALLBACK;
+                }
+              else
+                {
+                  ferr("ERROR: Unrecognized IPv6PROTO: %s=%s\n",
+                       variable, value);
+                }
+
+              /* Assume IPv4 settings are present if the IPv6BOOTPROTO
+               * setting is encountered.
+               */
+
+              found = true;
+            }
+          else if (strcmp(variable, "IPv6IPADDR") == 0)
+            {
+              ret = inet_pton(AF_INET6, value, &ipv6cfg->ipaddr);
+              if (ret < 0)
+                {
+                  ret = -errno;
+                  ferr("ERROR: inet_pton() failed: %d\n", ret);
+                  return ret;
+                }
+            }
+          else if (strcmp(variable, "IPv6NETMASK") == 0)
+            {
+              ret = inet_pton(AF_INET6, value, &ipv6cfg->netmask);
+              if (ret < 0)
+                {
+                  ret = -errno;
+                  ferr("ERROR: inet_pton() failed: %d\n", ret);
+                  return ret;
+                }
+            }
+          else if (strcmp(variable, "IPv6ROUTER") == 0)
+            {
+              ret = inet_pton(AF_INET6, value, &ipv6cfg->router);
+              if (ret < 0)
+                {
+                  ret = -errno;
+                  ferr("ERROR: inet_pton() failed: %d\n", ret);
+                  return ret;
+                }
+            }
+
+          /* Anything other than some IPv4 settings would be an error.
+           * This is a sloppy check because it does not detect invalid
+           * names variables that begin with "IPv4".
+           */
+
+          else if (strncmp(variable, "IPv4", 4) != 0)
+            {
+              ferr("ERROR: Unrecognized variable: %s=%s\n", variable, value);
+            }
+        }
+    }
+
+  /* Close the file and return */
+
+  fclose(stream);
+  return found ? OK : -ENOENT;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_text_ipv4
+ *
+ * Description:
+ *   Write the IPv4 configuration to a human-readable, text IP Configuration
+ *   file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv4cfg - The IPv4 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv4)
+int ipcfg_write_text_ipv4(FAR const char *path, FAR const char *netdev,
+                          FAR const struct ipv4cfg_s *ipv4cfg)
+{
+#ifdef CONFIG_NET_IPv6
+  struct ipv6cfg_s ipv6cfg;
+  bool ipv6 = false;
+#endif
+  FAR FILE *stream;
+  int ret;
+
+  DEBUGASSERT(stream != NULL && ipv4cfg != NULL);
+
+#ifdef CONFIG_NET_IPv6
+  /* Read any IPv6 data in the file */
+
+  ret = ipcfg_read_text_ipv6(path, netdev, &ipv6cfg);
+  if (ret < 0)
+    {
+      /* -ENOENT is not an error.  It simply means that there is no IPv6
+       * configuration in the file.
+       */
+
+      if (ret != -ENOENT)
+        {
+          return ret;
+        }
+    }
+  else
+    {
+      ipv6 = true;
+    }
+#endif
+
+  /* Open the file for writing (truncates) */
+
+  stream = fopen(path, "w");
+  if (stream == NULL)
+    {
+      ret = -errno;
+      ferr("ERROR: Failed to open %s: %d\n", path, ret);
+      return ret;
+    }
+
+  /* Save the device name */
+
+  fprintf(stream, "DEVICE=%s\n", netdev);
+
+  /* Write the IPv4 configuration */
+
+  ret = ipcfg_write_ipv4(stream, ipv4cfg);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+#ifdef CONFIG_NET_IPv6
+  /* Followed by any IPv6 data in the file */
+
+  if (ipv6)
+    {
+      ret = ipcfg_write_ipv6(stream, &ipv6cfg);
+    }
+#endif
+
+  fclose(stream);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipcfg_write_text_ipv6
+ *
+ * Description:
+ *   Write the IPv6 configuration to a binary IP Configuration file.
+ *
+ * Input Parameters:
+ *   path    - The full path to the IP configuration file
+ *   netdev  - Network device name string
+ *   ipv6cfg - The IPv6 configration to write
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_IPCFG_WRITABLE) && defined(CONFIG_NET_IPv6)
+int ipcfg_write_text_ipv6(FAR const char *path, FAR const char *netdev,
+                          FAR const struct ipv6cfg_s *ipv6cfg)
+{
+#ifdef CONFIG_NET_IPv4
+  struct ipv4cfg_s ipv4cfg;
+  bool ipv4 = false;
+#endif
+  FAR FILE *stream;
+  int ret;
+
+  DEBUGASSERT(netdev != NULL && ipv6cfg != NULL);
+
+#ifdef CONFIG_NET_IPv4
+  /* Read any IPv4 data in the file */
+
+  ret = ipcfg_read_text_ipv4(path, netdev, &ipv4cfg);
+  if (ret < 0)
+    {
+      /* -ENOENT is not an error.  It simply means that there is no IPv4
+       * configuration in the file.
+       */
+
+      if (ret != -ENOENT)
+        {
+          return ret;
+        }
+    }
+  else
+    {
+      ipv4 = true;
+    }
+#endif
+
+  /* Open the file for writing (truncates) */
+
+  stream = fopen(path, "w");
+  if (stream == NULL)
+    {
+      ret = -errno;
+      ferr("ERROR: Failed to open %s: %d\n", path, ret);
+      return ret;
+    }
+
+  /* Save the device name */
+
+  fprintf(stream, "DEVICE=%s\n", netdev);
+
+#ifdef CONFIG_NET_IPv4
+  if (ipv4)
+    {
+      /* Write the IPv4 configuration.  This is really unnecessary in most
+       * cases since the IPv4 data should already be in place.
+       */
+
+      ret = ipcfg_write_ipv4(stream, &ipv4cfg);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+#endif
+
+  /* Write the IPv6 configuration */
+
+  ret = ipcfg_write_ipv6(stream, ipv6cfg);
+  fclose(stream);
+  return ret;
+}
+#endif
+
+#endif /* !CONFIG_IPCFG_BINARY */
diff --git a/include/fsutils/ipcfg.h b/include/fsutils/ipcfg.h
index 63eaa2c..3b41178 100644
--- a/include/fsutils/ipcfg.h
+++ b/include/fsutils/ipcfg.h
@@ -123,10 +123,10 @@ struct ipv4cfg_s
 
 enum ipv6cfg_bootproto_e
 {
-  BOOTPROTO_NONE     = 0, /* No protocol assigned */
-  BOOTPROTO_STATIC   = 1, /* Use static IP */
-  BOOTPROTO_AUTOCONF = 2, /* Use ICMPv6 auto-configuration */
-  BOOTPROTO_FALLBACK = 3  /* Use auto-configuration with fall back static IP */
+  IPv6PROTO_NONE     = 0, /* No protocol assigned */
+  IPv6PROTO_STATIC   = 1, /* Use static IP */
+  IPv6PROTO_AUTOCONF = 2, /* Use ICMPv6 auto-configuration */
+  IPv6PROTO_FALLBACK = 3  /* Use auto-configuration with fall back static IP */
 };
 
 struct ipv6cfg_s
@@ -143,6 +143,7 @@ struct ipv6cfg_s
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
+
 #ifdef __cplusplus
 #define EXTERN extern "C"
 extern "C"