net: lwm2m: use security data for connections

In order to support bootstrap mode, we need to store server data
in the security / server objects.  Once the connection to the
bootstrap server is made, it will clear these objects and add
new server connection data.

Signed-off-by: Michael Scott <mike@foundries.io>
This commit is contained in:
Michael Scott 2019-01-25 21:43:52 -08:00 committed by Anas Nashif
parent 3ef993c88e
commit 54c10c04e5
6 changed files with 227 additions and 131 deletions

View file

@ -68,6 +68,13 @@ struct lwm2m_ctx {
k_thread_stack_t *dtls_stack;
size_t dtls_stack_len;
#endif
bool use_dtls;
/** Current security object index */
int sec_obj_inst;
/** Packet Flow Settings */
bool handle_separate_response;
};
typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id,
@ -220,8 +227,7 @@ int lwm2m_engine_set_res_data(char *pathstr, void *data_ptr, u16_t data_len,
int lwm2m_engine_get_res_data(char *pathstr, void **data_ptr, u16_t *data_len,
u8_t *data_flags);
int lwm2m_engine_start(struct lwm2m_ctx *client_ctx,
char *peer_str, u16_t peer_port);
int lwm2m_engine_start(struct lwm2m_ctx *client_ctx);
/* LWM2M RD Client */
@ -242,9 +248,7 @@ enum lwm2m_rd_client_event {
typedef void (*lwm2m_ctx_event_cb_t)(struct lwm2m_ctx *ctx,
enum lwm2m_rd_client_event event);
int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx,
char *peer_str, u16_t peer_port,
const char *ep_name,
lwm2m_ctx_event_cb_t event_cb);
void lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name,
lwm2m_ctx_event_cb_t event_cb);
#endif /* ZEPHYR_INCLUDE_NET_LWM2M_H_ */

View file

@ -25,6 +25,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#define CONFIG_NET_CONFIG_PEER_IPV6_ADDR ""
#endif
#if defined(CONFIG_NET_IPV6)
#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR
#elif defined(CONFIG_NET_IPV4)
#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR
#else
#error LwM2M requires either IPV6 or IPV4 support
#endif
#define WAIT_TIME K_SECONDS(10)
#define CONNECT_TIME K_SECONDS(10)
@ -207,8 +216,35 @@ static int firmware_block_received_cb(u16_t obj_inst_id,
static int lwm2m_setup(void)
{
struct float32_value float_value;
int ret;
char *server_url;
u16_t server_url_len;
u8_t server_url_flags;
/* setup SECURITY object */
/* Server URL */
ret = lwm2m_engine_get_res_data("0/0/0",
(void **)&server_url, &server_url_len,
&server_url_flags);
if (ret < 0) {
return ret;
}
/* TODO: add server port to URL */
snprintk(server_url, server_url_len, "coap%s//%s",
IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? "s:" : ":",
SERVER_ADDR);
/* Security Mode */
lwm2m_engine_set_u8("0/0/2",
IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? 0 : 3);
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
lwm2m_engine_set_string("0/0/3", (char *)client_psk_id);
lwm2m_engine_set_opaque("0/0/5",
(void *)client_psk, sizeof(client_psk));
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */
/* setup SERVER object */
/* setup DEVICE object */
@ -362,22 +398,7 @@ void main(void)
#endif /* CONFIG_NET_APP_DTLS */
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */
#if defined(CONFIG_NET_IPV6)
ret = lwm2m_rd_client_start(&client, CONFIG_NET_CONFIG_PEER_IPV6_ADDR,
CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD,
rd_client_event);
#elif defined(CONFIG_NET_IPV4)
ret = lwm2m_rd_client_start(&client, CONFIG_NET_CONFIG_PEER_IPV4_ADDR,
CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD,
rd_client_event);
#else
LOG_ERR("LwM2M client requires IPv4 or IPv6.");
ret = -EPROTONOSUPPORT;
#endif
if (ret < 0) {
LOG_ERR("LWM2M init LWM2M RD client error (%d)", ret);
return;
}
/* client.sec_obj_inst is 0 as a starting point */
lwm2m_rd_client_start(&client, CONFIG_BOARD, rd_client_event);
k_sem_take(&quit_lock, K_FOREVER);
}

View file

@ -15,8 +15,6 @@
/*
* TODO:
*
* - Use server / security object instance 0 for initial connection
* - Add DNS support for security uri parsing
* - BOOTSTRAP/DTLS cleanup
* - Handle WRITE_ATTRIBUTES (pmin=10&pmax=60)
* - Handle Resource ObjLink type
@ -3406,9 +3404,8 @@ error:
return 0;
}
void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
bool handle_separate_response,
udp_request_handler_cb_t udp_request_handler)
static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
udp_request_handler_cb_t udp_request_handler)
{
struct lwm2m_message *msg = NULL;
struct net_udp_hdr hdr, *udp_hdr;
@ -3495,7 +3492,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
* token id for all notifications), we have to use an
* additional flag to decide when to clear the reply callback.
*/
if (handle_separate_response && !tkl &&
if (client_ctx->handle_separate_response && !tkl &&
coap_header_get_type(&response) == COAP_TYPE_ACK) {
LOG_DBG("separated response, not removing reply");
return;
@ -3567,7 +3564,7 @@ static void udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt,
struct lwm2m_ctx,
net_app_ctx);
lwm2m_udp_receive(client_ctx, pkt, false, handle_request);
lwm2m_udp_receive(client_ctx, pkt, handle_request);
}
static void retransmit_request(struct k_work *work)
@ -3902,13 +3899,11 @@ static int setup_cert(struct net_app_ctx *app_ctx, void *cert)
}
#endif /* CONFIG_NET_APP_DTLS */
int lwm2m_engine_start(struct lwm2m_ctx *client_ctx,
char *peer_str, u16_t peer_port)
int lwm2m_net_app_start(struct lwm2m_ctx *client_ctx,
char *peer_str, u16_t peer_port)
{
struct sockaddr client_addr;
int ret = 0;
/* TODO: use security object for initial setup */
int ret;
/* setup the local client port */
(void)memset(&client_addr, 0, sizeof(client_addr));
@ -3931,8 +3926,6 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx,
goto error_start;
}
lwm2m_engine_context_init(client_ctx);
/* set net_app callbacks */
ret = net_app_set_cb(&client_ctx->net_app_ctx,
NULL, udp_receive, NULL, NULL);
@ -3942,20 +3935,22 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx,
}
#if defined(CONFIG_NET_APP_DTLS)
ret = net_app_client_tls(&client_ctx->net_app_ctx,
client_ctx->dtls_result_buf,
client_ctx->dtls_result_buf_len,
INSTANCE_INFO,
strlen(INSTANCE_INFO),
setup_cert,
client_ctx->cert_host,
NULL,
client_ctx->dtls_pool,
client_ctx->dtls_stack,
client_ctx->dtls_stack_len);
if (ret < 0) {
LOG_ERR("Cannot init DTLS (%d)", ret);
goto error_start;
if (client_ctx->use_dtls) {
ret = net_app_client_tls(&client_ctx->net_app_ctx,
client_ctx->dtls_result_buf,
client_ctx->dtls_result_buf_len,
INSTANCE_INFO,
strlen(INSTANCE_INFO),
setup_cert,
client_ctx->cert_host,
NULL,
client_ctx->dtls_pool,
client_ctx->dtls_stack,
client_ctx->dtls_stack_len);
if (ret < 0) {
LOG_ERR("Cannot init DTLS (%d)", ret);
goto error_start;
}
}
#endif
@ -3968,7 +3963,7 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx,
/* save remote addr */
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
if (client_ctx->net_app_ctx.dtls.ctx) {
if (client_ctx->use_dtls && client_ctx->net_app_ctx.dtls.ctx) {
memcpy(&client_ctx->remote_addr,
&client_ctx->net_app_ctx.dtls.ctx->remote,
sizeof(client_ctx->remote_addr));
@ -3979,7 +3974,6 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx,
&client_ctx->net_app_ctx.default_ctx->remote,
sizeof(client_ctx->remote_addr));
}
return 0;
error_start:
@ -3988,6 +3982,63 @@ error_start:
return ret;
}
int lwm2m_engine_start(struct lwm2m_ctx *client_ctx)
{
char pathstr[MAX_RESOURCE_LEN];
char *data_ptr, *peer_str;
u16_t peer_strlen;
u8_t peer_data_flags;
int ret = 0U;
/* get the server URL */
snprintk(pathstr, sizeof(pathstr), "0/%d/0", client_ctx->sec_obj_inst);
ret = lwm2m_engine_get_res_data(pathstr, (void **)&data_ptr,
&peer_strlen, &peer_data_flags);
if (ret < 0) {
return ret;
}
/* TODO: use http parser for URL to get protocol and server */
/* walk forward till colon shifting to lower case */
peer_str = data_ptr;
while (*peer_str != '\0' && *peer_str != ':') {
*peer_str = tolower(*peer_str);
peer_str += 1;
}
/* check to make sure there was a colon */
if (*peer_str != ':') {
return -EINVAL;
}
if (strncmp(data_ptr, "coap:", 5) != 0 &&
strncmp(data_ptr, "coaps:", 6) != 0) {
return -EPROTONOSUPPORT;
}
client_ctx->use_dtls = false;
if (strncmp(data_ptr, "coaps:", 6) == 0) {
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
client_ctx->use_dtls = true;
#else
return -EPROTONOSUPPORT;
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */
}
/* skip the colons and slashes */
while (*peer_str == ':' || *peer_str == '/') {
peer_str += 1;
}
LOG_DBG("URL: %s", data_ptr);
lwm2m_engine_context_init(client_ctx);
return lwm2m_net_app_start(client_ctx, peer_str,
CONFIG_LWM2M_PEER_PORT);
}
static int lwm2m_engine_init(struct device *dev)
{
(void)memset(block1_contexts, 0,

View file

@ -88,10 +88,6 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
struct lwm2m_engine_obj_field *obj_field,
struct lwm2m_message *msg);
void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
bool handle_separate_response,
udp_request_handler_cb_t udp_request_handler);
enum coap_block_size lwm2m_default_block_size(void);
int lwm2m_engine_add_service(void (*service)(void), u32_t period_ms);
@ -112,4 +108,8 @@ void lwm2m_firmware_set_update_result(u8_t result);
u8_t lwm2m_firmware_get_update_result(void);
#endif
/* Network API Layer */
int lwm2m_net_app_start(struct lwm2m_ctx *client_ctx,
char *peer_str, u16_t peer_port);
#endif /* LWM2M_ENGINE_H */

View file

@ -43,13 +43,6 @@ static char proxy_uri[URI_LEN];
static void do_transmit_timeout_cb(struct lwm2m_message *msg);
static void
firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt,
int status, void *user_data)
{
lwm2m_udp_receive(&firmware_ctx, pkt, true, NULL);
}
static void set_update_result_from_error(int error_code)
{
if (error_code == -ENOMEM) {
@ -409,7 +402,6 @@ static void do_transmit_timeout_cb(struct lwm2m_message *msg)
static void firmware_transfer(struct k_work *work)
{
struct sockaddr client_addr;
int ret, family;
u16_t off;
u16_t len;
@ -473,22 +465,11 @@ static void firmware_transfer(struct k_work *work)
tmp = server_addr[off + len];
server_addr[off + len] = '\0';
/* setup the local firmware download client port */
(void)memset(&client_addr, 0, sizeof(client_addr));
#if defined(CONFIG_NET_IPV6)
client_addr.sa_family = AF_INET6;
net_sin6(&client_addr)->sin6_port =
htons(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_LOCAL_PORT);
#elif defined(CONFIG_NET_IPV4)
client_addr.sa_family = AF_INET;
net_sin(&client_addr)->sin_port =
htons(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_LOCAL_PORT);
#endif
lwm2m_engine_context_init(&firmware_ctx);
firmware_ctx.handle_separate_response = true;
ret = net_app_init_udp_client(&firmware_ctx.net_app_ctx,
&client_addr, NULL,
&server_addr[off], parsed_uri.port,
firmware_ctx.net_init_timeout, NULL);
ret = lwm2m_net_app_start(&firmware_ctx, &server_addr[off],
parsed_uri.port);
server_addr[off + len] = tmp;
if (ret < 0) {
LOG_ERR("Could not get an UDP context (err:%d)", ret);
@ -499,38 +480,6 @@ static void firmware_transfer(struct k_work *work)
LOG_INF("Connecting to server %s, port %d", server_addr + off,
parsed_uri.port);
lwm2m_engine_context_init(&firmware_ctx);
/* set net_app callbacks */
ret = net_app_set_cb(&firmware_ctx.net_app_ctx, NULL,
firmware_udp_receive, NULL, NULL);
if (ret < 0) {
LOG_ERR("Could not set receive callback (err:%d)", ret);
/* make sure this sets RESULT_CONNECTION_LOST */
ret = -ENOMSG;
goto cleanup;
}
ret = net_app_connect(&firmware_ctx.net_app_ctx,
firmware_ctx.net_timeout);
if (ret < 0) {
LOG_ERR("Cannot connect UDP (%d)", ret);
goto cleanup;
}
/* save remote addr */
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
if (firmware_ctx.net_app_ctx.dtls.ctx) {
memcpy(&firmware_ctx.remote_addr,
&firmware_ctx.net_app_ctx.dtls.ctx->remote,
sizeof(firmware_ctx.remote_addr));
} else
#endif
{
memcpy(&firmware_ctx.remote_addr,
&firmware_ctx.net_app_ctx.default_ctx->remote,
sizeof(firmware_ctx.remote_addr));
}
/* reset block transfer context */
coap_block_transfer_init(&firmware_block_ctx,
lwm2m_default_block_size(), 0);

View file

@ -89,7 +89,7 @@ enum sm_engine_state {
};
struct lwm2m_rd_client_info {
u16_t lifetime;
u32_t lifetime;
struct lwm2m_ctx *ctx;
u8_t engine_state;
u8_t use_bootstrap;
@ -360,6 +360,69 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg)
sm_handle_timeout_state(msg, ENGINE_INIT);
}
static int sm_select_next_sec_inst(int *sec_obj_inst, u32_t *lifetime)
{
char pathstr[MAX_RESOURCE_LEN];
int ret, end, i, obj_inst_id, found = -1;
bool temp;
/* lookup existing index */
i = lwm2m_security_inst_id_to_index(*sec_obj_inst);
if (i < 0) {
*sec_obj_inst = -1;
i = -1;
}
/* store end marker, due to looping */
end = (i == -1 ? CONFIG_LWM2M_SECURITY_INSTANCE_COUNT : i);
/* loop through servers starting from the index after the current one */
for (i++; i != end; i++) {
if (i >= CONFIG_LWM2M_SECURITY_INSTANCE_COUNT) {
i = 0;
}
obj_inst_id = lwm2m_security_index_to_inst_id(i);
if (obj_inst_id < 0) {
continue;
}
snprintk(pathstr, sizeof(pathstr), "0/%d/1",
obj_inst_id);
ret = lwm2m_engine_get_bool(pathstr, &temp);
if (ret < 0) {
continue;
}
if (temp == false) {
found = obj_inst_id;
break;
}
}
if (found > -1) {
*sec_obj_inst = found;
/* query the lifetime */
/* TODO: use Short Server ID to link to server info */
snprintk(pathstr, sizeof(pathstr), "1/%d/1",
obj_inst_id);
if (lwm2m_engine_get_u32(pathstr, lifetime) < 0) {
*lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
LOG_DBG("Using default lifetime: %u", *lifetime);
}
}
if (*sec_obj_inst < 0) {
/* no servers found */
LOG_DBG("sec_obj_inst: NOT_FOUND");
return -ENOENT;
}
LOG_DBG("sec_obj_inst: %d", *sec_obj_inst);
return 0;
}
/* state machine step functions */
static int sm_do_init(void)
@ -590,9 +653,29 @@ static int sm_do_registration(void)
{
int ret = 0;
if (client.use_registration &&
!sm_is_registered() &&
client.has_registration_info) {
/* TODO: clear out connection data? */
ret = sm_select_next_sec_inst(&client.ctx->sec_obj_inst,
&client.lifetime);
if (ret < 0) {
set_sm_state(ENGINE_INIT);
return -EINVAL;
}
if (client.lifetime == 0) {
client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
}
LOG_INF("RD Client started with endpoint '%s' with client lifetime %d",
client.ep_name, client.lifetime);
ret = lwm2m_engine_start(client.ctx);
if (ret < 0) {
LOG_ERR("Cannot init LWM2M engine (%d)", ret);
return ret;
}
if (!sm_is_registered()) {
ret = sm_send_registration(true,
do_registration_reply_cb,
do_registration_timeout_cb);
@ -735,27 +818,15 @@ static void lwm2m_rd_client_service(void)
}
}
int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx,
char *peer_str, u16_t peer_port,
const char *ep_name,
lwm2m_ctx_event_cb_t event_cb)
void lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name,
lwm2m_ctx_event_cb_t event_cb)
{
int ret = 0;
ret = lwm2m_engine_start(client_ctx, peer_str, peer_port);
if (ret < 0) {
LOG_ERR("Cannot init LWM2M engine (%d)", ret);
return ret;
}
/* TODO: use server URI data from security */
client.ctx = client_ctx;
client.event_cb = event_cb;
set_sm_state(ENGINE_INIT);
strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1);
LOG_INF("LWM2M Client: %s", client.ep_name);
return 0;
}
static int lwm2m_rd_client_init(struct device *dev)