net: trickle: Do not initialize a work item from its handler

Initializing a work item from its handler will destroy the content of
the kernel structures used to process the work item. This can lead to a
system crash for example when the delayed work is being rescheduled when
the previous run is already queued for processing but not yet executed.

Fix this by initializing the work item once during trickle timer
creation and moving the logic, previously achieved by switching the work
handler, into the new work handler.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2021-04-26 15:31:17 +02:00 committed by Jukka Rissanen
commit afaf52af66
2 changed files with 21 additions and 11 deletions

View file

@ -60,6 +60,7 @@ struct net_trickle {
uint8_t c; /**< Consistency counter */
uint32_t Imax_abs; /**< Max interval size in ms (not doublings) */
bool double_to;
struct k_work_delayable timer;
net_trickle_cb_t cb; /**< Callback to be called when timer expires */

View file

@ -50,11 +50,8 @@ static uint32_t get_t(uint32_t I)
return I + (sys_rand32_get() % I);
}
static void double_interval_timeout(struct k_work *work)
static void double_interval_timeout(struct net_trickle *trickle)
{
struct net_trickle *trickle = CONTAINER_OF(work,
struct net_trickle,
timer);
uint32_t rand_time;
uint32_t last_end = get_end(trickle);
@ -80,7 +77,8 @@ static void double_interval_timeout(struct k_work *work)
NET_DBG("doubling time %u", rand_time);
trickle->Istart = k_uptime_get_32() + rand_time;
k_work_init_delayable(&trickle->timer, trickle_timeout);
trickle->double_to = false;
k_work_reschedule(&trickle->timer, K_MSEC(rand_time));
NET_DBG("last end %u new end %u for %u I %u",
@ -100,16 +98,13 @@ static inline void reschedule(struct net_trickle *trickle)
NET_DBG("Clock wrap");
}
k_work_init_delayable(&trickle->timer, double_interval_timeout);
trickle->double_to = true;
k_work_reschedule(&trickle->timer, K_MSEC(diff));
}
static void trickle_timeout(struct k_work *work)
static void inteval_timeout(struct net_trickle *trickle)
{
struct net_trickle *trickle = CONTAINER_OF(work,
struct net_trickle,
timer);
NET_DBG("Trickle timeout at %d", k_uptime_get_32());
if (trickle->cb) {
@ -125,6 +120,19 @@ static void trickle_timeout(struct k_work *work)
}
}
static void trickle_timeout(struct k_work *work)
{
struct net_trickle *trickle = CONTAINER_OF(work,
struct net_trickle,
timer);
if (trickle->double_to) {
double_interval_timeout(trickle);
} else {
inteval_timeout(trickle);
}
}
static void setup_new_interval(struct net_trickle *trickle)
{
uint32_t t;
@ -180,6 +188,7 @@ int net_trickle_start(struct net_trickle *trickle,
trickle->cb = cb;
trickle->user_data = user_data;
trickle->double_to = false;
/* Random I in [Imin , Imax] */
trickle->I = trickle->Imin +