blob: cb22444575cd657ebfd3ba220aa26c9c66154370 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*******************************************************************************
2 *
3 * Copyright (c) 2013, 2014 Intel Corporation and others.
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * and Eclipse Distribution License v1.0 which accompany this distribution.
7 *
8 * The Eclipse Public License is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 * The Eclipse Distribution License is available at
11 * http://www.eclipse.org/org/documents/edl-v10.php.
12 *
13 * Contributors:
14 * David Navarro, Intel Corporation - initial API and implementation
15 * Fabien Fleutot - Please refer to git log
16 * Toby Jaffey - Please refer to git log
17 * Benjamin Cabé - Please refer to git log
18 * Bosch Software Innovations GmbH - Please refer to git log
19 * Pascal Rieux - Please refer to git log
20 *
21 *******************************************************************************/
22
23/*
24 Copyright (c) 2013, 2014 Intel Corporation
25
26 Redistribution and use in source and binary forms, with or without modification,
27 are permitted provided that the following conditions are met:
28
29 * Redistributions of source code must retain the above copyright notice,
30 this list of conditions and the following disclaimer.
31 * Redistributions in binary form must reproduce the above copyright notice,
32 this list of conditions and the following disclaimer in the documentation
33 and/or other materials provided with the distribution.
34 * Neither the name of Intel Corporation nor the names of its contributors
35 may be used to endorse or promote products derived from this software
36 without specific prior written permission.
37
38 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
39 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
40 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
46 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
47 THE POSSIBILITY OF SUCH DAMAGE.
48
49 David Navarro <david.navarro@intel.com>
50
51*/
52#include "internals.h"
53
54#ifdef LWM2M_CLIENT_MODE
55
56
57#include <stdlib.h>
58#include <string.h>
59#include <stdio.h>
60
61
62static lwm2m_object_t * prv_find_object(lwm2m_context_t * contextP,
63 uint16_t Id)
64{
65 int i;
66
67 if (
68#ifdef LWM2M_BOOTSTRAP
69 (contextP->bsState != BOOTSTRAP_PENDING) &&
70#endif
71 (Id == LWM2M_SECURITY_OBJECT_ID))
72 {
73 return NULL;
74 }
75
76 for (i = 0 ; i < contextP->numObject ; i++)
77 {
78 if (contextP->objectList[i]->objID == Id)
79 {
80 return contextP->objectList[i];
81 }
82 }
83
84 return NULL;
85}
86
87coap_status_t object_read(lwm2m_context_t * contextP,
88 lwm2m_uri_t * uriP,
89 uint8_t ** bufferP,
90 size_t * lengthP)
91{
92 coap_status_t result;
93 lwm2m_object_t * targetP;
94 lwm2m_tlv_t * tlvP = NULL;
95 int size = 0;
96
97#ifdef LWM2M_BOOTSTRAP
98 if (contextP->bsState == BOOTSTRAP_PENDING) return METHOD_NOT_ALLOWED_4_05;
99#endif
100
101 targetP = prv_find_object(contextP, uriP->objectId);
102 if (NULL == targetP) return NOT_FOUND_4_04;
103 if (NULL == targetP->readFunc) return METHOD_NOT_ALLOWED_4_05;
104 if (targetP->instanceList == NULL)
105 {
106 // this is a single instance object
107 if (LWM2M_URI_IS_SET_INSTANCE(uriP) && (uriP->instanceId != 0))
108 {
109 return COAP_404_NOT_FOUND;
110 }
111 }
112 else
113 {
114 if (LWM2M_URI_IS_SET_INSTANCE(uriP))
115 {
116 if (NULL == lwm2m_list_find(targetP->instanceList, uriP->instanceId))
117 {
118 return COAP_404_NOT_FOUND;
119 }
120 }
121 else
122 {
123 // multiple object instances read
124 lwm2m_list_t * instanceP;
125 int i;
126
127 size = 0;
128 for (instanceP = targetP->instanceList; instanceP != NULL ; instanceP = instanceP->next)
129 {
130 size++;
131 }
132
133 tlvP = lwm2m_tlv_new(size);
134 if (tlvP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
135
136 result = COAP_205_CONTENT;
137 instanceP = targetP->instanceList;
138 i = 0;
139 while (instanceP != NULL && result == COAP_205_CONTENT)
140 {
141 result = targetP->readFunc(instanceP->id, (int*)&(tlvP[i].length), (lwm2m_tlv_t **)&(tlvP[i].value), targetP);
142 tlvP[i].type = LWM2M_TYPE_OBJECT_INSTANCE;
143 tlvP[i].id = instanceP->id;
144 i++;
145 instanceP = instanceP->next;
146 }
147
148 if (result == COAP_205_CONTENT)
149 {
150 *lengthP = lwm2m_tlv_serialize(size, tlvP, bufferP);
151 if (*lengthP == 0) result = COAP_500_INTERNAL_SERVER_ERROR;
152 }
153 lwm2m_tlv_free(size, tlvP);
154
155 return result;
156 }
157 }
158
159 // single instance read
160 if (LWM2M_URI_IS_SET_RESOURCE(uriP))
161 {
162 size = 1;
163 tlvP = lwm2m_tlv_new(size);
164 if (tlvP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
165
166 tlvP->type = LWM2M_TYPE_RESOURCE;
167 tlvP->flags = LWM2M_TLV_FLAG_TEXT_FORMAT;
168 tlvP->id = uriP->resourceId;
169 }
170 result = targetP->readFunc(uriP->instanceId, &size, &tlvP, targetP);
171 if (result == COAP_205_CONTENT)
172 {
173 if (size == 1
174 && tlvP->type == LWM2M_TYPE_RESOURCE
175 && (tlvP->flags && LWM2M_TLV_FLAG_TEXT_FORMAT) != 0 )
176 {
177 *bufferP = (uint8_t *)malloc(tlvP->length);
178 if (*bufferP == NULL)
179 {
180 result = COAP_500_INTERNAL_SERVER_ERROR;
181 }
182 else
183 {
184 memcpy(*bufferP, tlvP->value, tlvP->length);
185 *lengthP = tlvP->length;
186 }
187 }
188 else
189 {
190 *lengthP = lwm2m_tlv_serialize(size, tlvP, bufferP);
191 if (*lengthP == 0) result = COAP_500_INTERNAL_SERVER_ERROR;
192 }
193 }
194 lwm2m_tlv_free(size, tlvP);
195
196 return result;
197}
198
199coap_status_t object_write(lwm2m_context_t * contextP,
200 lwm2m_uri_t * uriP,
201 uint8_t * buffer,
202 size_t length)
203{
204 coap_status_t result = NO_ERROR;
205 lwm2m_object_t * targetP;
206 lwm2m_tlv_t * tlvP = NULL;
207 int size = 0;
208
209 targetP = prv_find_object(contextP, uriP->objectId);
210 if (NULL == targetP)
211 {
212 result = NOT_FOUND_4_04;
213 }
214 else if (NULL == targetP->writeFunc)
215 {
216 result = METHOD_NOT_ALLOWED_4_05;
217 }
218 else
219 {
220 if (LWM2M_URI_IS_SET_RESOURCE(uriP))
221 {
222 size = 1;
223 tlvP = lwm2m_tlv_new(size);
224 if (tlvP == NULL)
225 {
226 return COAP_500_INTERNAL_SERVER_ERROR;
227 }
228
229 tlvP->flags = LWM2M_TLV_FLAG_TEXT_FORMAT | LWM2M_TLV_FLAG_STATIC_DATA;
230 tlvP->type = LWM2M_TYPE_RESOURCE;
231 tlvP->id = uriP->resourceId;
232 tlvP->length = length;
233 tlvP->value = (uint8_t *)buffer;
234 }
235 else
236 {
237 size = lwm2m_tlv_parse(buffer, length, &tlvP);
238 if (size == 0)
239 {
240 result = COAP_500_INTERNAL_SERVER_ERROR;
241 }
242 }
243 }
244 if (result == NO_ERROR)
245 {
246#ifdef LWM2M_BOOTSTRAP
247 if (contextP->bsState == BOOTSTRAP_PENDING)
248 {
249 tlvP->flags |= LWM2M_TLV_FLAG_BOOTSTRAPPING;
250 }
251#endif
252 result = targetP->writeFunc(uriP->instanceId, size, tlvP, targetP);
253 lwm2m_tlv_free(size, tlvP);
254 }
255#ifdef LWM2M_BOOTSTRAP
256 if (contextP->bsState == BOOTSTRAP_PENDING)
257 {
258 if (result == COAP_204_CHANGED)
259 {
260 reset_bootstrap_timer(contextP);
261 }
262 else
263 {
264 bootstrap_failed(contextP);
265 }
266 }
267#endif
268 return result;
269}
270
271coap_status_t object_execute(lwm2m_context_t * contextP,
272 lwm2m_uri_t * uriP,
273 uint8_t * buffer,
274 size_t length)
275{
276 lwm2m_object_t * targetP;
277
278#ifdef LWM2M_BOOTSTRAP
279 if (contextP->bsState == BOOTSTRAP_PENDING) return METHOD_NOT_ALLOWED_4_05;
280#endif
281
282 targetP = prv_find_object(contextP, uriP->objectId);
283 if (NULL == targetP) return NOT_FOUND_4_04;
284 if (NULL == targetP->executeFunc) return METHOD_NOT_ALLOWED_4_05;
285
286 return targetP->executeFunc(uriP->instanceId, uriP->resourceId, buffer, length, targetP);
287}
288
289coap_status_t object_create(lwm2m_context_t * contextP,
290 lwm2m_uri_t * uriP,
291 uint8_t * buffer,
292 size_t length)
293{
294 lwm2m_object_t * targetP;
295 lwm2m_tlv_t * tlvP = NULL;
296 int size = 0;
297 uint8_t result;
298
299 if (length == 0 || buffer == 0)
300 {
301 return BAD_REQUEST_4_00;
302 }
303
304 targetP = prv_find_object(contextP, uriP->objectId);
305 if (NULL == targetP) return NOT_FOUND_4_04;
306 if (NULL == targetP->createFunc) return METHOD_NOT_ALLOWED_4_05;
307
308 if (LWM2M_URI_IS_SET_INSTANCE(uriP))
309 {
310 if (NULL != lwm2m_list_find(targetP->instanceList, uriP->instanceId))
311 {
312 // Instance already exists
313 return COAP_406_NOT_ACCEPTABLE;
314 }
315 }
316 else
317 {
318 uriP->instanceId = lwm2m_list_newId(targetP->instanceList);
319 uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID;
320 }
321
322 size = lwm2m_tlv_parse(buffer, length, &tlvP);
323 if (size == 0) return COAP_500_INTERNAL_SERVER_ERROR;
324#ifdef LWM2M_BOOTSTRAP
325 if (contextP->bsState == BOOTSTRAP_PENDING)
326 {
327 tlvP->flags |= LWM2M_TLV_FLAG_BOOTSTRAPPING;
328 }
329#endif
330 result = targetP->createFunc(uriP->instanceId, size, tlvP, targetP);
331 lwm2m_tlv_free(size, tlvP);
332
333 return result;
334}
335
336coap_status_t object_delete(lwm2m_context_t * contextP,
337 lwm2m_uri_t * uriP)
338{
339 lwm2m_object_t * targetP;
340
341 targetP = prv_find_object(contextP, uriP->objectId);
342 if (NULL == targetP) return NOT_FOUND_4_04;
343 if (NULL == targetP->deleteFunc) return METHOD_NOT_ALLOWED_4_05;
344
345 LOG(" Call to object_delete\r\n");
346
347 return targetP->deleteFunc(uriP->instanceId, targetP);
348}
349
350bool object_isInstanceNew(lwm2m_context_t * contextP,
351 uint16_t objectId,
352 uint16_t instanceId)
353{
354 lwm2m_object_t * targetP;
355
356 targetP = prv_find_object(contextP, objectId);
357 if (targetP != NULL)
358 {
359 if (NULL != lwm2m_list_find(targetP->instanceList, instanceId))
360 {
361 return false;
362 }
363 }
364
365 return true;
366}
367
368int prv_getRegisterPayload(lwm2m_context_t * contextP,
369 uint8_t * buffer,
370 size_t length)
371{
372 int index;
373 int i;
374 int result;
375
376 // index can not be greater than length
377 index = 0;
378
379 if ((contextP->altPath != NULL)
380 && (contextP->altPath[0] != 0))
381 {
382 result = snprintf((char *)buffer, length, REG_ALT_PATH_LINK, contextP->altPath);
383 if (result > 0 && result <= length)
384 {
385 index = result;
386 }
387 else
388 {
389 return 0;
390 }
391 }
392 for (i = 0 ; i < contextP->numObject ; i++)
393 {
394 if (contextP->objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID) continue;
395
396 if (contextP->objectList[i]->instanceList == NULL)
397 {
398 result = snprintf((char *)buffer + index, length - index,
399 REG_OBJECT_PATH,
400 contextP->altPath?contextP->altPath:"", contextP->objectList[i]->objID);
401 if (result > 0 && result <= length - index)
402 {
403 index += result;
404 }
405 else
406 {
407 return 0;
408 }
409 }
410 else
411 {
412 lwm2m_list_t * targetP;
413 for (targetP = contextP->objectList[i]->instanceList ; targetP != NULL ; targetP = targetP->next)
414 {
415 result = snprintf((char *)buffer + index, length - index,
416 REG_OBJECT_INSTANCE_PATH,
417 contextP->altPath?contextP->altPath:"", contextP->objectList[i]->objID, targetP->id);
418 if (result > 0 && result <= length - index)
419 {
420 index += result;
421 }
422 else
423 {
424 return 0;
425 }
426 }
427 }
428 }
429
430 if (index > 0)
431 {
432 index = index - 1; // remove trailing ','
433 }
434
435 buffer[index] = 0;
436
437 return index;
438}
439
440static lwm2m_list_t * prv_findServerInstance(lwm2m_object_t * objectP,
441 uint16_t shortID)
442{
443 lwm2m_list_t * instanceP;
444
445 instanceP = objectP->instanceList;
446 while (NULL != instanceP)
447 {
448 int64_t value;
449 lwm2m_tlv_t * tlvP;
450 int size;
451
452 size = 1;
453 tlvP = lwm2m_tlv_new(size);
454 if (tlvP == NULL) return NULL;
455 tlvP->id = LWM2M_SERVER_SHORT_ID_ID;
456
457 if (objectP->readFunc(instanceP->id, &size, &tlvP, objectP) != COAP_205_CONTENT)
458 {
459 lwm2m_tlv_free(size, tlvP);
460 return NULL;
461 }
462
463 if (1 == lwm2m_tlv_decode_int(tlvP, &value))
464 {
465 if (value == shortID)
466 {
467 lwm2m_tlv_free(size, tlvP);
468 break;
469 }
470 }
471 lwm2m_tlv_free(size, tlvP);
472 instanceP = instanceP->next;
473 }
474
475 return instanceP;
476}
477
478static int prv_getMandatoryInfo(lwm2m_object_t * objectP,
479 uint16_t instanceID,
480 lwm2m_server_t * targetP)
481{
482 lwm2m_tlv_t * tlvP;
483 int size;
484 int64_t value;
485
486 size = 2;
487 tlvP = lwm2m_tlv_new(size);
488 if (tlvP == NULL) return -1;
489 tlvP[0].id = LWM2M_SERVER_LIFETIME_ID;
490 tlvP[1].id = LWM2M_SERVER_BINDING_ID;
491
492 if (objectP->readFunc(instanceID, &size, &tlvP, objectP) != COAP_205_CONTENT)
493 {
494 lwm2m_tlv_free(size, tlvP);
495 return -1;
496 }
497
498 if (0 == lwm2m_tlv_decode_int(tlvP, &value)
499 || value < 0 || value >0xFFFFFFFF) // This is an implementation limit
500 {
501 lwm2m_tlv_free(size, tlvP);
502 return -1;
503 }
504 targetP->lifetime = value;
505
506 targetP->binding = lwm2m_stringToBinding(tlvP[1].value, tlvP[1].length);
507
508 lwm2m_tlv_free(size, tlvP);
509
510 if (targetP->binding == BINDING_UNKNOWN)
511 {
512 return -1;
513 }
514
515 return 0;
516}
517
518int object_getServers(lwm2m_context_t * contextP)
519{
520 lwm2m_object_t * securityObjP = NULL;
521 lwm2m_object_t * serverObjP = NULL;
522 lwm2m_list_t * securityInstP; // instanceID of the server in the LWM2M Security Object
523 int i;
524
525 for (i = 0 ; i < contextP->numObject ; i++)
526 {
527 if (contextP->objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID)
528 {
529 securityObjP = contextP->objectList[i];
530 }
531 else if (contextP->objectList[i]->objID == LWM2M_SERVER_OBJECT_ID)
532 {
533 serverObjP = contextP->objectList[i];
534 }
535 }
536
537 if (NULL == securityObjP) return -1;
538
539 securityInstP = securityObjP->instanceList;
540 while (securityInstP != NULL)
541 {
542 lwm2m_tlv_t * tlvP;
543 int size;
544 lwm2m_server_t * targetP;
545 bool isBootstrap;
546 int64_t value = 0;
547
548 size = 3;
549 tlvP = lwm2m_tlv_new(size);
550 if (tlvP == NULL) return -1;
551 tlvP[0].id = LWM2M_SECURITY_BOOTSTRAP_ID;
552 tlvP[1].id = LWM2M_SECURITY_SHORT_SERVER_ID;
553 tlvP[2].id = LWM2M_SECURITY_HOLD_OFF_ID;
554
555 if (securityObjP->readFunc(securityInstP->id, &size, &tlvP, securityObjP) != COAP_205_CONTENT)
556 {
557 lwm2m_tlv_free(size, tlvP);
558 return -1;
559 }
560
561 targetP = (lwm2m_server_t *)lwm2m_malloc(sizeof(lwm2m_server_t));
562 if (targetP == NULL) {
563 lwm2m_tlv_free(size, tlvP);
564 return -1;
565 }
566 memset(targetP, 0, sizeof(lwm2m_server_t));
567 targetP->secObjInstID = securityInstP->id;
568
569 if (0 == lwm2m_tlv_decode_bool(tlvP + 0, &isBootstrap))
570 {
571 lwm2m_free(targetP);
572 lwm2m_tlv_free(size, tlvP);
573 return -1;
574 }
575
576 if (0 == lwm2m_tlv_decode_int(tlvP + 1, &value)
577 || value < (isBootstrap ? 0 : 1) || value > 0xFFFF) // 0 is forbidden as a Short Server ID
578 {
579 lwm2m_free(targetP);
580 lwm2m_tlv_free(size, tlvP);
581 return -1;
582 }
583 targetP->shortID = value;
584
585 if (isBootstrap == true)
586 {
587 if (0 == lwm2m_tlv_decode_int(tlvP + 2, &value)
588 || value < 0 || value > 0xFFFFFFFF) // This is an implementation limit
589 {
590 lwm2m_free(targetP);
591 lwm2m_tlv_free(size, tlvP);
592 return -1;
593 }
594 // lifetime of a bootstrap server is set to ClientHoldOffTime
595 targetP->lifetime = value;
596
597 contextP->bootstrapServerList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->bootstrapServerList, targetP);
598 }
599 else
600 {
601 lwm2m_list_t * serverInstP; // instanceID of the server in the LWM2M Server Object
602
603 serverInstP = prv_findServerInstance(serverObjP, targetP->shortID);
604 if (serverInstP == NULL)
605 {
606 lwm2m_free(targetP);
607 lwm2m_tlv_free(size, tlvP);
608 return -1;
609 }
610 if (0 != prv_getMandatoryInfo(serverObjP, serverInstP->id, targetP))
611 {
612 lwm2m_free(targetP);
613 lwm2m_tlv_free(size, tlvP);
614 return -1;
615 }
616 targetP->status = STATE_DEREGISTERED;
617 contextP->serverList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->serverList, targetP);
618 }
619 lwm2m_tlv_free(size, tlvP);
620 securityInstP = securityInstP->next;
621 }
622
623 return 0;
624}
625
626#endif