Add DHCP support to rc.conf.

This commit is contained in:
Chris Johns
2016-06-30 09:19:52 +10:00
parent 912b685792
commit 573b198243
3 changed files with 326 additions and 74 deletions

View File

@@ -39,11 +39,16 @@
#include <sysexits.h> #include <sysexits.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <rtems.h> #include <rtems.h>
@@ -52,6 +57,8 @@
#include <machine/rtems-bsd-commands.h> #include <machine/rtems-bsd-commands.h>
#include <machine/rtems-bsd-rc-conf-services.h> #include <machine/rtems-bsd-rc-conf-services.h>
#include <rtems/rtems-routes.h>
/* /*
* Default defaultroute_delay is 30seconds. * Default defaultroute_delay is 30seconds.
*/ */
@@ -335,45 +342,6 @@ defaultrouter(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa)
return 0; return 0;
} }
/*
* defaultroute_delay
*
* eg defaultroute=120
*
* See 'man rc.conf(5)' on FreeBSD.
*/
static int
defaultroute_delay(rtems_bsd_rc_conf* rc_conf,
int argc,
const char** argv)
{
int value;
char* end = NULL;
if (argc != 2) {
errno = EINVAL;
return -1;
}
value = strtol(argv[1], &end, 10);
if (end == NULL) {
const char* args[] = {
"defaultrouter_delay", argv[1], NULL
};
rtems_bsd_rc_conf_print_cmd(rc_conf, "defaultrouter", 2, args);
defaultroute_delay_secs = value;
}
else {
errno = EINVAL;
return -1;
}
return 0;
}
static int static int
show_interfaces(const char* msg, struct ifaddrs* ifap) show_interfaces(const char* msg, struct ifaddrs* ifap)
{ {
@@ -381,6 +349,10 @@ show_interfaces(const char* msg, struct ifaddrs* ifap)
fprintf(stdout, msg); fprintf(stdout, msg);
/*
* Always have lo0 first.
*/
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcasecmp("lo0", ifa->ifa_name) == 0) { if (strcasecmp("lo0", ifa->ifa_name) == 0) {
fprintf(stdout, "%s ", ifa->ifa_name); fprintf(stdout, "%s ", ifa->ifa_name);
@@ -399,10 +371,21 @@ show_interfaces(const char* msg, struct ifaddrs* ifap)
return 0; return 0;
} }
static int
dhcp_check(rtems_bsd_rc_conf_argc_argv* aa)
{
if (aa->argc == 2 &&
(strcasecmp("DHCP", aa->argv[1]) == 0 ||
strcasecmp("SYNCDHCP", aa->argv[1]) == 0))
return true;
return false;
}
static int static int
setup_lo0(rtems_bsd_rc_conf* rc_conf, struct ifaddrs* ifap) setup_lo0(rtems_bsd_rc_conf* rc_conf, struct ifaddrs* ifap)
{ {
struct ifaddrs* ifa; struct ifaddrs* ifa;
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcasecmp("lo0", ifa->ifa_name) == 0) { if (strcasecmp("lo0", ifa->ifa_name) == 0) {
const char* lo0_argv[] = { const char* lo0_argv[] = {
@@ -412,34 +395,45 @@ setup_lo0(rtems_bsd_rc_conf* rc_conf, struct ifaddrs* ifap)
return 0; return 0;
} }
} }
fprintf(stderr, "warning: no loopback interface found\n"); fprintf(stderr, "warning: no loopback interface found\n");
return -1; return -1;
} }
static int static int
setup_interfaces(rtems_bsd_rc_conf* rc_conf, setup_interfaces(rtems_bsd_rc_conf* rc_conf,
rtems_bsd_rc_conf_argc_argv* aa, rtems_bsd_rc_conf_argc_argv* aa,
struct ifaddrs* ifap) struct ifaddrs* ifap,
bool* dhcp)
{ {
struct ifaddrs* ifa; struct ifaddrs* ifa;
int r;
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcasecmp("lo0", ifa->ifa_name) != 0) { if (strcasecmp("lo0", ifa->ifa_name) != 0) {
char iface[64]; char iface[64];
int r;
snprintf(iface, sizeof(iface), "ifconfig_%s", ifa->ifa_name); snprintf(iface, sizeof(iface), "ifconfig_%s", ifa->ifa_name);
r = rtems_bsd_rc_conf_find(rc_conf, iface, aa); r = rtems_bsd_rc_conf_find(rc_conf, iface, aa);
if (r == 0) { if (r == 0) {
show_result(iface, ifconfig_(rc_conf, ifa->ifa_name, aa->argc, aa->argv)); if (dhcp_check(aa)) {
*dhcp = true;
}
else {
show_result(iface, ifconfig_(rc_conf, ifa->ifa_name, aa->argc, aa->argv));
}
} }
} }
} }
return 0; return 0;
} }
static int static int
setup_vlans(rtems_bsd_rc_conf* rc_conf, setup_vlans(rtems_bsd_rc_conf* rc_conf,
rtems_bsd_rc_conf_argc_argv* aa, rtems_bsd_rc_conf_argc_argv* aa,
struct ifaddrs* ifap) struct ifaddrs* ifap,
bool* dhcp)
{ {
rtems_bsd_rc_conf_argc_argv* vaa; rtems_bsd_rc_conf_argc_argv* vaa;
struct ifaddrs* ifa; struct ifaddrs* ifa;
@@ -481,8 +475,13 @@ setup_vlans(rtems_bsd_rc_conf* rc_conf,
"ifconfig_%s_%s", ifa->ifa_name, aa->argv[arg]); "ifconfig_%s_%s", ifa->ifa_name, aa->argv[arg]);
r = rtems_bsd_rc_conf_find(rc_conf, expr, vaa); r = rtems_bsd_rc_conf_find(rc_conf, expr, vaa);
if (r == 0) { if (r == 0) {
show_result(vlan_name, ifconfig_(rc_conf, vlan_name, if (dhcp_check(vaa)) {
vaa->argc, vaa->argv)); *dhcp = true;
}
else {
show_result(vlan_name, ifconfig_(rc_conf, vlan_name,
vaa->argc, vaa->argv));
}
} }
} }
} }
@@ -495,10 +494,189 @@ setup_vlans(rtems_bsd_rc_conf* rc_conf,
return 0; return 0;
} }
/*
* The rc_conf struct cannot be passed to a thread as a pointer. It can only be
* used in the rc.conf worker thread. As a result the values need to print a
* verbose message to aid debugging needs to have local oopies made and passed
* to the dhcpcd worker. The dhcpcd worker runs for ever.
*/
typedef struct dhcpcd_data {
rtems_bsd_rc_conf_argc_argv* argc_argv;
bool verbose;
const char* name;
} dhcpcd_data;
static void
dhcpcd_worker(rtems_task_argument arg)
{
dhcpcd_data* dd = (dhcpcd_data*) arg;
int argc;
const char** argv;
const char* dhcpcd_argv[] = { "dhcpcd", NULL };
struct stat sb;
int r;
r = stat("/var", &sb);
if (r < 0) {
mkdir("/var", S_IRWXU | S_IRWXG | S_IRWXO);
}
r = stat("/var/db", &sb);
if (r < 0) {
mkdir("/var/db", S_IRWXU | S_IRWXG | S_IRWXO);
}
if (dd->argc_argv->argc > 0) {
argc = dd->argc_argv->argc;
argv = dd->argc_argv->argv;
}
else {
argc = 1;
argv = dhcpcd_argv;
}
if (dd->verbose) {
fprintf(stdout, "rc.conf: %s: dhcpcd ", dd->name);
for (r = 1; r < argc; ++r)
fprintf(stdout, "%s ", argv[r]);
fprintf(stdout, "\n");
}
r = rtems_bsd_command_dhcpcd(argc, argv);
if (r != EX_OK)
fprintf(stderr, "error: dhcpcd: stopped\n");
free(dd->name);
rtems_bsd_rc_conf_argc_argv_destroy(dd->argc_argv);
free(dd);
rtems_task_delete(RTEMS_SELF);
}
static int
run_dhcp(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa)
{
dhcpcd_data* dd;
rtems_status_code sc;
rtems_id id;
rtems_task_priority priority = RTEMS_MAXIMUM_PRIORITY - 1;
char* end = NULL;
int delay = 30;
int r;
/*
* These are passed to the worker and cleaned up there if it ever exits. Do
* not destroy here unless an error before the thread runs.
*/
dd = calloc(1, sizeof(*dd));
if (dd == NULL) {
fprintf(stderr, "error: dhcpcd data: no memory\n");
errno = ENOMEM;
return -1;
}
dd->name = strdup(rtems_bsd_rc_conf_name(rc_conf));
if (dd == NULL) {
free(dd);
fprintf(stderr, "error: dhcpcd data: no memory\n");
errno = ENOMEM;
return -1;
}
dd->argc_argv = rtems_bsd_rc_conf_argc_argv_create();
if (dd->argc_argv == NULL) {
free(dd->name);
free(dd);
errno = ENOMEM;
return -1;
}
dd->verbose = rtems_bsd_rc_conf_verbose(rc_conf);
r = rtems_bsd_rc_conf_find(rc_conf, "dhcpcd_priority", dd->argc_argv);
if (r == 0) {
if (dd->argc_argv->argc == 2) {
priority = strtoul(dd->argc_argv->argv[1], &end, 10);
if (priority == 0 || *end != '\0')
priority = RTEMS_MAXIMUM_PRIORITY - 1;
}
}
rtems_bsd_rc_conf_find(rc_conf, "dhcpcd_options", dd->argc_argv);
sc = rtems_task_create(rtems_build_name('D', 'H', 'C', 'P'),
priority,
2 * RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_MODES,
RTEMS_FLOATING_POINT,
&id);
if (sc == RTEMS_SUCCESSFUL)
sc = rtems_task_start(id, dhcpcd_worker, (rtems_task_argument) dd);
if (sc != RTEMS_SUCCESSFUL) {
fprintf(stderr,
"error: dhcpcd: thread create/start: %s\n", rtems_status_text(sc));
rtems_bsd_rc_conf_argc_argv_destroy(dd->argc_argv);
free(dd->name);
free(dd);
errno = EIO;
return -1;
}
/*
* See if a delay is specified else use default to 30 seconds. Wait for a
* valid default route.
*/
r = rtems_bsd_rc_conf_find(rc_conf, "defaultroute_delay", aa);
if (r == 0 && aa->argc == 2) {
delay = (int) strtol(aa->argv[1], &end, 10);
if (*end != '\0') {
fprintf(stderr, "error: defaultroute_delay: invalid delay value\n");
delay = 30;
}
}
printf("Waiting %ds for default route interface: ", delay);
fflush(stdout);
while (delay > 0) {
struct sockaddr_in sin;
struct sockaddr* rti_info[RTAX_MAX];
--delay;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
inet_pton(AF_INET, "0.0.0.0.", &sin.sin_addr);
r = rtems_get_route(&sin, rti_info);
if (r == 0 && rti_info[RTAX_GATEWAY] != NULL) {
break;
}
else if (r < 0 && errno != ESRCH) {
fprintf(stderr,
"error: get routes %d: %d %s\n", r, errno, strerror(errno));
}
sleep(1);
}
/*
* We should print the interface but I cannot see how to get the interface
* with the default route without a lot of code.
*/
if (delay > 0)
printf("found.\n");
else
printf("\nerror: no default route found\n");
return 0;
}
static int static int
interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa)
{ {
struct ifaddrs* ifap; struct ifaddrs* ifap;
bool dhcp = false;
if (getifaddrs(&ifap) != 0) { if (getifaddrs(&ifap) != 0) {
fprintf(stderr, "error: interfaces: getifaddrs: %s\n", strerror(errno)); fprintf(stderr, "error: interfaces: getifaddrs: %s\n", strerror(errno));
@@ -508,8 +686,11 @@ interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa)
show_interfaces("Starting network: ", ifap); show_interfaces("Starting network: ", ifap);
show_result("cloned_interfaces", cloned_interfaces(rc_conf, aa)); show_result("cloned_interfaces", cloned_interfaces(rc_conf, aa));
show_result("lo0", setup_lo0(rc_conf, ifap)); show_result("lo0", setup_lo0(rc_conf, ifap));
show_result("ifaces", setup_interfaces(rc_conf, aa, ifap)); show_result("ifaces", setup_interfaces(rc_conf, aa, ifap, &dhcp));
show_result("vlans", setup_vlans(rc_conf, aa, ifap)); show_result("vlans", setup_vlans(rc_conf, aa, ifap, &dhcp));
show_result("defaultrouter", defaultrouter(rc_conf, aa));
if (dhcp)
show_result("dhcp", run_dhcp(rc_conf, aa));
free(ifap); free(ifap);
@@ -534,8 +715,6 @@ network_service(rtems_bsd_rc_conf* rc_conf)
return -1; return -1;
} }
show_result("defaultrouter", defaultrouter(rc_conf, aa));
rtems_bsd_rc_conf_argc_argv_destroy(aa); rtems_bsd_rc_conf_argc_argv_destroy(aa);
return 0; return 0;
@@ -549,5 +728,6 @@ rc_conf_net_init(void* arg)
"after:first;", "after:first;",
network_service); network_service);
if (r < 0) if (r < 0)
fprintf(stderr, "error: network service add failed: %s\n", strerror(errno)); fprintf(stderr,
"error: network service add failed: %s\n", strerror(errno));
} }

View File

@@ -37,6 +37,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <regex.h> #include <regex.h>
#include <syslog.h>
#include <rtems.h> #include <rtems.h>
#include <rtems/chain.h> #include <rtems/chain.h>
@@ -108,6 +110,7 @@ argc_argv_clean(rtems_bsd_rc_conf_argc_argv* aa)
free(aa->command); free(aa->command);
aa->argv = NULL; aa->argv = NULL;
aa->command = NULL; aa->command = NULL;
aa->argc = 0;
} }
} }
@@ -422,6 +425,8 @@ int rtems_bsd_rc_conf_find_next(rtems_bsd_rc_conf* rc_conf,
regfree(&rege); regfree(&rege);
} }
argc_argv_clean(argc_argv);
errno = ENOENT; errno = ENOENT;
return -1; return -1;
@@ -669,12 +674,41 @@ rtems_bsd_rc_conf_service_remove(const char* name)
return -1; return -1;
} }
static rtems_task rc_conf_worker(rtems_task_argument task_argument) static void
rc_conf_syslog(rtems_bsd_rc_conf* rc_conf)
{
rtems_bsd_rc_conf_argc_argv* aa;
int r = 0;
aa = rtems_bsd_rc_conf_argc_argv_create();
if (aa != NULL) {
r = rtems_bsd_rc_conf_find(rc_conf, "syslog_priority", aa);
if (r == 0) {
if (aa->argc == 2) {
r = rtems_bsd_setlogpriority(aa->argv[1]);
if (r < 0)
fprintf(stderr,
"error: syslog: invalid priority: %s\n", aa->argv[1]);
}
else {
fprintf(stderr, "error: syslog: invalid priority\n");
}
}
rtems_bsd_rc_conf_argc_argv_destroy(aa);
}
}
static rtems_task
rc_conf_worker(rtems_task_argument task_argument)
{ {
rtems_bsd_rc_conf* rc_conf = (rtems_bsd_rc_conf*) task_argument; rtems_bsd_rc_conf* rc_conf = (rtems_bsd_rc_conf*) task_argument;
rtems_chain_node* node = rtems_chain_first(&services); rtems_chain_node* node = rtems_chain_first(&services);
int r = 0; int r = 0;
int error; int error;
/*
* Check for a syslog priority before any services are run.
*/
rc_conf_syslog(rc_conf);
if (rc_conf->verbose) if (rc_conf->verbose)
printf("rc.conf: running\n"); printf("rc.conf: running\n");
@@ -686,7 +720,8 @@ static rtems_task rc_conf_worker(rtems_task_argument task_argument)
printf("Starting %s.\n", srv->name); printf("Starting %s.\n", srv->name);
rr = srv->entry(rc_conf); rr = srv->entry(rc_conf);
if (rr < 0) { if (rr < 0) {
fprintf(stderr, "error: bsd service: %s: %s\n", srv->name, strerror(errno)); fprintf(stderr,
"error: bsd service: %s: %s\n", srv->name, strerror(errno));
if (r == 0) { if (r == 0) {
r = rr; r = rr;
error = errno; error = errno;

View File

@@ -23,6 +23,31 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
/*
* Tests:
*
* 1. rc.conf processing
* 1.1 syslog_priority
* 1.2 create_args_*
* 1.3 hostname
* 1.4 ifconfig_<iface>
* 1.5 vlans_<iface>
* 1.6 ifconfig_<iface>.<vlan>
* 1.7 defaultrouter
* 1.8 defaultroute_delay
* 1.9 ftp_enable
* 1.10 ftp_options
* 1.11 dhcpcd_priority
* 1.12 dhcpcd_options
*
* 2. dhcpcd (via vlan, should timeout unless VLAN is present)
*
* 3. get route, the defaultrouter sets a default route and the vlan DHCP
* interface requires the default route be probed and found.
*
* 4. ftpd
*/
#include <rtems/bsd/sys/param.h> #include <rtems/bsd/sys/param.h>
#include <assert.h> #include <assert.h>
@@ -44,12 +69,15 @@
#include <rtems/console.h> #include <rtems/console.h>
#include <rtems/shell.h> #include <rtems/shell.h>
#if DEFINE_FOR_TESTING
#define RCCONF02_HAS_SHELL #define RCCONF02_HAS_SHELL
#endif
#define TEST_NAME "LIBBSD RC.CONF 2" #define TEST_NAME "LIBBSD RC.CONF 2"
#define IFACE_IPV4(iface) \ #define IFACE_IPV4(iface) \
"ifconfig_" # iface " inet " NET_CFG_SELF_IP " netmask " NET_CFG_NETMASK "\n" "ifconfig_" # iface "=\"inet " NET_CFG_SELF_IP " netmask " NET_CFG_NETMASK "\"\n"
#define RC_CONF_IFACES \ #define RC_CONF_IFACES \
IFACE_IPV4(dmc0) \ IFACE_IPV4(dmc0) \
@@ -61,8 +89,8 @@
#define IFACE_VLAN(iface) \ #define IFACE_VLAN(iface) \
"vlans_" # iface "=\"101 102\"\n" \ "vlans_" # iface "=\"101 102\"\n" \
"ifconfig_" # iface "_101=\"inet 192.0.101.1/24\n" \ "ifconfig_" # iface "_101=\"inet 192.0.101.1/24\"\n" \
"ifconfig_" # iface "_102=\"inet 192.0.102.1/24\n" "ifconfig_" # iface "_102=\"DHCP\"\n"
#define RC_CONF_VLANS \ #define RC_CONF_VLANS \
IFACE_VLAN(dmc0) \ IFACE_VLAN(dmc0) \
@@ -72,22 +100,28 @@
IFACE_VLAN(em0) \ IFACE_VLAN(em0) \
IFACE_VLAN(re0) IFACE_VLAN(re0)
static const char* rc_conf_text = \ static const char* rc_conf_text = \
"#\n" \ "#\n" \
"# Tests rc.conf. Add every NIC\n" \ "# Tests rc.conf. Add every NIC\n" \
"#\n" \ "#\n" \
"hostname=\"rctest\"\n" \ "\n" \
"\n" \ "syslog_priority=\"debug\"\n" \
"create_args_myvlan=\"vlan 102\"\n" \ "\n" \
"create_args_yourvlan=\"vlan 202\"\n" \ "hostname=\"rctest\"\n" \
"\n" \ "\n" \
RC_CONF_IFACES \ "create_args_myvlan=\"vlan 102\"\n" \
"\n" \ "create_args_yourvlan=\"vlan 202\"\n" \
RC_CONF_VLANS \ "\n" \
"\n" \ RC_CONF_IFACES \
"defaultrouter=\"" NET_CFG_GATEWAY_IP "\"\n" \ "\n" \
"\n" \ RC_CONF_VLANS \
"ftpd_enable=\"YES\"\n" \ "\n" \
"defaultrouter=\"" NET_CFG_GATEWAY_IP "\"\n" \
"defaultroute_delay=\"5\"\n" \
"\n" \
"dhcpcd_options=\"-h foobar\"\n" \
"\n" \
"ftpd_enable=\"YES\"\n" \
"ftpd_options=\"-v -p 21 -C 10 -P 150 -L -I 10 -R /\"\n" \ "ftpd_options=\"-v -p 21 -C 10 -P 150 -L -I 10 -R /\"\n" \
"n"; "n";
@@ -129,6 +163,9 @@ test_main(void)
true, true,
NULL NULL
); );
#else
printf("RCCONF02 sleeping for 10s\n");
sleep(10);
#endif /* RCCONF02_HAS_SHELL */ #endif /* RCCONF02_HAS_SHELL */
exit(0); exit(0);