56 #include "lwm2m-security.h" 65 #if LWM2M_QUEUE_MODE_ENABLED 72 #define LOG_MODULE "lwm2m-rd" 73 #define LOG_LEVEL LOG_LEVEL_LWM2M 75 #ifndef LWM2M_DEFAULT_CLIENT_LIFETIME 76 #define LWM2M_DEFAULT_CLIENT_LIFETIME 30 79 #define MAX_RD_UPDATE_WAIT 5000 81 #define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) 82 #define BS_REMOTE_PORT UIP_HTONS(5685) 84 #define STATE_MACHINE_UPDATE_INTERVAL 500 86 static struct lwm2m_session_info session_info;
87 static coap_request_state_t rd_request_state;
89 static coap_message_t request[1];
96 #define WAIT_NETWORK 1 97 #define DO_BOOTSTRAP 3 98 #define BOOTSTRAP_SENT 4 99 #define BOOTSTRAP_DONE 5 100 #define DO_REGISTRATION 6 101 #define REGISTRATION_SENT 7 102 #define REGISTRATION_DONE 8 103 #define UPDATE_SENT 9 104 #define DEREGISTER 10 105 #define DEREGISTER_SENT 11 106 #define DEREGISTER_FAILED 12 107 #define DEREGISTERED 13 108 #if LWM2M_QUEUE_MODE_ENABLED 109 #define QUEUE_MODE_AWAKE 14 110 #define QUEUE_MODE_SEND_UPDATE 15 113 #define FLAG_RD_DATA_DIRTY 0x01 114 #define FLAG_RD_DATA_UPDATE_TRIGGERED 0x02 115 #define FLAG_RD_DATA_UPDATE_ON_DIRTY 0x10 117 static uint8_t rd_state = 0;
118 static uint8_t rd_flags = FLAG_RD_DATA_UPDATE_ON_DIRTY;
119 static uint64_t wait_until_network_check = 0;
120 static uint64_t last_update;
121 static uint64_t last_rd_progress = 0;
123 static char query_data[64];
124 static uint8_t rd_data[128];
126 static uint32_t rd_block1;
127 static uint8_t rd_more;
128 static coap_timer_t rd_timer;
129 static void (*rd_callback)(coap_request_state_t *state);
131 static coap_timer_t block1_timer;
133 #if LWM2M_QUEUE_MODE_ENABLED 134 static coap_timer_t queue_mode_client_awake_timer;
137 static uint8_t queue_mode_client_awake;
140 static uint16_t queue_mode_client_awake_time;
142 static void queue_mode_awake_timer_callback(coap_timer_t *
timer);
145 static void check_periodic_observations();
146 static void update_callback(coap_request_state_t *state);
149 set_rd_data(coap_message_t *request)
151 lwm2m_buffer_t outbuf;
154 outbuf.buffer = rd_data;
155 outbuf.size =
sizeof(rd_data);
159 rd_more = lwm2m_engine_set_rd_data(&outbuf, 0);
160 coap_set_payload(request, rd_data, outbuf.len);
164 LOG_DBG(
"Setting block1 in request\n");
165 coap_set_header_block1(request, 0, 1,
sizeof(rd_data));
171 prepare_update(coap_message_t *request,
int triggered)
173 coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0);
174 coap_set_header_uri_path(request, session_info.assigned_ep);
176 snprintf(query_data,
sizeof(query_data) - 1,
"?lt=%d&b=%s", session_info.lifetime, session_info.binding);
177 LOG_DBG(
"UPDATE:%s %s\n", session_info.assigned_ep, query_data);
178 coap_set_header_uri_query(request, query_data);
180 if((triggered || rd_flags & FLAG_RD_DATA_UPDATE_ON_DIRTY) && (rd_flags & FLAG_RD_DATA_DIRTY)) {
181 rd_flags &= ~FLAG_RD_DATA_DIRTY;
182 set_rd_data(request);
183 rd_callback = update_callback;
188 has_network_access(
void)
190 #if UIP_CONF_IPV6_RPL 192 #ifndef CONTIKI_TARGET_NATIVE 202 lwm2m_rd_client_is_registered(
void)
204 return rd_state == REGISTRATION_DONE || rd_state == UPDATE_SENT;
208 lwm2m_rd_client_use_bootstrap_server(
int use)
210 session_info.use_bootstrap = use != 0;
211 if(session_info.use_bootstrap) {
218 lwm2m_rd_client_set_session_callback(session_callback_t cb)
220 session_info.callback = cb;
224 perform_session_callback(
int state)
226 if(session_info.callback != NULL) {
227 LOG_DBG(
"Performing session callback: %d cb:%p\n",
228 state, session_info.callback);
229 session_info.callback(&session_info, state);
234 lwm2m_rd_client_use_registration_server(
int use)
236 session_info.use_registration = use != 0;
237 if(session_info.use_registration) {
243 lwm2m_rd_client_get_lifetime(
void)
245 return session_info.lifetime;
249 lwm2m_rd_client_set_lifetime(uint16_t lifetime)
252 session_info.lifetime = lifetime;
254 session_info.lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME;
259 lwm2m_rd_client_set_update_rd(
void)
261 rd_flags |= FLAG_RD_DATA_DIRTY;
265 lwm2m_rd_client_set_automatic_update(
int update)
267 rd_flags = (rd_flags & ~FLAG_RD_DATA_UPDATE_ON_DIRTY) |
268 (update != 0 ? FLAG_RD_DATA_UPDATE_ON_DIRTY : 0);
272 lwm2m_rd_client_register_with_server(
const coap_endpoint_t *server)
275 session_info.has_registration_server_info = 1;
276 session_info.registered = 0;
277 if(session_info.use_registration) {
283 update_registration_server(
void)
285 if(session_info.has_registration_server_info) {
289 #if UIP_CONF_IPV6_RPL 308 lwm2m_rd_client_register_with_bootstrap_server(
const coap_endpoint_t *server)
311 session_info.has_bs_server_info = 1;
312 session_info.bootstrapped = 0;
313 session_info.registered = 0;
314 if(session_info.use_bootstrap) {
320 lwm2m_rd_client_deregister(
void)
322 if(lwm2m_rd_client_is_registered()) {
323 rd_state = DEREGISTER;
331 lwm2m_rd_client_update_triggered(
void)
333 rd_flags |= FLAG_RD_DATA_UPDATE_TRIGGERED;
338 update_bootstrap_server(
void)
340 if(session_info.has_bs_server_info) {
344 #if UIP_CONF_IPV6_RPL 373 bootstrap_callback(coap_request_state_t *state)
375 LOG_DBG(
"Bootstrap callback Response: %d, ", state->response != NULL);
376 if(state->response) {
377 if(CHANGED_2_04 == state->response->code) {
378 LOG_DBG_(
"Considered done!\n");
379 rd_state = BOOTSTRAP_DONE;
383 LOG_DBG_(
"Failed with code %d. Retrying\n", state->response->code);
386 }
else if(BOOTSTRAP_SENT == rd_state) {
388 LOG_DBG(
"Bootstrap failed! Retry?");
389 rd_state = DO_BOOTSTRAP;
396 produce_more_rd(
void)
398 lwm2m_buffer_t outbuf;
400 LOG_DBG(
"GOT Continue!\n");
403 outbuf.buffer = rd_data;
404 outbuf.size =
sizeof(rd_data);
410 rd_more = lwm2m_engine_set_rd_data(&outbuf, rd_block1);
411 coap_set_payload(request, rd_data, outbuf.len);
413 LOG_DBG(
"Setting block1 in request - block: %d more: %d\n",
414 (
int)rd_block1, (
int)rd_more);
415 coap_set_header_block1(request, rd_block1, rd_more,
sizeof(rd_data));
417 coap_send_request(&rd_request_state, &session_info.server_ep, request, rd_callback);
421 block1_rd_callback(coap_timer_t *
timer)
430 registration_callback(coap_request_state_t *state)
432 LOG_DBG(
"Registration callback. Response: %d, ", state->response != NULL);
433 if(state->response) {
436 if(CONTINUE_2_31 == state->response->code) {
438 coap_get_header_block1(state->response, &rd_block1, NULL, NULL, NULL);
441 LOG_DBG_(
"Continue\n");
442 }
else if(CREATED_2_01 == state->response->code) {
443 if(state->response->location_path_len < LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN) {
444 memcpy(session_info.assigned_ep, state->response->location_path,
445 state->response->location_path_len);
446 session_info.assigned_ep[state->response->location_path_len] = 0;
448 #if LWM2M_QUEUE_MODE_ENABLED 449 #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION 450 if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) {
451 lwm2m_queue_mode_set_first_request();
454 lwm2m_rd_client_fsm_execute_queue_mode_awake();
456 rd_state = REGISTRATION_DONE;
460 LOG_DBG_(
"Done (assigned EP='%s')!\n", session_info.assigned_ep);
461 perform_session_callback(LWM2M_RD_CLIENT_REGISTERED);
465 LOG_DBG_(
"failed to handle assigned EP: '");
466 LOG_DBG_COAP_STRING(state->response->location_path,
467 state->response->location_path_len);
468 LOG_DBG_(
"'. Re-init network.\n");
471 LOG_DBG_(
"failed with code %d. Re-init network\n", state->response->code);
478 LOG_DBG_(
"Ignore\n");
486 update_callback(coap_request_state_t *state)
488 LOG_DBG(
"Update callback. Response: %d, ", state->response != NULL);
490 if(state->response) {
492 if(CONTINUE_2_31 == state->response->code) {
494 LOG_DBG_(
"Continue\n");
495 coap_get_header_block1(state->response, &rd_block1, NULL, NULL, NULL);
498 }
else if(CHANGED_2_04 == state->response->code) {
502 #if LWM2M_QUEUE_MODE_ENABLED 504 if(lwm2m_queue_mode_is_waked_up_by_notification()) {
506 lwm2m_queue_mode_clear_waked_up_by_notification();
507 lwm2m_notification_queue_send_notifications();
509 #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION 510 if(lwm2m_queue_mode_get_dynamic_adaptation_flag()) {
511 lwm2m_queue_mode_set_first_request();
514 lwm2m_rd_client_fsm_execute_queue_mode_awake();
516 rd_state = REGISTRATION_DONE;
517 rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED;
521 LOG_DBG_(
"Failed with code %d. Retrying registration\n",
522 state->response->code);
523 rd_state = DO_REGISTRATION;
533 deregister_callback(coap_request_state_t *state)
535 LOG_DBG(
"Deregister callback. Response Code: %d\n",
536 state->response != NULL ? state->response->code : 0);
538 if(state->response && (DELETED_2_02 == state->response->code)) {
539 LOG_DBG(
"Deregistration success\n");
540 rd_state = DEREGISTERED;
541 perform_session_callback(LWM2M_RD_CLIENT_DEREGISTERED);
543 LOG_DBG(
"Deregistration failed\n");
544 if(rd_state == DEREGISTER_SENT) {
545 rd_state = DEREGISTER_FAILED;
546 perform_session_callback(LWM2M_RD_CLIENT_DEREGISTER_FAILED);
552 recover_from_rd_delay(
void)
560 periodic_process(coap_timer_t *
timer)
565 #if LWM2M_QUEUE_MODE_ENABLED 567 if(!((rd_state & 0xF) == 0xE)) {
576 LOG_DBG(
"RD Client - state: %d, ms: %lu\n", rd_state,
581 LOG_DBG(
"RD Client started with endpoint '%s' and client lifetime %d\n", session_info.ep, session_info.lifetime);
582 rd_state = WAIT_NETWORK;
585 if(now > wait_until_network_check) {
587 LOG_DBG(
"Checking for network... %lu\n",
588 (
unsigned long)wait_until_network_check);
589 wait_until_network_check = now + 10000;
590 if(has_network_access()) {
592 if(session_info.use_bootstrap) {
593 rd_state = DO_BOOTSTRAP;
595 rd_state = DO_REGISTRATION;
602 if(session_info.use_bootstrap && session_info.bootstrapped == 0) {
603 if(update_bootstrap_server()) {
605 coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0);
606 coap_set_header_uri_path(request,
"/bs");
608 snprintf(query_data,
sizeof(query_data) - 1,
"?ep=%s", session_info.ep);
609 coap_set_header_uri_query(request, query_data);
610 LOG_INFO(
"Registering ID with bootstrap server [");
611 LOG_INFO_COAP_EP(&session_info.bs_server_ep);
612 LOG_INFO_(
"] as '%s'\n", query_data);
615 request, bootstrap_callback);
617 rd_state = BOOTSTRAP_SENT;
626 if(session_info.use_bootstrap) {
627 lwm2m_security_server_t *security;
628 LOG_DBG(
"*** Bootstrap - checking for server info...\n");
630 for(security = lwm2m_security_get_first();
632 security = lwm2m_security_get_next(security)) {
633 if(security->bootstrap == 0) {
638 if(security != NULL) {
640 if(security->server_uri_len > 0) {
643 LOG_DBG(
"**** Found security instance using: ");
644 LOG_DBG_COAP_STRING((
const char *)security->server_uri,
645 security->server_uri_len);
646 LOG_DBG_(
" (len %d) \n", security->server_uri_len);
649 secure = strncmp((
const char *)security->server_uri,
653 security->server_uri_len,
654 &session_info.server_ep)) {
655 LOG_DBG(
"Failed to parse server URI!\n");
657 LOG_DBG(
"Server address:");
658 LOG_DBG_COAP_EP(&session_info.server_ep);
661 LOG_DBG(
"Secure CoAP requested but not supported - can not bootstrap\n");
663 lwm2m_rd_client_register_with_server(&session_info.server_ep);
664 session_info.bootstrapped++;
668 LOG_DBG(
"** failed to parse URI ");
669 LOG_DBG_COAP_STRING((
const char *)security->server_uri,
670 security->server_uri_len);
676 if(session_info.bootstrapped == 0) {
678 rd_state = DO_BOOTSTRAP;
680 rd_state = DO_REGISTRATION;
684 case DO_REGISTRATION:
688 LOG_DBG(
"Wait until connected... \n");
691 if(session_info.use_registration && !session_info.registered &&
692 update_registration_server()) {
696 coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0);
697 coap_set_header_uri_path(request,
"/rd");
699 snprintf(query_data,
sizeof(query_data) - 1,
"?ep=%s<=%d&b=%s", session_info.ep, session_info.lifetime, session_info.binding);
700 coap_set_header_uri_query(request, query_data);
702 len = set_rd_data(request);
703 rd_callback = registration_callback;
705 LOG_INFO(
"Registering with [");
706 LOG_INFO_COAP_EP(&session_info.server_ep);
707 LOG_INFO_(
"] lwm2m endpoint '%s': '", query_data);
709 LOG_INFO_COAP_STRING((
const char *)rd_data, len);
711 LOG_INFO_(
"' More:%d\n", rd_more);
714 request, registration_callback);
716 rd_state = REGISTRATION_SENT;
719 case REGISTRATION_SENT:
723 recover_from_rd_delay();
726 case REGISTRATION_DONE:
729 check_periodic_observations();
732 if((rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED) ||
733 ((uint32_t)session_info.lifetime * 500) <= now - last_update) {
735 prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED);
739 rd_state = UPDATE_SENT;
742 #if LWM2M_QUEUE_MODE_ENABLED 743 case QUEUE_MODE_AWAKE:
744 LOG_DBG(
"Queue Mode: Client is AWAKE at %lu\n", (
unsigned long)
coap_timer_uptime());
745 queue_mode_client_awake = 1;
746 queue_mode_client_awake_time = lwm2m_queue_mode_get_awake_time();
747 coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time);
749 case QUEUE_MODE_SEND_UPDATE:
753 #ifdef LWM2M_QUEUE_MODE_WAKE_UP 754 LWM2M_QUEUE_MODE_WAKE_UP();
756 prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED);
760 rd_state = UPDATE_SENT;
768 recover_from_rd_delay();
772 LOG_INFO(
"DEREGISTER %s\n", session_info.assigned_ep);
773 coap_init_message(request, COAP_TYPE_CON, COAP_DELETE, 0);
774 coap_set_header_uri_path(request, session_info.assigned_ep);
776 deregister_callback);
777 rd_state = DEREGISTER_SENT;
779 case DEREGISTER_SENT:
781 case DEREGISTER_FAILED:
787 LOG_WARN(
"Unhandled state: %d\n", rd_state);
792 lwm2m_rd_client_init(
const char *ep)
794 session_info.ep = ep;
796 #if LWM2M_QUEUE_MODE_ENABLED 797 session_info.binding =
"UQ";
801 session_info.lifetime = (LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2;
803 session_info.binding =
"U";
804 if(session_info.lifetime == 0) {
805 session_info.lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME;
814 #if LWM2M_QUEUE_MODE_ENABLED 820 check_periodic_observations(
void)
828 #if LWM2M_QUEUE_MODE_ENABLED 831 lwm2m_rd_client_restart_client_awake_timer(
void)
833 coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time);
837 lwm2m_rd_client_is_client_awake(
void)
839 return queue_mode_client_awake;
843 queue_mode_awake_timer_callback(coap_timer_t *timer)
846 LOG_DBG(
"Queue Mode: Client is SLEEPING at %lu\n", (
unsigned long)
coap_timer_uptime());
847 queue_mode_client_awake = 0;
850 #ifdef LWM2M_QUEUE_MODE_SLEEP_MS 851 LWM2M_QUEUE_MODE_SLEEP_MS(lwm2m_queue_mode_get_sleep_time());
853 rd_state = QUEUE_MODE_SEND_UPDATE;
858 lwm2m_rd_client_fsm_execute_queue_mode_awake()
861 rd_state = QUEUE_MODE_AWAKE;
862 periodic_process(&rd_timer);
866 lwm2m_rd_client_fsm_execute_queue_mode_update()
869 rd_state = QUEUE_MODE_SEND_UPDATE;
870 periodic_process(&rd_timer);
Header file for the LWM2M object API
API to address CoAP endpoints
CoAP engine implementation.
int coap_endpoint_connect(coap_endpoint_t *ep)
Request a connection to a CoAP endpoint.
Header file for the Contiki OMA LWM2M plain text reader / writer
int coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep)
Parse a CoAP endpoint.
static void coap_timer_set_callback(coap_timer_t *timer, void(*callback)(coap_timer_t *))
Set a callback function to be called when a CoAP timer expires.
Header file for functions to manage the queue to store notifications when waiting for the respons...
void coap_timer_reset(coap_timer_t *timer, uint64_t time)
Reset a CoAP timer to expire a specified time after the last expiration time.
Header file for the Contiki OMA LWM2M device
Header file for the Contiki OMA LWM2M JSON writer
int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint, coap_message_t *request, void(*callback)(coap_request_state_t *state))
Send a CoAP request to a remote endpoint.
rpl_dag_t * rpl_get_any_dag(void)
Returns pointer to any DAG (for compatibility with legagy RPL code)
Header file for the Contiki OMA LWM2M Registration and Bootstrap Client.
static uint64_t coap_timer_uptime(void)
Get the time since boot in milliseconds.
Header file for the Contiki OMA LWM2M Queue Mode implementation to manage the parameters ...
Callback API for doing CoAP requests Adapted from the blocking API
void coap_endpoint_copy(coap_endpoint_t *dest, const coap_endpoint_t *src)
Copy a CoAP endpoint from one memory area to another.
Header file for the Contiki OMA LWM2M engine
void coap_timer_stop(coap_timer_t *timer)
Stop a pending CoAP timer.
An implementation of the Constrained Application Protocol (RFC 7252).
void coap_timer_set(coap_timer_t *timer, uint64_t time)
Set a CoAP timer to expire after the specified time.
int coap_endpoint_is_connected(const coap_endpoint_t *ep)
Check if a CoAP endpoint is connected.