/**************************************************************************** * 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 #include #include #include #include #include #include #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 =
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 =
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(path != NULL && netdev != 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 = 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 IPv4PROTO * 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 = 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(path != NULL && netdev != 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(path != NULL && 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 */