/**************************************************************************** * 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 #include #include #include #include #include #include #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.version == IPCFG_VERSION && hdr.type == af) { return OK; } else if (hdr.version != IPCFG_VERSION || (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(path != NULL && 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(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); DEBUGASSERT(fd >= 0); if (fd < 0) { return fd; } /* Write the IPv4 file header */ hdr.next = ipv6 ? sizeof(struct ipv4cfg_s) : 0; hdr.type = AF_INET; hdr.version = IPCFG_VERSION; 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; hdr.version = IPCFG_VERSION; 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; hdr.version = IPCFG_VERSION; 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; hdr.version = IPCFG_VERSION; 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 */