From 573b1982436d2e11f2ae1450f2232ca22d862a8a Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 30 Jun 2016 09:19:52 +1000 Subject: Add DHCP support to rc.conf. --- rtemsbsd/rtems/rtems-bsd-rc-conf-net.c | 280 +++++++++++++++++++++++++++------ rtemsbsd/rtems/rtems-bsd-rc-conf.c | 45 +++++- testsuite/rcconf02/test_main.c | 75 ++++++--- 3 files changed, 326 insertions(+), 74 deletions(-) diff --git a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c index f4dc0d6f..81812266 100644 --- a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c +++ b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c @@ -39,11 +39,16 @@ #include #include +#include +#include +#include +#include #include #include #include #include +#include #include #include @@ -52,6 +57,8 @@ #include #include +#include + /* * 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; } -/* - * 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 show_interfaces(const char* msg, struct ifaddrs* ifap) { @@ -381,6 +349,10 @@ show_interfaces(const char* msg, struct ifaddrs* ifap) fprintf(stdout, msg); + /* + * Always have lo0 first. + */ + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strcasecmp("lo0", ifa->ifa_name) == 0) { fprintf(stdout, "%s ", ifa->ifa_name); @@ -399,10 +371,21 @@ show_interfaces(const char* msg, struct ifaddrs* ifap) 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 setup_lo0(rtems_bsd_rc_conf* rc_conf, struct ifaddrs* ifap) { struct ifaddrs* ifa; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strcasecmp("lo0", ifa->ifa_name) == 0) { const char* lo0_argv[] = { @@ -412,34 +395,45 @@ setup_lo0(rtems_bsd_rc_conf* rc_conf, struct ifaddrs* ifap) return 0; } } + fprintf(stderr, "warning: no loopback interface found\n"); + return -1; } static int setup_interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa, - struct ifaddrs* ifap) + struct ifaddrs* ifap, + bool* dhcp) { struct ifaddrs* ifa; + int r; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strcasecmp("lo0", ifa->ifa_name) != 0) { char iface[64]; - int r; snprintf(iface, sizeof(iface), "ifconfig_%s", ifa->ifa_name); r = rtems_bsd_rc_conf_find(rc_conf, iface, aa); 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; } static int setup_vlans(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa, - struct ifaddrs* ifap) + struct ifaddrs* ifap, + bool* dhcp) { rtems_bsd_rc_conf_argc_argv* vaa; struct ifaddrs* ifa; @@ -481,8 +475,13 @@ setup_vlans(rtems_bsd_rc_conf* rc_conf, "ifconfig_%s_%s", ifa->ifa_name, aa->argv[arg]); r = rtems_bsd_rc_conf_find(rc_conf, expr, vaa); if (r == 0) { - show_result(vlan_name, ifconfig_(rc_conf, vlan_name, - vaa->argc, vaa->argv)); + if (dhcp_check(vaa)) { + *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; } +/* + * 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 interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) { struct ifaddrs* ifap; + bool dhcp = false; if (getifaddrs(&ifap) != 0) { 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_result("cloned_interfaces", cloned_interfaces(rc_conf, aa)); show_result("lo0", setup_lo0(rc_conf, ifap)); - show_result("ifaces", setup_interfaces(rc_conf, aa, ifap)); - show_result("vlans", setup_vlans(rc_conf, aa, ifap)); + show_result("ifaces", setup_interfaces(rc_conf, aa, ifap, &dhcp)); + 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); @@ -534,8 +715,6 @@ network_service(rtems_bsd_rc_conf* rc_conf) return -1; } - show_result("defaultrouter", defaultrouter(rc_conf, aa)); - rtems_bsd_rc_conf_argc_argv_destroy(aa); return 0; @@ -549,5 +728,6 @@ rc_conf_net_init(void* arg) "after:first;", network_service); 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)); } diff --git a/rtemsbsd/rtems/rtems-bsd-rc-conf.c b/rtemsbsd/rtems/rtems-bsd-rc-conf.c index 53465931..ce5f6aaf 100644 --- a/rtemsbsd/rtems/rtems-bsd-rc-conf.c +++ b/rtemsbsd/rtems/rtems-bsd-rc-conf.c @@ -37,6 +37,8 @@ #include #include +#include + #include #include @@ -108,6 +110,7 @@ argc_argv_clean(rtems_bsd_rc_conf_argc_argv* aa) free(aa->command); aa->argv = 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(®e); } + argc_argv_clean(argc_argv); + errno = ENOENT; return -1; @@ -669,12 +674,41 @@ rtems_bsd_rc_conf_service_remove(const char* name) 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_chain_node* node = rtems_chain_first(&services); - int r = 0; - int error; + rtems_chain_node* node = rtems_chain_first(&services); + int r = 0; + int error; + + /* + * Check for a syslog priority before any services are run. + */ + rc_conf_syslog(rc_conf); if (rc_conf->verbose) 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); rr = srv->entry(rc_conf); 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) { r = rr; error = errno; diff --git a/testsuite/rcconf02/test_main.c b/testsuite/rcconf02/test_main.c index 1ce456b3..7cb99994 100644 --- a/testsuite/rcconf02/test_main.c +++ b/testsuite/rcconf02/test_main.c @@ -23,6 +23,31 @@ * SUCH DAMAGE. */ +/* + * Tests: + * + * 1. rc.conf processing + * 1.1 syslog_priority + * 1.2 create_args_* + * 1.3 hostname + * 1.4 ifconfig_ + * 1.5 vlans_ + * 1.6 ifconfig_. + * 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 #include @@ -44,12 +69,15 @@ #include #include +#if DEFINE_FOR_TESTING #define RCCONF02_HAS_SHELL +#endif #define TEST_NAME "LIBBSD RC.CONF 2" #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 \ IFACE_IPV4(dmc0) \ @@ -61,8 +89,8 @@ #define IFACE_VLAN(iface) \ "vlans_" # iface "=\"101 102\"\n" \ - "ifconfig_" # iface "_101=\"inet 192.0.101.1/24\n" \ - "ifconfig_" # iface "_102=\"inet 192.0.102.1/24\n" + "ifconfig_" # iface "_101=\"inet 192.0.101.1/24\"\n" \ + "ifconfig_" # iface "_102=\"DHCP\"\n" #define RC_CONF_VLANS \ IFACE_VLAN(dmc0) \ @@ -72,22 +100,28 @@ IFACE_VLAN(em0) \ IFACE_VLAN(re0) -static const char* rc_conf_text = \ - "#\n" \ - "# Tests rc.conf. Add every NIC\n" \ - "#\n" \ - "hostname=\"rctest\"\n" \ - "\n" \ - "create_args_myvlan=\"vlan 102\"\n" \ - "create_args_yourvlan=\"vlan 202\"\n" \ - "\n" \ - RC_CONF_IFACES \ - "\n" \ - RC_CONF_VLANS \ - "\n" \ - "defaultrouter=\"" NET_CFG_GATEWAY_IP "\"\n" \ - "\n" \ - "ftpd_enable=\"YES\"\n" \ +static const char* rc_conf_text = \ + "#\n" \ + "# Tests rc.conf. Add every NIC\n" \ + "#\n" \ + "\n" \ + "syslog_priority=\"debug\"\n" \ + "\n" \ + "hostname=\"rctest\"\n" \ + "\n" \ + "create_args_myvlan=\"vlan 102\"\n" \ + "create_args_yourvlan=\"vlan 202\"\n" \ + "\n" \ + RC_CONF_IFACES \ + "\n" \ + RC_CONF_VLANS \ + "\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" \ "n"; @@ -129,6 +163,9 @@ test_main(void) true, NULL ); +#else + printf("RCCONF02 sleeping for 10s\n"); + sleep(10); #endif /* RCCONF02_HAS_SHELL */ exit(0); -- cgit v1.2.3