dhcpd: Supports kernel mode compilation

The previous method of terminating the dhcp daemon via a global variable has been removed; instead, the `kill pid` command is used. Also, because the original `dhcp_start` method creates tasks via `task_create`, which is not supported in kernel mode, `dhcp_start` is not compiled in kernel mode. The daemon can be started in kernel mode using `dhcpd xxx &`.

Signed-off-by: zhangshuai39 <zhangshuai39@xiaomi.com>
This commit is contained in:
zhangshuai39 2025-08-07 14:33:52 +08:00 committed by Alan C. Assis
parent 9ad4c3c395
commit 6830e297cf
4 changed files with 135 additions and 77 deletions

View file

@ -30,23 +30,27 @@ if(CONFIG_EXAMPLES_DHCPD)
STACKSIZE STACKSIZE
${CONFIG_DEFAULT_TASK_STACKSIZE}) ${CONFIG_DEFAULT_TASK_STACKSIZE})
nuttx_add_application( if(NOT CONFIG_BUILD_KERNEL)
NAME nuttx_add_application(
dhcpd_start NAME
SRCS dhcpd_start
dhcpd_start.c SRCS
dhcpd_daemon.c dhcpd_start.c
STACKSIZE dhcpd_daemon.c
${CONFIG_DEFAULT_TASK_STACKSIZE}) STACKSIZE
${CONFIG_DEFAULT_TASK_STACKSIZE})
endif()
nuttx_add_application( if(CONFIG_SCHED_WAITPID)
NAME nuttx_add_application(
dhcpd_stop NAME
SRCS dhcpd_stop
dhcpd_stop.c SRCS
dhcpd_daemon.c dhcpd_stop.c
STACKSIZE dhcpd_daemon.c
${CONFIG_DEFAULT_TASK_STACKSIZE}) STACKSIZE
${CONFIG_DEFAULT_TASK_STACKSIZE})
endif()
add_definitions(-DCONFIG_NETUTILS_DHCPD_HOST=1 -DHAVE_SO_REUSEADDR=1 add_definitions(-DCONFIG_NETUTILS_DHCPD_HOST=1 -DHAVE_SO_REUSEADDR=1
-DHAVE_SO_BROADCAST=1) -DHAVE_SO_BROADCAST=1)

View file

@ -26,13 +26,23 @@ include $(APPDIR)/Make.defs
CSRCS = dhcpd_daemon.c CSRCS = dhcpd_daemon.c
MAINSRC = dhcpd_start.c dhcpd_stop.c target.c MAINSRC = target.c
# DHCPD built-in application info # DHCPD built-in application info
PROGNAME = dhcpd_start dhcpd_stop dhcpd PROGNAME = dhcpd
PRIORITY = SCHED_PRIORITY_DEFAULT PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE) STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
MODULE = $(CONFIG_EXAMPLES_DHCPD) MODULE = $(CONFIG_EXAMPLES_DHCPD)
ifneq ($(CONFIG_BUILD_KERNEL),y)
MAINSRC += dhcpd_start.c
PROGNAME += dhcpd_start
endif
ifeq ($(CONFIG_SCHED_WAITPID),y)
MAINSRC += dhcpd_stop.c
PROGNAME += dhcpd_stop
endif
include $(APPDIR)/Application.mk include $(APPDIR)/Application.mk

View file

@ -128,10 +128,12 @@ int dhcpd_daemon(int argc, FAR char *argv[], bool daemon)
/* Then start the dhcpd */ /* Then start the dhcpd */
if (daemon) #ifndef CONFIG_BUILD_KERNEL
if (!daemon)
{ {
return dhcpd_run(devname); return dhcpd_start(devname);
} }
#endif
return dhcpd_start(devname); return dhcpd_run(devname);
} }

View file

@ -47,6 +47,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/wait.h>
#include <inttypes.h> #include <inttypes.h>
#include <sched.h> #include <sched.h>
@ -276,8 +277,6 @@ struct dhcpd_state_s
struct dhcpd_daemon_s struct dhcpd_daemon_s
{ {
uint8_t ds_state; /* See enum dhcpd_daemon_e */ uint8_t ds_state; /* See enum dhcpd_daemon_e */
sem_t ds_lock; /* Used to protect the whole structure */
sem_t ds_sync; /* Used to synchronize start and stop events */
pid_t ds_pid; /* Task ID of the DHCPD daemon */ pid_t ds_pid; /* Task ID of the DHCPD daemon */
FAR struct dhcpd_state_s *ds_data; /* DHCPD daemon data */ FAR struct dhcpd_state_s *ds_data; /* DHCPD daemon data */
}; };
@ -314,8 +313,6 @@ static const uint8_t g_magiccookie[4] =
static struct dhcpd_daemon_s g_dhcpd_daemon = static struct dhcpd_daemon_s g_dhcpd_daemon =
{ {
DHCPD_NOT_RUNNING, DHCPD_NOT_RUNNING,
SEM_INITIALIZER(1),
SEM_INITIALIZER(0),
-1, -1,
NULL NULL
}; };
@ -1019,7 +1016,7 @@ static int dhcpd_sendpacket(int sockfd, int bbroadcast)
#endif #endif
/* Create a socket to respond with a packet to the client. We /* Create a socket to respond with a packet to the client. We
* cannot re-use the listener socket because it is not bound correctly * cannot reuse the listener socket because it is not bound correctly
*/ */
/* Then send the response to the DHCP client port at that address */ /* Then send the response to the DHCP client port at that address */
@ -1407,7 +1404,7 @@ static inline int dhcpd_decline(void)
lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr);
if (lease) if (lease)
{ {
/* Disassociate the IP from the MAC, but prevent re-used of this /* Disassociate the IP from the MAC, but prevent reused of this
* address for a period of time. * address for a period of time.
*/ */
@ -1497,10 +1494,74 @@ static inline int dhcpd_openlistener(FAR const char *interface)
* Name: dhcpd_task_run * Name: dhcpd_task_run
****************************************************************************/ ****************************************************************************/
#ifndef CONFIG_BUILD_KERNEL
static int dhcpd_task_run(int argc, char **argv) static int dhcpd_task_run(int argc, char **argv)
{ {
return dhcpd_run(argv[1]); return dhcpd_run(argv[1]);
} }
#endif
/****************************************************************************
* Name: dhcpd_get_pid
*
* Description:
* Use /proc filesystem to get dhcpd process PID
*
* Returned Value:
* PID of dhcpd process on success, -1 on failure
*
****************************************************************************/
#if !defined(CONFIG_BUILD_KERNEL) || defined(CONFIG_SCHED_WAITPID)
static pid_t dhcpd_get_pid(void)
{
pid_t pid = -1;
#if !defined(CONFIG_BUILD_KERNEL)
pid = g_dhcpd_daemon.ds_pid;
#elif defined(CONFIG_SYSTEM_POPEN)
FAR FILE *fp;
char line[32];
fp = popen(("pidof dhcpd"), "r");
if (fp == NULL)
{
return -errno;
}
if (fgets(line, sizeof(line), fp) != NULL)
{
pid = atoi(line);
}
pclose(fp);
#endif
return pid;
}
#endif
/****************************************************************************
* Name: dhcpd_signal_handler
*
* Description:
* Signal handler for CONFIG_NETUTILS_DHCPD_SIGWAKEUP
* This function allows dhcpd_stop to terminate dhcpd daemon
*
* Input Parameters:
* signo - Signal number
* info - Signal information
* ctx - Signal context
*
****************************************************************************/
static void
dhcpd_signal_handler(int signo, FAR siginfo_t *info, FAR void *ctx)
{
/* Set global flag to indicate stop request */
g_dhcpd_daemon.ds_state = DHCPD_STOP_REQUESTED;
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
@ -1512,7 +1573,8 @@ static int dhcpd_task_run(int argc, char **argv)
int dhcpd_run(FAR const char *interface) int dhcpd_run(FAR const char *interface)
{ {
int sockfd; struct sigaction act;
int sockfd = -1;
int nbytes; int nbytes;
ninfo("Started\n"); ninfo("Started\n");
@ -1538,15 +1600,19 @@ int dhcpd_run(FAR const char *interface)
g_dhcpd_daemon.ds_pid = getpid(); g_dhcpd_daemon.ds_pid = getpid();
/* Install signal handler for CONFIG_NETUTILS_DHCPD_SIGWAKEUP */
memset(&act, 0, sizeof(act));
act.sa_sigaction = dhcpd_signal_handler;
act.sa_flags = SA_SIGINFO;
sigaction(CONFIG_NETUTILS_DHCPD_SIGWAKEUP, &act, NULL);
/* Indicate that we have started */ /* Indicate that we have started */
g_dhcpd_daemon.ds_state = DHCPD_RUNNING; g_dhcpd_daemon.ds_state = DHCPD_RUNNING;
sem_post(&g_dhcpd_daemon.ds_sync);
/* Now loop indefinitely, reading packets from the DHCP server socket */ /* Now loop indefinitely, reading packets from the DHCP server socket */
sockfd = -1;
while (g_dhcpd_daemon.ds_state != DHCPD_STOP_REQUESTED) while (g_dhcpd_daemon.ds_state != DHCPD_STOP_REQUESTED)
{ {
/* Create a socket to listen for requests from DHCP clients */ /* Create a socket to listen for requests from DHCP clients */
@ -1631,7 +1697,6 @@ int dhcpd_run(FAR const char *interface)
g_dhcpd_daemon.ds_data = NULL; g_dhcpd_daemon.ds_data = NULL;
g_dhcpd_daemon.ds_pid = -1; g_dhcpd_daemon.ds_pid = -1;
g_dhcpd_daemon.ds_state = DHCPD_STOPPED; g_dhcpd_daemon.ds_state = DHCPD_STOPPED;
sem_post(&g_dhcpd_daemon.ds_sync);
return OK; return OK;
} }
@ -1648,6 +1713,7 @@ int dhcpd_run(FAR const char *interface)
* *
****************************************************************************/ ****************************************************************************/
#ifndef CONFIG_BUILD_KERNEL
int dhcpd_start(FAR const char *interface) int dhcpd_start(FAR const char *interface)
{ {
FAR char *argv[2]; FAR char *argv[2];
@ -1658,17 +1724,13 @@ int dhcpd_start(FAR const char *interface)
/* Is the DHCPD in a non-running state? */ /* Is the DHCPD in a non-running state? */
sem_wait(&g_dhcpd_daemon.ds_lock); if (dhcpd_get_pid() < 0)
if (g_dhcpd_daemon.ds_state == DHCPD_NOT_RUNNING ||
g_dhcpd_daemon.ds_state == DHCPD_STOPPED)
{ {
/* Start the DHCPD daemon */ /* Start the DHCPD daemon */
g_dhcpd_daemon.ds_state = DHCPD_STARTED; pid = task_create("dhcpd", CONFIG_NETUTILS_DHCPD_PRIORITY,
pid = CONFIG_NETUTILS_DHCPD_STACKSIZE, dhcpd_task_run,
task_create("DHCPD daemon", CONFIG_NETUTILS_DHCPD_PRIORITY, argv);
CONFIG_NETUTILS_DHCPD_STACKSIZE, dhcpd_task_run,
argv);
/* Handle failures to start the DHCPD daemon */ /* Handle failures to start the DHCPD daemon */
@ -1676,24 +1738,14 @@ int dhcpd_start(FAR const char *interface)
{ {
int errval = errno; int errval = errno;
g_dhcpd_daemon.ds_state = DHCPD_STOPPED;
nerr("ERROR: Failed to start the DHCPD daemon: %d\n", errval); nerr("ERROR: Failed to start the DHCPD daemon: %d\n", errval);
sem_post(&g_dhcpd_daemon.ds_lock);
return -errval; return -errval;
} }
/* Wait for any daemon state change */
do
{
sem_wait(&g_dhcpd_daemon.ds_sync);
}
while (g_dhcpd_daemon.ds_state == DHCPD_STARTED);
} }
sem_post(&g_dhcpd_daemon.ds_lock);
return OK; return OK;
} }
#endif
/**************************************************************************** /****************************************************************************
* Name: dhcpd_stop * Name: dhcpd_stop
@ -1707,46 +1759,36 @@ int dhcpd_start(FAR const char *interface)
* *
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SCHED_WAITPID
int dhcpd_stop(void) int dhcpd_stop(void)
{ {
int ret; pid_t pid;
/* Is the DHCPD in a running state? */ /* Is the DHCPD in a running state? */
sem_wait(&g_dhcpd_daemon.ds_lock); pid = dhcpd_get_pid();
if (g_dhcpd_daemon.ds_state == DHCPD_STARTED || if (pid >= 0)
g_dhcpd_daemon.ds_state == DHCPD_RUNNING)
{ {
/* Yes.. request that the daemon stop. */ /* Yes.. request that the daemon stop. */
g_dhcpd_daemon.ds_state = DHCPD_STOP_REQUESTED; if (kill(pid, CONFIG_NETUTILS_DHCPD_SIGWAKEUP) < 0)
/* Wait for any daemon state change */
do
{ {
/* Signal the DHCPD client */ nerr("ERROR: kill pid %d failed: %d\n", pid, errno);
return -errno;
ret = kill(g_dhcpd_daemon.ds_pid, }
CONFIG_NETUTILS_DHCPD_SIGWAKEUP);
/* Wait for the DHCPD client to respond to the stop request */
if (ret < 0)
{ if (waitpid(pid, NULL, 0) < 0)
nerr("ERROR: kill pid %d failed: %d\n", {
g_dhcpd_daemon.ds_pid, errno); nerr("ERROR: waitpid failed: %d\n", errno);
break; return -errno;
}
/* Wait for the DHCPD client to respond to the stop request */
sem_wait(&g_dhcpd_daemon.ds_sync);
} }
while (g_dhcpd_daemon.ds_state == DHCPD_STOP_REQUESTED);
} }
sem_post(&g_dhcpd_daemon.ds_lock);
return OK; return OK;
} }
#endif
/**************************************************************************** /****************************************************************************
* Name: dhcpd_set_startip * Name: dhcpd_set_startip