| /**************************************************************************** |
| * apps/examples/ipcfg/ipcfg_main.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/mount.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <debug.h> |
| #include <unistd.h> |
| |
| #include <arpa/inet.h> |
| |
| #include "fsutils/ipcfg.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_IPCFG_CHARDEV |
| # error This example will not work with a character device |
| #endif |
| |
| #ifndef CONFIG_IPCFG_WRITABLE |
| # warning This example will not work with a without write support |
| #endif |
| |
| #define DEVICE1 "eth0" |
| #define DEVICE2 "eth1" |
| #define 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 */ |
| "static", /* IPv4PROTO_STATIC */ |
| "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_nibble |
| * |
| * Description: |
| * Convert a binary nibble to a hexadecimal character. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_IPCFG_BINARY |
| static char ipcfg_nibble(unsigned char nibble) |
| { |
| if (nibble < 10) |
| { |
| 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 |
| }; |
| |
| char inetaddr[INET_ADDRSTRLEN]; |
| |
| printf("%s%s\n", variable, |
| inet_ntoa_r(saddr, inetaddr, sizeof(inetaddr))); |
| } |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: ipcfg_check_ipv6addr |
| ****************************************************************************/ |
| |
| #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; |
| |
| ret = ipcfg_read(netdev, (FAR struct ipcfg_s *)&ipv4cfg, AF_INET); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: ipcfg_read() failed: %d\n", ret); |
| return ret; |
| } |
| |
| /* Dump the content in human readable form */ |
| |
| if (ipv4cfg.proto > IPv4PROTO_MAX) |
| { |
| printf("\n IPv4BOOTPROTO: %d [INVALID]\n", ipv4cfg.proto); |
| return -EINVAL; |
| } |
| else |
| { |
| printf("\n IPv4BOOTPROTO: %s\n", g_ipv4proto_name[ipv4cfg.proto]); |
| } |
| |
| 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_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 |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_NET_IPv4 |
| static int ipcfg_write_ipv4(FAR const char *netdev) |
| { |
| struct ipv4cfg_s ipv4cfg; |
| int ret; |
| |
| memset(&ipv4cfg, 0, sizeof(struct ipv4cfg_s)); |
| |
| ipv4cfg.proto = IPv4PROTO_FALLBACK; |
| ipv4cfg.ipaddr = HTONL(0x0a000002); |
| ipv4cfg.netmask = HTONL(0xffffff00); |
| ipv4cfg.router = HTONL(0x0a000001); |
| ipv4cfg.dnsaddr = HTONL(0x0a000003); |
| |
| ret = ipcfg_write(netdev, (FAR struct ipcfg_s *)&ipv4cfg, AF_INET); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: ipcfg_write() ipcfg_write: %d\n", ret); |
| } |
| |
| 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 |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: ipcfg_main |
| ****************************************************************************/ |
| |
| int main(int argc, FAR char *argv[]) |
| { |
| int ret; |
| |
| /* Mount the TMPFS file system at the expected location for the IPv4 |
| * Configuration file directory. |
| */ |
| |
| ret = mount(NULL, CONFIG_IPCFG_PATH, "tmpfs", 0, NULL); |
| if (ret < 0) |
| { |
| int errcode = errno; |
| fprintf(stderr, "ERROR: Failed to mount " CONFIG_IPCFG_PATH "\n: %d", |
| errcode); |
| return EXIT_FAILURE; |
| } |
| |
| /* Dump files. These should all fail. */ |
| |
| printf("\n1. Dump before creating configuration files\n"); |
| ipcfg_dump_config(DEVICE1); |
| ipcfg_dump_config(DEVICE2); |
| |
| #ifdef CONFIG_IPCFG_WRITABLE |
| /* Create files */ |
| |
| printf("\n2. Create configuration files\n\n"); |
| ipcfg_write_config(DEVICE1, PATH1); |
| ipcfg_write_config(DEVICE2, PATH2); |
| |
| /* Dump the files again */ |
| |
| printf("\n3. Dump after creating configuration files\n"); |
| ipcfg_dump_config(DEVICE1); |
| ipcfg_dump_config(DEVICE2); |
| #endif |
| |
| umount(CONFIG_IPCFG_PATH); |
| return EXIT_SUCCESS; |
| } |