mesh: Rename mesh-db.c to mesh-config-json.c
[platform/upstream/bluez.git] / mesh / mesh-config-json.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2018-2019  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2.1 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
25 #define _GNU_SOURCE
26 #endif
27 #include <errno.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <ell/ell.h>
32 #include <json-c/json.h>
33
34 #include "mesh/mesh-defs.h"
35 #include "mesh/util.h"
36 #include "mesh/mesh-config.h"
37
38 #define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
39
40 static bool get_int(json_object *jobj, const char *keyword, int *value)
41 {
42         json_object *jvalue;
43
44         if (!json_object_object_get_ex(jobj, keyword, &jvalue))
45                 return false;
46
47         *value = json_object_get_int(jvalue);
48         if (errno == EINVAL)
49                 return false;
50
51         return true;
52 }
53
54 static bool add_u64_value(json_object *jobject, const char *desc,
55                                         const uint8_t u64[8])
56 {
57         json_object *jstring;
58         char hexstr[17];
59
60         hex2str((uint8_t *) u64, 8, hexstr, 17);
61         jstring = json_object_new_string(hexstr);
62         if (!jstring)
63                 return false;
64
65         json_object_object_add(jobject, desc, jstring);
66         return true;
67 }
68
69 static bool add_key_value(json_object *jobject, const char *desc,
70                                         const uint8_t key[16])
71 {
72         json_object *jstring;
73         char hexstr[33];
74
75         hex2str((uint8_t *) key, 16, hexstr, 33);
76         jstring = json_object_new_string(hexstr);
77         if (!jstring)
78                 return false;
79
80         json_object_object_add(jobject, desc, jstring);
81         return true;
82 }
83
84 static int get_element_index(json_object *jnode, uint16_t ele_addr)
85 {
86         json_object *jvalue, *jelements;
87         uint16_t addr, num_ele;
88         char *str;
89
90         if (!json_object_object_get_ex(jnode, "unicastAddress", &jvalue))
91                 return -1;
92
93         str = (char *)json_object_get_string(jvalue);
94         if (sscanf(str, "%04hx", &addr) != 1)
95                 return -1;
96
97         if (!json_object_object_get_ex(jnode, "elements", &jelements))
98                 return -1;
99
100         num_ele = json_object_array_length(jelements);
101
102         if (ele_addr >= addr + num_ele || ele_addr < addr)
103                 return -1;
104
105         return ele_addr - addr;
106 }
107
108 static json_object *get_element_model(json_object *jnode, int ele_idx,
109                                                 uint32_t mod_id, bool vendor)
110 {
111         json_object *jelements, *jelement, *jmodels;
112         int i, num_mods;
113         size_t len;
114         char buf[9];
115
116         if (!vendor)
117                 snprintf(buf, 5, "%4.4x", (uint16_t)mod_id);
118         else
119                 snprintf(buf, 9, "%8.8x", mod_id);
120
121         if (!json_object_object_get_ex(jnode, "elements", &jelements))
122                 return NULL;
123
124         jelement = json_object_array_get_idx(jelements, ele_idx);
125         if (!jelement)
126                 return NULL;
127
128         if (!json_object_object_get_ex(jelement, "models", &jmodels))
129                 return NULL;
130
131         num_mods = json_object_array_length(jmodels);
132         if (!num_mods)
133                 return NULL;
134
135         if (!vendor) {
136                 snprintf(buf, 5, "%4.4x", mod_id);
137                 len = 4;
138         } else {
139                 snprintf(buf, 9, "%8.8x", mod_id);
140                 len = 8;
141         }
142
143         for (i = 0; i < num_mods; ++i) {
144                 json_object *jmodel, *jvalue;
145                 char *str;
146
147                 jmodel = json_object_array_get_idx(jmodels, i);
148                 if (!json_object_object_get_ex(jmodel, "modelId", &jvalue))
149                         return NULL;
150
151                 str = (char *)json_object_get_string(jvalue);
152                 if (!str)
153                         return NULL;
154
155                 if (!strncmp(str, buf, len))
156                         return jmodel;
157         }
158
159         return NULL;
160 }
161
162 static bool jarray_has_string(json_object *jarray, char *str, size_t len)
163 {
164         int i, sz = json_object_array_length(jarray);
165
166         for (i = 0; i < sz; ++i) {
167                 json_object *jentry;
168                 char *str_entry;
169
170                 jentry = json_object_array_get_idx(jarray, i);
171                 str_entry = (char *)json_object_get_string(jentry);
172                 if (!str_entry)
173                         continue;
174
175                 if (!strncmp(str, str_entry, len))
176                         return true;
177         }
178
179         return false;
180 }
181
182 static json_object *jarray_string_del(json_object *jarray, char *str,
183                                                                 size_t len)
184 {
185         int i, sz = json_object_array_length(jarray);
186         json_object *jarray_new;
187
188         jarray_new = json_object_new_array();
189         if (!jarray_new)
190                 return NULL;
191
192         for (i = 0; i < sz; ++i) {
193                 json_object *jentry;
194                 char *str_entry;
195
196                 jentry = json_object_array_get_idx(jarray, i);
197                 str_entry = (char *)json_object_get_string(jentry);
198                 if (str_entry && !strncmp(str, str_entry, len))
199                         continue;
200
201                 json_object_get(jentry);
202                 json_object_array_add(jarray_new, jentry);
203         }
204
205         return jarray_new;
206 }
207
208 static json_object *get_key_object(json_object *jarray, uint16_t idx)
209 {
210         int i, sz = json_object_array_length(jarray);
211
212         for (i = 0; i < sz; ++i) {
213                 json_object *jentry, *jvalue;
214                 uint32_t jidx;
215
216                 jentry = json_object_array_get_idx(jarray, i);
217                 if (!json_object_object_get_ex(jentry, "index", &jvalue))
218                         return NULL;
219
220                 jidx = json_object_get_int(jvalue);
221
222                 if (jidx == idx)
223                         return jentry;
224         }
225
226         return NULL;
227 }
228
229 static json_object *jarray_key_del(json_object *jarray, int16_t idx)
230 {
231         json_object *jarray_new;
232         int i, sz = json_object_array_length(jarray);
233
234         jarray_new = json_object_new_array();
235         if (!jarray_new)
236                 return NULL;
237
238         for (i = 0; i < sz; ++i) {
239                 json_object *jentry, *jvalue;
240
241                 jentry = json_object_array_get_idx(jarray, i);
242
243                 if (json_object_object_get_ex(jentry, "index", &jvalue)) {
244                         int tmp = json_object_get_int(jvalue);
245
246                         if (tmp == idx)
247                                 continue;
248                 }
249
250                 json_object_get(jentry);
251                 json_object_array_add(jarray_new, jentry);
252         }
253
254         return jarray_new;
255 }
256
257 bool mesh_db_read_iv_index(json_object *jobj, uint32_t *idx, bool *update)
258 {
259         int tmp;
260
261         /* IV index */
262         if (!get_int(jobj, "IVindex", &tmp))
263                 return false;
264
265         *idx = (uint32_t) tmp;
266
267         if (!get_int(jobj, "IVupdate", &tmp))
268                 return false;
269
270         *update = tmp ? true : false;
271
272         return true;
273 }
274
275 bool mesh_db_read_token(json_object *jobj, uint8_t token[8])
276 {
277         json_object *jvalue;
278         char *str;
279
280         if (!token)
281                 return false;
282
283         if (!json_object_object_get_ex(jobj, "token", &jvalue))
284                 return false;
285
286         str = (char *)json_object_get_string(jvalue);
287         if (!str2hex(str, strlen(str), token, 8))
288                 return false;
289
290         return true;
291 }
292
293 bool mesh_db_read_device_key(json_object *jobj, uint8_t key_buf[16])
294 {
295         json_object *jvalue;
296         char *str;
297
298         if (!key_buf)
299                 return false;
300
301         if (!json_object_object_get_ex(jobj, "deviceKey", &jvalue))
302                 return false;
303
304         str = (char *)json_object_get_string(jvalue);
305         if (!str2hex(str, strlen(str), key_buf, 16))
306                 return false;
307
308         return true;
309 }
310
311 bool mesh_db_read_app_keys(json_object *jobj, mesh_db_app_key_cb cb,
312                                                         void *user_data)
313 {
314         json_object *jarray;
315         int len;
316         int i;
317
318         if (!cb)
319                 return true;
320
321         if (!json_object_object_get_ex(jobj, "appKeys", &jarray))
322                 return false;
323
324         if (json_object_get_type(jarray) != json_type_array)
325                 return false;
326
327         len = json_object_array_length(jarray);
328
329         for (i = 0; i < len; ++i) {
330                 json_object *jtemp, *jvalue;
331                 int app_idx, net_idx;
332                 bool key_refresh = false;
333                 char *str;
334                 uint8_t key[16];
335                 uint8_t new_key[16];
336
337                 jtemp = json_object_array_get_idx(jarray, i);
338
339                 if (!get_int(jtemp, "index", &app_idx))
340                         return false;
341
342                 if (!CHECK_KEY_IDX_RANGE(app_idx))
343                         return false;
344
345                 if (!get_int(jtemp, "boundNetKey", &net_idx))
346                         return false;
347
348                 if (!CHECK_KEY_IDX_RANGE(net_idx))
349                         return false;
350
351                 if (json_object_object_get_ex(jtemp, "oldKey", &jvalue)) {
352                         str = (char *)json_object_get_string(jvalue);
353                         if (!str2hex(str, strlen(str), key, 16))
354                                 return false;
355                         key_refresh = true;
356                 }
357
358                 if (!json_object_object_get_ex(jtemp, "key", &jvalue))
359                         return false;
360
361                 str = (char *)json_object_get_string(jvalue);
362                 if (!str2hex(str, strlen(str), key_refresh ? new_key : key, 16))
363                         return false;
364
365                 if (!cb((uint16_t)net_idx, (uint16_t) app_idx, key,
366                                 key_refresh ? new_key : NULL, user_data))
367                         return false;
368         }
369
370         return true;
371 }
372
373 bool mesh_db_read_net_keys(json_object *jobj, mesh_db_net_key_cb cb,
374                                                                 void *user_data)
375 {
376         json_object *jarray;
377         int len;
378         int i;
379
380         if (!cb)
381                 return true;
382
383         if (!json_object_object_get_ex(jobj, "netKeys", &jarray))
384                 return false;
385
386         if (json_object_get_type(jarray) != json_type_array)
387                 return false;
388
389         len = json_object_array_length(jarray);
390
391         for (i = 0; i < len; ++i) {
392                 json_object *jtemp, *jvalue;
393                 int idx;
394                 char *str;
395                 bool key_refresh = false;
396                 int phase;
397                 uint8_t key[16];
398                 uint8_t new_key[16];
399
400                 jtemp = json_object_array_get_idx(jarray, i);
401
402                 if (!get_int(jtemp, "index", &idx))
403                         return false;
404
405                 if (!CHECK_KEY_IDX_RANGE(idx))
406                         return false;
407
408                 if (json_object_object_get_ex(jtemp, "oldKey", &jvalue)) {
409                         str = (char *)json_object_get_string(jvalue);
410                         if (!str2hex(str, strlen(str), key, 16))
411                                 return false;
412                         key_refresh = true;
413                 }
414
415                 if (!json_object_object_get_ex(jtemp, "key", &jvalue))
416                         return false;
417
418                 str = (char *)json_object_get_string(jvalue);
419                 if (!str2hex(str, strlen(str), key_refresh ? new_key : key, 16))
420                         return false;
421
422                 if (!json_object_object_get_ex(jtemp, "keyRefresh", &jvalue))
423                         phase = KEY_REFRESH_PHASE_NONE;
424                 else
425                         phase = json_object_get_int(jvalue);
426
427
428                 if (!cb((uint16_t)idx, key, key_refresh ? new_key : NULL, phase,
429                                                                 user_data))
430                         return false;
431         }
432
433         return true;
434 }
435
436 bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
437                                                         const uint8_t key[16])
438 {
439         json_object *jarray = NULL, *jentry = NULL, *jstring;
440         char buf[5];
441
442         json_object_object_get_ex(jobj, "netKeys", &jarray);
443         if (jarray)
444                 jentry = get_key_object(jarray, idx);
445
446         /* Do not allow direct overwrite */
447         if (jentry)
448                 return false;
449
450         jentry = json_object_new_object();
451         if (!jentry)
452                 return false;
453
454         snprintf(buf, 5, "%4.4x", idx);
455         jstring = json_object_new_string(buf);
456         if (!jstring)
457                 goto fail;
458
459         json_object_object_add(jentry, "index", jstring);
460
461         if (!add_key_value(jentry, "key", key))
462                 goto fail;
463
464         json_object_object_add(jentry, "keyRefresh",
465                                 json_object_new_int(KEY_REFRESH_PHASE_NONE));
466
467         if (!jarray) {
468                 jarray = json_object_new_array();
469                 if (!jarray)
470                         goto fail;
471                 json_object_object_add(jobj, "netKeys", jarray);
472         }
473
474         json_object_array_add(jarray, jentry);
475
476         return true;
477 fail:
478         if (jentry)
479                 json_object_put(jentry);
480
481         return false;
482 }
483
484 bool mesh_db_net_key_update(json_object *jobj, uint16_t idx,
485                                                         const uint8_t key[16])
486 {
487         json_object *jarray, *jentry, *jstring;
488         const char *str;
489
490         if (!json_object_object_get_ex(jobj, "netKeys", &jarray))
491                 return false;
492
493         jentry = get_key_object(jarray, idx);
494         /* Net key must be already recorded */
495         if (!jentry)
496                 return false;
497
498         if (!json_object_object_get_ex(jentry, "key", &jstring))
499                 return false;
500
501         str = json_object_get_string(jstring);
502         jstring = json_object_new_string(str);
503         json_object_object_add(jentry, "oldKey", jstring);
504         json_object_object_del(jentry, "key");
505
506         if (!add_key_value(jentry, "key", key))
507                 return false;
508
509         json_object_object_add(jentry, "keyRefresh",
510                                 json_object_new_int(KEY_REFRESH_PHASE_ONE));
511
512         return true;
513 }
514
515 bool mesh_db_net_key_del(json_object *jobj, uint16_t idx)
516 {
517         json_object *jarray, *jarray_new;
518
519         if (!json_object_object_get_ex(jobj, "netKeys", &jarray))
520                 return true;
521
522         /* Check if matching entry exists */
523         if (!get_key_object(jarray, idx))
524                 return true;
525
526         if (json_object_array_length(jarray) == 1) {
527                 json_object_object_del(jobj, "netKeys");
528                 return true;
529         }
530
531         /*
532          * There is no easy way to delete a value from json array.
533          * Create a new copy without specified element and
534          * then remove old array.
535          */
536         jarray_new = jarray_key_del(jarray, idx);
537         if (!jarray_new)
538                 return false;
539
540         json_object_object_del(jobj, "netKeys");
541         json_object_object_add(jobj, "netKeys", jarray_new);
542
543         return true;
544 }
545
546 bool mesh_db_write_device_key(json_object *jnode, uint8_t *key)
547 {
548         return add_key_value(jnode, "deviceKey", key);
549 }
550
551 bool mesh_db_write_token(json_object *jnode, uint8_t *token)
552 {
553         return add_u64_value(jnode, "token", token);
554 }
555
556 bool mesh_db_app_key_add(json_object *jobj, uint16_t net_idx, uint16_t app_idx,
557                                                         const uint8_t key[16])
558 {
559         json_object *jarray = NULL, *jentry = NULL, *jstring = NULL;
560         char buf[5];
561
562         json_object_object_get_ex(jobj, "appKeys", &jarray);
563         if (jarray)
564                 jentry = get_key_object(jarray, app_idx);
565
566         /* Do not allow direct overrwrite */
567         if (jentry)
568                 return false;
569
570         jentry = json_object_new_object();
571         if (!jentry)
572                 return false;
573
574         snprintf(buf, 5, "%4.4x", app_idx);
575         jstring = json_object_new_string(buf);
576         if (!jstring)
577                 goto fail;
578
579         json_object_object_add(jentry, "index", jstring);
580
581         snprintf(buf, 5, "%4.4x", net_idx);
582         jstring = json_object_new_string(buf);
583         if (!jstring)
584                 goto fail;
585
586         json_object_object_add(jentry, "boundNetKey", jstring);
587
588         if (!add_key_value(jentry, "key", key))
589                 goto fail;
590
591         if (!jarray) {
592                 jarray = json_object_new_array();
593                 if (!jarray)
594                         goto fail;
595                 json_object_object_add(jobj, "appKeys", jarray);
596         }
597
598         json_object_array_add(jarray, jentry);
599
600         return true;
601 fail:
602
603         if (jentry)
604                 json_object_put(jentry);
605
606         return false;
607 }
608
609 bool mesh_db_app_key_update(json_object *jobj, uint16_t app_idx,
610                                                         const uint8_t key[16])
611 {
612         json_object *jarray, *jentry = NULL, *jstring = NULL;
613         const char *str;
614
615         if (!json_object_object_get_ex(jobj, "appKeys", &jarray))
616                 return false;
617
618         /* The key entry should exist if the key is updated */
619         jentry = get_key_object(jarray, app_idx);
620         if (!jentry)
621                 return false;
622
623         if (!json_object_object_get_ex(jentry, "key", &jstring))
624                 return false;
625
626         str = json_object_get_string(jstring);
627         jstring = json_object_new_string(str);
628         json_object_object_add(jentry, "oldKey", jstring);
629         json_object_object_del(jentry, "key");
630
631         return add_key_value(jentry, "key", key);
632 }
633
634 bool mesh_db_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx)
635 {
636         json_object *jarray, *jarray_new;
637
638         if (!json_object_object_get_ex(jobj, "appKeys", &jarray))
639                 return true;
640
641         /* Check if matching entry exists */
642         if (!get_key_object(jarray, idx))
643                 return true;
644
645         if (json_object_array_length(jarray) == 1) {
646                 json_object_object_del(jobj, "appKeys");
647                 return true;
648         }
649
650         /*
651          * There is no easy way to delete a value from json array.
652          * Create a new copy without specified element and
653          * then remove old array.
654          */
655         jarray_new = jarray_key_del(jarray, idx);
656         if (!jarray_new)
657                 return false;
658
659         json_object_object_del(jobj, "appKeys");
660         json_object_object_add(jobj, "appKeys", jarray_new);
661
662         return true;
663 }
664
665 bool mesh_db_model_binding_add(json_object *jnode, uint8_t ele_idx, bool vendor,
666                                 uint32_t mod_id, uint16_t app_idx)
667 {
668         json_object *jmodel, *jstring, *jarray = NULL;
669         char buf[5];
670
671         jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
672         if (!jmodel)
673                 return false;
674
675         snprintf(buf, 5, "%4.4x", app_idx);
676
677         json_object_object_get_ex(jmodel, "bind", &jarray);
678         if (jarray && jarray_has_string(jarray, buf, 4))
679                 return true;
680
681         jstring = json_object_new_string(buf);
682         if (!jstring)
683                 return false;
684
685         if (!jarray) {
686                 jarray = json_object_new_array();
687                 if (!jarray) {
688                         json_object_put(jstring);
689                         return false;
690                 }
691                 json_object_object_add(jmodel, "bind", jarray);
692         }
693
694         json_object_array_add(jarray, jstring);
695
696         return true;
697 }
698
699 bool mesh_db_model_binding_del(json_object *jnode, uint8_t ele_idx, bool vendor,
700                                 uint32_t mod_id, uint16_t app_idx)
701 {
702         json_object *jmodel, *jarray, *jarray_new;
703         char buf[5];
704
705         jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
706         if (!jmodel)
707                 return false;
708
709         if (!json_object_object_get_ex(jmodel, "bind", &jarray))
710                 return true;
711
712         snprintf(buf, 5, "%4.4x", app_idx);
713
714         if (!jarray_has_string(jarray, buf, 4))
715                 return true;
716
717         if (json_object_array_length(jarray) == 1) {
718                 json_object_object_del(jmodel, "bind");
719                 return true;
720         }
721
722         /*
723          * There is no easy way to delete a value from json array.
724          * Create a new copy without specified element and
725          * then remove old array.
726          */
727         jarray_new = jarray_string_del(jarray, buf, 4);
728         if (!jarray_new)
729                 return false;
730
731         json_object_object_del(jmodel, "bind");
732         json_object_object_add(jmodel, "bind", jarray_new);
733
734         return true;
735 }
736
737 static void free_model(void *data)
738 {
739         struct mesh_db_model *mod = data;
740
741         l_free(mod->bindings);
742         l_free(mod->subs);
743         l_free(mod->pub);
744         l_free(mod);
745 }
746
747 static void free_element(void *data)
748 {
749         struct mesh_db_element *ele = data;
750
751         l_queue_destroy(ele->models, free_model);
752         l_free(ele);
753 }
754
755 static bool parse_bindings(json_object *jbindings, struct mesh_db_model *mod)
756 {
757         int cnt;
758         int i;
759
760         cnt = json_object_array_length(jbindings);
761         if (cnt > 0xffff)
762                 return false;
763
764         mod->num_bindings = cnt;
765
766         /* Allow empty bindings list */
767         if (!cnt)
768                 return true;
769
770         mod->bindings = l_new(uint16_t, cnt);
771
772         for (i = 0; i < cnt; ++i) {
773                 int idx;
774                 json_object *jvalue;
775
776                 jvalue = json_object_array_get_idx(jbindings, i);
777                 if (!jvalue)
778                         return false;
779
780                 idx = json_object_get_int(jvalue);
781                 if (!CHECK_KEY_IDX_RANGE(idx))
782                         return false;
783
784                 mod->bindings[i] = (uint16_t) idx;
785         }
786
787         return true;
788 }
789
790 static bool get_key_index(json_object *jobj, const char *keyword,
791                                                                 uint16_t *index)
792 {
793         int idx;
794
795         if (!get_int(jobj, keyword, &idx))
796                 return false;
797
798         if (!CHECK_KEY_IDX_RANGE(idx))
799                 return false;
800
801         *index = (uint16_t) idx;
802         return true;
803 }
804
805 static struct mesh_db_pub *parse_model_publication(json_object *jpub)
806 {
807         json_object *jvalue;
808         struct mesh_db_pub *pub;
809         int len, value;
810         char *str;
811
812         if (!json_object_object_get_ex(jpub, "address", &jvalue))
813                 return NULL;
814
815         str = (char *)json_object_get_string(jvalue);
816         len = strlen(str);
817         pub = l_new(struct mesh_db_pub, 1);
818
819         switch (len) {
820         case 4:
821                 if (sscanf(str, "%04hx", &pub->addr) != 1)
822                         goto fail;
823                 break;
824         case 32:
825                 if (!str2hex(str, len, pub->virt_addr, 16))
826                         goto fail;
827                 pub->virt = true;
828                 break;
829         default:
830                 goto fail;
831         }
832
833         if (!get_key_index(jpub, "index", &pub->idx))
834                 goto fail;
835
836         if (!get_int(jpub, "ttl", &value))
837                 goto fail;
838         pub->ttl = (uint8_t) value;
839
840         if (!get_int(jpub, "period", &value))
841                 goto fail;
842         pub->period = value;
843
844         if (!get_int(jpub, "credentials", &value))
845                 goto fail;
846         pub->credential = (uint8_t) value;
847
848         if (!json_object_object_get_ex(jpub, "retransmit", &jvalue))
849                 goto fail;
850
851         if (!get_int(jvalue, "count", &value))
852                 goto fail;
853         pub->count = (uint8_t) value;
854
855         if (!get_int(jvalue, "interval", &value))
856                 goto fail;
857         pub->interval = (uint8_t) value;
858
859         return pub;
860
861 fail:
862         l_free(pub);
863         return NULL;
864 }
865
866 static bool parse_model_subscriptions(json_object *jsubs,
867                                                 struct mesh_db_model *mod)
868 {
869         struct mesh_db_sub *subs;
870         int i, cnt;
871
872         if (json_object_get_type(jsubs) != json_type_array)
873                 return NULL;
874
875         cnt = json_object_array_length(jsubs);
876         /* Allow empty array */
877         if (!cnt)
878                 return true;
879
880         subs = l_new(struct mesh_db_sub, cnt);
881
882         for (i = 0; i < cnt; ++i) {
883                 char *str;
884                 int len;
885                 json_object *jvalue;
886
887                 jvalue = json_object_array_get_idx(jsubs, i);
888                 if (!jvalue)
889                         return false;
890
891                 str = (char *)json_object_get_string(jvalue);
892                 len = strlen(str);
893
894                 switch (len) {
895                 case 4:
896                         if (sscanf(str, "%04hx", &subs[i].src.addr) != 1)
897                                 goto fail;
898                 break;
899                 case 32:
900                         if (!str2hex(str, len, subs[i].src.virt_addr, 16))
901                                 goto fail;
902                         subs[i].virt = true;
903                         break;
904                 default:
905                         goto fail;
906                 }
907         }
908
909         mod->num_subs = cnt;
910         mod->subs = subs;
911
912         return true;
913 fail:
914         l_free(subs);
915         return false;
916 }
917
918 static bool parse_models(json_object *jmodels, struct mesh_db_element *ele)
919 {
920         int i, num_models;
921
922         num_models = json_object_array_length(jmodels);
923         if (!num_models)
924                 return true;
925
926         for (i = 0; i < num_models; ++i) {
927                 json_object *jmodel, *jarray, *jvalue;
928                 struct mesh_db_model *mod;
929                 uint32_t id;
930                 int len;
931                 char *str;
932
933                 jmodel = json_object_array_get_idx(jmodels, i);
934                 if (!jmodel)
935                         goto fail;
936
937                 mod = l_new(struct mesh_db_model, 1);
938
939                 if (!json_object_object_get_ex(jmodel, "modelId", &jvalue))
940                         goto fail;
941
942                 str = (char *)json_object_get_string(jvalue);
943
944                 len = strlen(str);
945
946                 if (len != 4 && len != 8)
947                         goto fail;
948
949                 if (len == 4) {
950                         if (sscanf(str, "%04x", &id) != 1)
951                                 goto fail;
952
953                         id |= VENDOR_ID_MASK;
954                 } else if (len == 8) {
955                         if (sscanf(str, "%08x", &id) != 1)
956                                 goto fail;
957                 } else
958                         goto fail;
959
960                 mod->id = id;
961
962                 if (len == 8)
963                         mod->vendor = true;
964
965                 if (json_object_object_get_ex(jmodel, "bind", &jarray)) {
966                         if (json_object_get_type(jarray) != json_type_array ||
967                                         !parse_bindings(jarray, mod))
968                                 goto fail;
969                 }
970
971                 if (json_object_object_get_ex(jmodel, "publish", &jvalue)) {
972                         mod->pub = parse_model_publication(jvalue);
973                         if (!mod->pub)
974                                 goto fail;
975                 }
976
977                 if (json_object_object_get_ex(jmodel, "subscribe", &jarray)) {
978                         if (!parse_model_subscriptions(jarray, mod))
979                                 goto fail;
980                 }
981
982                 l_queue_push_tail(ele->models, mod);
983         }
984
985         return true;
986
987 fail:
988         l_queue_destroy(ele->models, free_model);
989         return false;
990 }
991
992 static bool parse_elements(json_object *jelements, struct mesh_db_node *node)
993 {
994         int i, num_ele;
995
996         if (json_object_get_type(jelements) != json_type_array)
997                 return false;
998
999         num_ele = json_object_array_length(jelements);
1000         if (!num_ele)
1001                 /* Allow "empty" nodes */
1002                 return true;
1003
1004         node->elements = l_queue_new();
1005
1006         for (i = 0; i < num_ele; ++i) {
1007                 json_object *jelement;
1008                 json_object *jmodels;
1009                 json_object *jvalue;
1010                 struct mesh_db_element *ele;
1011                 int index;
1012                 char *str;
1013
1014                 jelement = json_object_array_get_idx(jelements, i);
1015                 if (!jelement)
1016                         goto fail;
1017
1018                 if (!get_int(jelement, "elementIndex", &index) ||
1019                                                                 index > num_ele)
1020                         goto fail;
1021
1022                 ele = l_new(struct mesh_db_element, 1);
1023                 ele->index = index;
1024                 ele->models = l_queue_new();
1025
1026                 if (!json_object_object_get_ex(jelement, "location", &jvalue))
1027                         goto fail;
1028
1029                 str = (char *)json_object_get_string(jvalue);
1030                 if (sscanf(str, "%04hx", &(ele->location)) != 1)
1031                         goto fail;
1032
1033                 if (json_object_object_get_ex(jelement, "models", &jmodels)) {
1034                         if (json_object_get_type(jmodels) != json_type_array ||
1035                                                 !parse_models(jmodels, ele))
1036                                 goto fail;
1037                 }
1038
1039                 l_queue_push_tail(node->elements, ele);
1040         }
1041
1042         return true;
1043
1044 fail:
1045         l_queue_destroy(node->elements, free_element);
1046         node->elements = NULL;
1047
1048         return false;
1049 }
1050
1051 static int get_mode(json_object *jvalue)
1052 {
1053         const char *str;
1054
1055         str = json_object_get_string(jvalue);
1056         if (!str)
1057                 return 0xffffffff;
1058
1059         if (!strncasecmp(str, "disabled", strlen("disabled")))
1060                 return MESH_MODE_DISABLED;
1061
1062         if (!strncasecmp(str, "enabled", strlen("enabled")))
1063                 return MESH_MODE_ENABLED;
1064
1065         if (!strncasecmp(str, "unsupported", strlen("unsupported")))
1066                 return MESH_MODE_UNSUPPORTED;
1067
1068         return 0xffffffff;
1069 }
1070
1071 static void parse_features(json_object *jconfig, struct mesh_db_node *node)
1072 {
1073         json_object *jvalue, *jrelay;
1074         int mode, count;
1075         uint16_t interval;
1076
1077         if (json_object_object_get_ex(jconfig, "proxy", &jvalue)) {
1078                 mode = get_mode(jvalue);
1079                 if (mode <= MESH_MODE_UNSUPPORTED)
1080                         node->modes.proxy = mode;
1081         }
1082
1083         if (json_object_object_get_ex(jconfig, "friend", &jvalue)) {
1084                 mode = get_mode(jvalue);
1085                 if (mode <= MESH_MODE_UNSUPPORTED)
1086                         node->modes.friend = mode;
1087         }
1088
1089         if (json_object_object_get_ex(jconfig, "lowPower", &jvalue)) {
1090                 mode = get_mode(jvalue);
1091                 if (mode <= MESH_MODE_UNSUPPORTED)
1092                         node->modes.friend = mode;
1093         }
1094
1095         if (json_object_object_get_ex(jconfig, "beacon", &jvalue)) {
1096                 mode = get_mode(jvalue);
1097                 if (mode <= MESH_MODE_UNSUPPORTED)
1098                         node->modes.beacon = mode;
1099         }
1100
1101         if (!json_object_object_get_ex(jconfig, "relay", &jrelay))
1102                 return;
1103
1104         if (json_object_object_get_ex(jrelay, "mode", &jvalue)) {
1105                 mode = get_mode(jvalue);
1106                 if (mode <= MESH_MODE_UNSUPPORTED)
1107                         node->modes.relay.state = mode;
1108                 else
1109                         return;
1110         } else
1111                 return;
1112
1113         if (!json_object_object_get_ex(jrelay, "count", &jvalue))
1114                 return;
1115
1116         /* TODO: check range */
1117         count = json_object_get_int(jvalue);
1118         node->modes.relay.cnt = count;
1119
1120         if (!json_object_object_get_ex(jrelay, "interval", &jvalue))
1121                 return;
1122
1123         /* TODO: check range */
1124         interval = json_object_get_int(jvalue);
1125         node->modes.relay.interval = interval;
1126 }
1127
1128 static bool parse_composition(json_object *jcomp, struct mesh_db_node *node)
1129 {
1130         json_object *jvalue;
1131         char *str;
1132
1133         /* All the fields in node composition are mandatory */
1134         if (!json_object_object_get_ex(jcomp, "cid", &jvalue))
1135                 return false;
1136
1137         str = (char *)json_object_get_string(jvalue);
1138         if (sscanf(str, "%04hx", &node->cid) != 1)
1139                 return false;
1140
1141         if (!json_object_object_get_ex(jcomp, "pid", &jvalue))
1142                 return false;
1143
1144         str = (char *)json_object_get_string(jvalue);
1145         if (sscanf(str, "%04hx", &node->pid) != 1)
1146                 return false;
1147
1148         if (!json_object_object_get_ex(jcomp, "vid", &jvalue))
1149                 return false;
1150
1151         str = (char *)json_object_get_string(jvalue);
1152         if (sscanf(str, "%04hx", &node->vid) != 1)
1153                 return false;
1154
1155         if (!json_object_object_get_ex(jcomp, "crpl", &jvalue))
1156                 return false;
1157
1158         str = (char *)json_object_get_string(jvalue);
1159         if (sscanf(str, "%04hx", &node->crpl) != 1)
1160                 return false;
1161
1162         return true;
1163 }
1164
1165 bool mesh_db_read_node(json_object *jnode, mesh_db_node_cb cb, void *user_data)
1166 {
1167         struct mesh_db_node node;
1168         json_object *jvalue;
1169         char *str;
1170
1171         if (!jnode)
1172                 return false;
1173
1174         if (!cb) {
1175                 l_info("Node read callback is required");
1176                 return false;
1177         }
1178
1179         memset(&node, 0, sizeof(node));
1180
1181         if (!parse_composition(jnode, &node)) {
1182                 l_info("Failed to parse local node composition");
1183                 return false;
1184         }
1185
1186         parse_features(jnode, &node);
1187
1188         if (!json_object_object_get_ex(jnode, "unicastAddress", &jvalue)) {
1189                 l_info("Bad config: Unicast address must be present");
1190                 return false;
1191         }
1192
1193         str = (char *)json_object_get_string(jvalue);
1194         if (sscanf(str, "%04hx", &node.unicast) != 1)
1195                 return false;
1196
1197         if (json_object_object_get_ex(jnode, "defaultTTL", &jvalue)) {
1198                 int ttl = json_object_get_int(jvalue);
1199
1200                 if (ttl < 0 || ttl == 1 || ttl > DEFAULT_TTL)
1201                         return false;
1202                 node.ttl = (uint8_t) ttl;
1203         }
1204
1205         if (json_object_object_get_ex(jnode, "sequenceNumber", &jvalue))
1206                 node.seq_number = json_object_get_int(jvalue);
1207
1208         /* Check for required "elements" property */
1209         if (!json_object_object_get_ex(jnode, "elements", &jvalue))
1210                 return false;
1211
1212         if (!parse_elements(jvalue, &node))
1213                 return false;
1214
1215         return cb(&node, user_data);
1216 }
1217
1218 bool mesh_db_write_uint16_hex(json_object *jobj, const char *desc,
1219                                                                 uint16_t value)
1220 {
1221         json_object *jstring;
1222         char buf[5];
1223
1224         if (!jobj)
1225                 return false;
1226
1227         snprintf(buf, 5, "%4.4x", value);
1228         jstring = json_object_new_string(buf);
1229         if (!jstring)
1230                 return false;
1231
1232         json_object_object_add(jobj, desc, jstring);
1233         return true;
1234 }
1235
1236 bool mesh_db_write_uint32_hex(json_object *jobj, const char *desc,
1237                                                                 uint32_t value)
1238 {
1239         json_object *jstring;
1240         char buf[9];
1241
1242         if (!jobj)
1243                 return false;
1244
1245         snprintf(buf, 9, "%8.8x", value);
1246         jstring = json_object_new_string(buf);
1247         if (!jstring)
1248                 return false;
1249
1250         json_object_object_add(jobj, desc, jstring);
1251         return true;
1252 }
1253
1254 bool mesh_db_write_int(json_object *jobj, const char *keyword, int value)
1255 {
1256         json_object *jvalue;
1257
1258         if (!jobj)
1259                 return false;
1260
1261         json_object_object_del(jobj, keyword);
1262
1263         jvalue = json_object_new_int(value);
1264         if (!jvalue)
1265                 return false;
1266
1267         json_object_object_add(jobj, keyword, jvalue);
1268         return true;
1269 }
1270
1271 bool mesh_db_write_bool(json_object *jobj, const char *keyword, bool value)
1272 {
1273         json_object *jvalue;
1274
1275         if (!jobj)
1276                 return false;
1277
1278         json_object_object_del(jobj, keyword);
1279
1280         jvalue = json_object_new_boolean(value);
1281         if (!jvalue)
1282                 return false;
1283
1284         json_object_object_add(jobj, keyword, jvalue);
1285         return true;
1286 }
1287
1288 static const char *mode_to_string(int mode)
1289 {
1290         switch (mode) {
1291         case MESH_MODE_DISABLED:
1292                 return "disabled";
1293         case MESH_MODE_ENABLED:
1294                 return "enabled";
1295         default:
1296                 return "unsupported";
1297         }
1298 }
1299
1300 bool mesh_db_write_mode(json_object *jobj, const char *keyword, int value)
1301 {
1302         json_object *jstring;
1303
1304         if (!jobj)
1305                 return false;
1306
1307         jstring = json_object_new_string(mode_to_string(value));
1308
1309         if (!jstring)
1310                 return false;
1311
1312         json_object_object_add(jobj, keyword, jstring);
1313
1314         return true;
1315 }
1316
1317 bool mesh_db_write_relay_mode(json_object *jnode, uint8_t mode, uint8_t count,
1318                                                         uint16_t interval)
1319 {
1320         json_object *jrelay;
1321
1322         if (!jnode)
1323                 return false;
1324
1325         json_object_object_del(jnode, "relay");
1326
1327         jrelay = json_object_new_object();
1328         if (!jrelay)
1329                 return false;
1330
1331         if (!mesh_db_write_mode(jrelay, "mode", mode))
1332                 goto fail;
1333
1334         if (!mesh_db_write_int(jrelay, "count", count))
1335                 goto fail;
1336
1337         if (!mesh_db_write_int(jrelay, "interval", interval))
1338                 goto fail;
1339
1340         json_object_object_add(jnode, "relay", jrelay);
1341
1342         return true;
1343 fail:
1344         json_object_put(jrelay);
1345         return false;
1346 }
1347
1348 bool mesh_db_read_net_transmit(json_object *jobj, uint8_t *cnt,
1349                                                         uint16_t *interval)
1350 {
1351         json_object *jretransmit, *jvalue;
1352
1353         if (!jobj)
1354                 return false;
1355
1356         if (!json_object_object_get_ex(jobj, "retransmit", &jretransmit))
1357                 return false;
1358
1359         if (!json_object_object_get_ex(jretransmit, "count", &jvalue))
1360                 return false;
1361
1362         *cnt = (uint8_t) json_object_get_int(jvalue);
1363
1364         if (!json_object_object_get_ex(jretransmit, "interval", &jvalue))
1365                 return false;
1366
1367         *interval = (uint16_t) json_object_get_int(jvalue);
1368
1369         return true;
1370 }
1371
1372 bool mesh_db_write_net_transmit(json_object *jobj, uint8_t cnt,
1373                                                         uint16_t interval)
1374 {
1375         json_object *jretransmit;
1376
1377         if (!jobj)
1378                 return false;
1379
1380         json_object_object_del(jobj, "retransmit");
1381
1382         jretransmit = json_object_new_object();
1383         if (jretransmit)
1384                 return false;
1385
1386         if (!mesh_db_write_int(jretransmit, "count", cnt))
1387                 goto fail;
1388
1389         if (!mesh_db_write_int(jretransmit, "interval", interval))
1390                 goto fail;
1391
1392         json_object_object_add(jobj, "retransmit", jretransmit);
1393
1394         return true;
1395 fail:
1396         json_object_put(jretransmit);
1397         return false;
1398
1399 }
1400
1401 bool mesh_db_write_iv_index(json_object *jobj, uint32_t idx, bool update)
1402 {
1403         int tmp = update ? 1 : 0;
1404
1405         if (!jobj)
1406                 return false;
1407
1408         if (!mesh_db_write_int(jobj, "IVindex", idx))
1409                 return false;
1410
1411         if (!mesh_db_write_int(jobj, "IVupdate", tmp))
1412                 return false;
1413
1414         return true;
1415 }
1416
1417 void mesh_db_remove_property(json_object *jobj, const char *desc)
1418 {
1419         if (jobj)
1420                 json_object_object_del(jobj, desc);
1421 }
1422
1423 static void add_model(void *a, void *b)
1424 {
1425         struct mesh_db_model *mod = a;
1426         json_object *jmodels = b, *jmodel;
1427
1428         jmodel = json_object_new_object();
1429         if (!jmodel)
1430                 return;
1431
1432         if (!mod->vendor)
1433                 mesh_db_write_uint16_hex(jmodel, "modelId",
1434                                                 (uint16_t) mod->id);
1435         else
1436                 mesh_db_write_uint32_hex(jmodel, "modelId", mod->id);
1437
1438         json_object_array_add(jmodels, jmodel);
1439 }
1440
1441 /* Add unprovisioned node (local) */
1442 bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {
1443
1444         struct mesh_db_modes *modes = &node->modes;
1445         const struct l_queue_entry *entry;
1446         json_object *jelements;
1447
1448         if (!jnode)
1449                 return false;
1450
1451         /* CID, PID, VID, crpl */
1452         if (!mesh_db_write_uint16_hex(jnode, "cid", node->cid))
1453                 return false;
1454
1455         if (!mesh_db_write_uint16_hex(jnode, "pid", node->pid))
1456                 return false;
1457
1458         if (!mesh_db_write_uint16_hex(jnode, "vid", node->vid))
1459                 return false;
1460
1461         if (!mesh_db_write_uint16_hex(jnode, "crpl", node->crpl))
1462                 return false;
1463
1464         /* Features: relay, LPN, friend, proxy*/
1465         if (!mesh_db_write_relay_mode(jnode, modes->relay.state,
1466                                                 modes->relay.cnt,
1467                                                 modes->relay.interval))
1468                 return false;
1469
1470         if (!mesh_db_write_mode(jnode, "lowPower", modes->lpn))
1471                 return false;
1472
1473         if (!mesh_db_write_mode(jnode, "friend", modes->friend))
1474                 return false;
1475
1476         if (!mesh_db_write_mode(jnode, "proxy", modes->proxy))
1477                 return false;
1478
1479         /* Beaconing state */
1480         if (!mesh_db_write_mode(jnode, "beacon", modes->beacon))
1481                 return false;
1482
1483         /* Sequence number */
1484         json_object_object_add(jnode, "sequenceNumber",
1485                                         json_object_new_int(node->seq_number));
1486
1487         /* Default TTL */
1488         json_object_object_add(jnode, "defaultTTL",
1489                                                 json_object_new_int(node->ttl));
1490
1491         /* Elements */
1492         jelements = json_object_new_array();
1493         if (!jelements)
1494                 return false;
1495
1496         entry = l_queue_get_entries(node->elements);
1497
1498         for (; entry; entry = entry->next) {
1499                 struct mesh_db_element *ele = entry->data;
1500                 json_object *jelement, *jmodels;
1501
1502                 jelement = json_object_new_object();
1503
1504                 if (!jelement) {
1505                         json_object_put(jelements);
1506                         return false;
1507                 }
1508
1509                 mesh_db_write_int(jelement, "elementIndex", ele->index);
1510                 mesh_db_write_uint16_hex(jelement, "location", ele->location);
1511                 json_object_array_add(jelements, jelement);
1512
1513                 /* Models */
1514                 if (l_queue_isempty(ele->models))
1515                         continue;
1516
1517                 jmodels = json_object_new_array();
1518                 if (!jmodels) {
1519                         json_object_put(jelements);
1520                         return false;
1521                 }
1522
1523                 json_object_object_add(jelement, "models", jmodels);
1524                 l_queue_foreach(ele->models, add_model, jmodels);
1525         }
1526
1527         json_object_object_add(jnode, "elements", jelements);
1528
1529         return true;
1530 }
1531
1532 static void finish_key_refresh(json_object *jobj, uint16_t net_idx)
1533 {
1534         json_object *jarray;
1535         int i, len;
1536
1537         /* Clean up all the bound appkeys */
1538         if (!json_object_object_get_ex(jobj, "appKeys", &jarray))
1539                 return;
1540
1541         len = json_object_array_length(jarray);
1542
1543         for (i = 0; i < len; ++i) {
1544                 json_object *jentry;
1545                 uint16_t idx;
1546
1547                 jentry = json_object_array_get_idx(jarray, i);
1548
1549                 if (!get_key_index(jentry, "boundNetKey", &idx))
1550                         continue;
1551
1552                 if (idx != net_idx)
1553                         continue;
1554
1555                 json_object_object_del(jentry, "oldKey");
1556
1557                 if (!get_key_index(jentry, "index", &idx))
1558                         continue;
1559         }
1560
1561 }
1562
1563 bool mesh_db_net_key_set_phase(json_object *jobj, uint16_t idx, uint8_t phase)
1564 {
1565         json_object *jarray, *jentry = NULL;
1566
1567         if (!jobj)
1568                 return false;
1569
1570         if (json_object_object_get_ex(jobj, "netKeys", &jarray))
1571                 jentry = get_key_object(jarray, idx);
1572
1573         if (!jentry)
1574                 return false;
1575
1576         json_object_object_del(jentry, "keyRefresh");
1577         json_object_object_add(jentry, "keyRefresh",
1578                                         json_object_new_int(phase));
1579
1580         if (phase == KEY_REFRESH_PHASE_NONE) {
1581                 json_object_object_del(jentry, "oldKey");
1582                 finish_key_refresh(jobj, idx);
1583         }
1584
1585         return true;
1586 }
1587
1588 bool mesh_db_model_pub_add(json_object *jnode, uint16_t addr, uint32_t mod_id,
1589                                         bool vendor, struct mesh_db_pub *pub)
1590 {
1591         json_object *jmodel, *jpub, *jretransmit;
1592         bool res;
1593         int ele_idx;
1594
1595         if (!jnode)
1596                 return false;
1597
1598         ele_idx = get_element_index(jnode, addr);
1599         if (ele_idx < 0)
1600                 return false;
1601
1602         jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
1603         if (!jmodel)
1604                 return false;
1605
1606         json_object_object_del(jmodel, "publish");
1607
1608         jpub = json_object_new_object();
1609         if (!jpub)
1610                 return false;
1611
1612         if (pub->virt)
1613                 res = add_key_value(jpub, "address", pub->virt_addr);
1614         else
1615                 res = mesh_db_write_uint16_hex(jpub, "address", pub->addr);
1616
1617         if (!res)
1618                 goto fail;
1619
1620         if (!mesh_db_write_uint16_hex(jpub, "index", pub->idx))
1621                 goto fail;
1622
1623         if (!mesh_db_write_int(jpub, "ttl", pub->ttl))
1624                 goto fail;
1625
1626         if (!mesh_db_write_int(jpub, "period", pub->period))
1627                 goto fail;
1628
1629         if (!mesh_db_write_int(jpub, "credentials", pub->credential ? 1 : 0))
1630                 goto fail;
1631
1632         jretransmit = json_object_new_object();
1633         if (!jretransmit)
1634                 goto fail;
1635
1636         if (!mesh_db_write_int(jretransmit, "count", pub->count))
1637                 goto fail;
1638
1639         if (!mesh_db_write_int(jretransmit, "interval", pub->interval))
1640                 goto fail;
1641
1642         json_object_object_add(jpub, "retransmit", jretransmit);
1643         json_object_object_add(jmodel, "publish", jpub);
1644
1645         return true;
1646 fail:
1647         json_object_put(jpub);
1648         return false;
1649 }
1650
1651 static bool delete_model_property(json_object *jnode, uint16_t addr,
1652                         uint32_t mod_id, bool vendor, const char *keyword)
1653 {
1654         json_object *jmodel;
1655         int ele_idx;
1656
1657         ele_idx = get_element_index(jnode, addr);
1658         if (ele_idx < 0)
1659                 return false;
1660
1661         jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
1662         if (!jmodel)
1663                 return false;
1664
1665         json_object_object_del(jmodel, keyword);
1666
1667         return true;
1668 }
1669
1670 bool mesh_db_model_pub_del(json_object *jnode, uint16_t addr, uint32_t mod_id,
1671                                                                 bool vendor)
1672 {
1673         if (!jnode)
1674                 return false;
1675
1676         return delete_model_property(jnode, addr, mod_id, vendor, "publish");
1677 }
1678
1679 bool mesh_db_model_sub_add(json_object *jnode, uint16_t addr, uint32_t mod_id,
1680                                         bool vendor, struct mesh_db_sub *sub)
1681 {
1682         json_object *jmodel, *jstring, *jarray = NULL;
1683         int ele_idx, len;
1684         char buf[33];
1685
1686         if (!jnode)
1687                 return false;
1688
1689         ele_idx = get_element_index(jnode, addr);
1690         if (ele_idx < 0)
1691                 return false;
1692
1693         jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
1694         if (!jmodel)
1695                 return false;
1696
1697         if (!sub->virt) {
1698                 snprintf(buf, 5, "%4.4x", sub->src.addr);
1699                 len = 4;
1700         } else {
1701                 hex2str(sub->src.virt_addr, 16, buf, 33);
1702                 len = 32;
1703         }
1704
1705         json_object_object_get_ex(jmodel, "subscribe", &jarray);
1706         if (jarray && jarray_has_string(jarray, buf, len))
1707                 return true;
1708
1709         jstring = json_object_new_string(buf);
1710         if (!jstring)
1711                 return false;
1712
1713         if (!jarray) {
1714                 jarray = json_object_new_array();
1715                 if (!jarray) {
1716                         json_object_put(jstring);
1717                         return false;
1718                 }
1719                 json_object_object_add(jmodel, "subscribe", jarray);
1720         }
1721
1722         json_object_array_add(jarray, jstring);
1723
1724         return true;
1725 }
1726
1727 bool mesh_db_model_sub_del(json_object *jnode, uint16_t addr,
1728                         uint32_t mod_id, bool vendor, struct mesh_db_sub *sub)
1729 {
1730         json_object *jmodel, *jarray, *jarray_new;
1731         char buf[33];
1732         int len, ele_idx;
1733
1734         if (!jnode)
1735                 return false;
1736
1737         ele_idx = get_element_index(jnode, addr);
1738         if (ele_idx < 0)
1739                 return false;
1740
1741         jmodel = get_element_model(jnode, ele_idx, mod_id, vendor);
1742         if (!jmodel)
1743                 return false;
1744
1745         if (!json_object_object_get_ex(jmodel, "subscribe", &jarray))
1746                 return true;
1747
1748         if (!sub->virt) {
1749                 snprintf(buf, 5, "%4.4x", sub->src.addr);
1750                 len = 4;
1751         } else {
1752                 hex2str(sub->src.virt_addr, 16, buf, 33);
1753                 len = 32;
1754         }
1755
1756         if (!jarray_has_string(jarray, buf, len))
1757                 return true;
1758
1759         if (json_object_array_length(jarray) == 1) {
1760                 json_object_object_del(jmodel, "subscribe");
1761                 return true;
1762         }
1763
1764         /*
1765          * There is no easy way to delete a value from a json array.
1766          * Create a new copy without specified element and
1767          * then remove old array.
1768          */
1769         jarray_new = jarray_string_del(jarray, buf, len);
1770         if (!jarray_new)
1771                 return false;
1772
1773         json_object_object_del(jmodel, "subscribe");
1774         json_object_object_add(jmodel, "subscribe", jarray_new);
1775
1776         return true;
1777 }
1778
1779 bool mesh_db_model_sub_del_all(json_object *jnode, uint16_t addr,
1780                                                 uint32_t mod_id, bool vendor)
1781 {
1782         if (!jnode)
1783                 return false;
1784
1785         return delete_model_property(jnode, addr, mod_id, vendor, "subscribe");
1786 }