[rtems-libbsd commit] Add DHCP support to rc.conf.

Chris Johns chrisj at rtems.org
Wed Jun 29 23:20:11 UTC 2016


Module:    rtems-libbsd
Branch:    master
Commit:    573b1982436d2e11f2ae1450f2232ca22d862a8a
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=573b1982436d2e11f2ae1450f2232ca22d862a8a

Author:    Chris Johns <chrisj at rtems.org>
Date:      Thu Jun 30 09:19:52 2016 +1000

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 f4dc0d6..8181226 100644
--- a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c
+++ b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c
@@ -39,11 +39,16 @@
 #include <sysexits.h>
 
 #include <ifaddrs.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 
 #include <errno.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include <rtems.h>
@@ -52,6 +57,8 @@
 #include <machine/rtems-bsd-commands.h>
 #include <machine/rtems-bsd-rc-conf-services.h>
 
+#include <rtems/rtems-routes.h>
+
 /*
  * 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);
@@ -400,9 +372,20 @@ show_interfaces(const char* msg, struct ifaddrs* ifap)
 }
 
 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 5346593..ce5f6aa 100644
--- a/rtemsbsd/rtems/rtems-bsd-rc-conf.c
+++ b/rtemsbsd/rtems/rtems-bsd-rc-conf.c
@@ -37,6 +37,8 @@
 #include <sys/stat.h>
 #include <regex.h>
 
+#include <syslog.h>
+
 #include <rtems.h>
 #include <rtems/chain.h>
 
@@ -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(&rege);
   }
 
+  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 1ce456b..7cb9999 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_<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 <assert.h>
@@ -44,12 +69,15 @@
 #include <rtems/console.h>
 #include <rtems/shell.h>
 
+#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);



More information about the vc mailing list