net: lwm2m: Allow cancel-observe to match path

The specification states that the server can cancel observations "at any
moment, by sendinga GET request with Observe option=1, the LwM2M Server
cancancel an “Observe”operation on a specified Resource, or specified
Object Instance(s)."

It does not mention any token matching requirement, but RFC 7641 does.
The correct interpretation is not obvious. The EMQx LwM2M implementation
uses a new token for instance, which does not work with Zephyrs token
matching cancel-observe.

This commit introduces cancel-observe via path matching as a Kconfig
option. This could hypothetically introduce problems when we are
connected to multiple peers simultaneously, but since that is not likely
to be supported for a long time (if ever), this change should be fairly
uncontroversial since path matching is only used as a fallback.

Signed-off-by: Benjamin Lindqvist <benjamin.lindqvist@endian.se>
This commit is contained in:
Benjamin Lindqvist 2021-03-03 11:43:05 +01:00 committed by Jukka Rissanen
commit e3f8757b70
2 changed files with 64 additions and 1 deletions

View file

@ -554,6 +554,54 @@ static int engine_remove_observer(const uint8_t *token, uint8_t tkl)
return 0;
}
#if defined(CONFIG_LOG)
char *lwm2m_path_log_strdup(struct lwm2m_obj_path *path)
{
char buf[sizeof("65535/65535/65535/65535")];
size_t cur = sprintf(buf, "%u", path->obj_id);
if (path->level > 1) {
cur += sprintf(buf + cur, "/%u", path->obj_inst_id);
}
if (path->level > 2) {
cur += sprintf(buf + cur, "/%u", path->res_id);
}
if (path->level > 3) {
cur += sprintf(buf + cur, "/%u", path->res_inst_id);
}
return log_strdup(buf);
}
#endif /* CONFIG_LOG */
#if defined(CONFIG_LWM2M_CANCEL_OBSERVE_BY_PATH)
static int engine_remove_observer_by_path(struct lwm2m_obj_path *path)
{
struct observe_node *obs, *found_obj = NULL;
sys_snode_t *prev_node = NULL;
/* find the node index */
SYS_SLIST_FOR_EACH_CONTAINER(&engine_observer_list, obs, node) {
if (memcmp(path, &obs->path, sizeof(*path)) == 0) {
found_obj = obs;
break;
}
prev_node = &obs->node;
}
if (!found_obj) {
return -ENOENT;
}
LOG_INF("Removing observer for path %s", lwm2m_path_log_strdup(path));
sys_slist_remove(&engine_observer_list, prev_node, &found_obj->node);
(void)memset(found_obj, 0, sizeof(*found_obj));
return 0;
}
#endif /* CONFIG_LWM2M_CANCEL_OBSERVE_BY_PATH */
static void engine_remove_observer_by_id(uint16_t obj_id, int32_t obj_inst_id)
{
struct observe_node *obs, *tmp;
@ -3847,7 +3895,13 @@ static int handle_request(struct coap_packet *request,
/* remove observer */
r = engine_remove_observer(token, tkl);
if (r < 0) {
LOG_ERR("remove observe error: %d", r);
#if defined(CONFIG_LWM2M_CANCEL_OBSERVE_BY_PATH)
r = engine_remove_observer_by_path(&msg->path);
if (r < 0)
#endif /* CONFIG_LWM2M_CANCEL_OBSERVE_BY_PATH */
{
LOG_ERR("remove observe error: %d", r);
}
}
}