595 lines
14 KiB
C
595 lines
14 KiB
C
/****************************************************************************
|
|
* 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 <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
|
|
};
|
|
|
|
printf("%s%s\n", variable, inet_ntoa(saddr));
|
|
}
|
|
}
|
|
#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;
|
|
}
|