| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2019-2020 Intel Corporation. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <ftw.h>
- #include <libgen.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <unistd.h>
- #include <ell/ell.h>
- #include <json-c/json.h>
- #include "mesh/mesh-defs.h"
- #include "mesh/util.h"
- #include "tools/mesh/keys.h"
- #include "tools/mesh/remote.h"
- #include "tools/mesh/cfgcli.h"
- #include "tools/mesh/model.h"
- #include "tools/mesh/mesh-db.h"
- #define KEY_IDX_INVALID NET_IDX_INVALID
- #define DEFAULT_LOCATION 0x0000
- struct mesh_db {
- json_object *jcfg;
- char *cfg_fname;
- uint8_t token[8];
- };
- static struct mesh_db *cfg;
- static const char *bak_ext = ".bak";
- static const char *tmp_ext = ".tmp";
- static const char *js_schema = "http://json-schema.org/draft-04/schema#";
- static const char *schema_id = "http://www.bluetooth.com/specifications/"
- "assigned-numbers/mesh-profile/"
- "cdb-schema.json#";
- const char *schema_version = "1.0.0";
- static bool add_string(json_object *jobj, const char *desc, const char *str)
- {
- json_object *jstring = json_object_new_string(str);
- if (!jstring)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, desc);
- json_object_object_add(jobj, desc, jstring);
- return true;
- }
- static bool set_timestamp(json_object *jobj)
- {
- time_t time_raw;
- struct tm *tp;
- char buf[80];
- time(&time_raw);
- tp = gmtime(&time_raw);
- strftime(buf, 80, "%FT%TZ", tp);
- return add_string(jobj, "timestamp", buf);
- }
- static bool save_config_file(const char *fname)
- {
- FILE *outfile;
- const char *str;
- bool result = false;
- outfile = fopen(fname, "w");
- if (!outfile) {
- l_error("Failed to save configuration to %s", cfg->cfg_fname);
- return false;
- }
- set_timestamp(cfg->jcfg);
- str = json_object_to_json_string_ext(cfg->jcfg,
- JSON_C_TO_STRING_PRETTY);
- if (fwrite(str, sizeof(char), strlen(str), outfile) < strlen(str))
- l_warn("Incomplete write of mesh configuration");
- else
- result = true;
- fclose(outfile);
- return result;
- }
- static bool save_config(void)
- {
- char *fname_tmp, *fname_bak, *fname_cfg;
- bool result = false;
- fname_cfg = cfg->cfg_fname;
- fname_tmp = l_strdup_printf("%s%s", fname_cfg, tmp_ext);
- fname_bak = l_strdup_printf("%s%s", fname_cfg, bak_ext);
- remove(fname_tmp);
- result = save_config_file(fname_tmp);
- if (result) {
- remove(fname_bak);
- rename(fname_cfg, fname_bak);
- rename(fname_tmp, fname_cfg);
- }
- remove(fname_tmp);
- l_free(fname_tmp);
- l_free(fname_bak);
- return result;
- }
- static void release_config(void)
- {
- l_free(cfg->cfg_fname);
- json_object_put(cfg->jcfg);
- l_free(cfg);
- cfg = NULL;
- }
- static json_object *get_node_by_unicast(json_object *jcfg, uint16_t unicast)
- {
- json_object *jarray;
- int i, sz;
- if (!json_object_object_get_ex(jcfg, "nodes", &jarray))
- return NULL;
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return NULL;
- sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry, *jval;
- uint16_t addr;
- const char *str;
- jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "unicastAddress",
- &jval))
- return NULL;
- str = json_object_get_string(jval);
- if (sscanf(str, "%04hx", &addr) != 1)
- continue;
- if (addr == unicast)
- return jentry;
- }
- return NULL;
- }
- static bool get_int(json_object *jobj, const char *keyword, int *value)
- {
- json_object *jvalue;
- if (!json_object_object_get_ex(jobj, keyword, &jvalue))
- return false;
- *value = json_object_get_int(jvalue);
- if (errno == EINVAL) {
- l_error("Error: %s should contain an integer value\n",
- keyword);
- return false;
- }
- return true;
- }
- static bool write_int(json_object *jobj, const char *keyword, int val)
- {
- json_object *jval;
- jval = json_object_new_int(val);
- if (!jval)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, keyword);
- json_object_object_add(jobj, keyword, jval);
- return true;
- }
- static bool get_bool(json_object *jobj, const char *keyword, bool *value)
- {
- json_object *jvalue;
- if (!json_object_object_get_ex(jobj, keyword, &jvalue))
- return false;
- if (json_object_get_type(jvalue) != json_type_boolean) {
- l_error("Error: %s should contain a boolean value\n",
- keyword);
- return false;
- }
- *value = json_object_get_boolean(jvalue);
- return true;
- }
- static bool write_bool(json_object *jobj, const char *keyword, bool val)
- {
- json_object *jval;
- jval = json_object_new_boolean(val);
- if (!jval)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, keyword);
- json_object_object_add(jobj, keyword, jval);
- return true;
- }
- static json_object *get_key_object(json_object *jarray, uint16_t idx)
- {
- int i, sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry;
- int jidx;
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "index", &jidx))
- return NULL;
- if (jidx == idx)
- return jentry;
- }
- return NULL;
- }
- static bool write_uint16_hex(json_object *jobj, const char *desc,
- uint16_t value)
- {
- json_object *jstring;
- char buf[5];
- snprintf(buf, 5, "%4.4x", value);
- jstring = json_object_new_string(buf);
- if (!jstring)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, desc);
- json_object_object_add(jobj, desc, jstring);
- return true;
- }
- static bool write_uint32_hex(json_object *jobj, const char *desc, uint32_t val)
- {
- json_object *jstring;
- char buf[9];
- snprintf(buf, 9, "%8.8x", val);
- jstring = json_object_new_string(buf);
- if (!jstring)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, desc);
- json_object_object_add(jobj, desc, jstring);
- return true;
- }
- static json_object *get_node_by_uuid(json_object *jcfg, uint8_t uuid[16])
- {
- json_object *jarray = NULL;
- char buf[37];
- int i, sz;
- if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
- return NULL;
- json_object_object_get_ex(jcfg, "nodes", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return NULL;
- sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry, *jval;
- const char *str;
- jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "UUID", &jval))
- return NULL;
- str = json_object_get_string(jval);
- if (strlen(str) != 36)
- continue;
- if (!strcmp(buf, str))
- return jentry;
- }
- return NULL;
- }
- static bool add_u8_8(json_object *jobj, const char *desc,
- const uint8_t value[8])
- {
- json_object *jstring;
- char buf[17];
- hex2str((uint8_t *) value, 8, buf, 17);
- jstring = json_object_new_string(buf);
- if (!jstring)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, desc);
- json_object_object_add(jobj, desc, jstring);
- return true;
- }
- static bool add_u8_16(json_object *jobj, const char *desc,
- const uint8_t value[16])
- {
- json_object *jstring;
- char buf[33];
- hex2str((uint8_t *) value, 16, buf, 33);
- jstring = json_object_new_string(buf);
- if (!jstring)
- return false;
- /* Overwrite old value if present */
- json_object_object_del(jobj, desc);
- json_object_object_add(jobj, desc, jstring);
- return true;
- }
- static bool get_token(json_object *jobj, uint8_t token[8])
- {
- json_object *jval;
- const char *str;
- if (!token)
- return false;
- if (!json_object_object_get_ex(jobj, "token", &jval))
- return false;
- str = json_object_get_string(jval);
- if (!str2hex(str, strlen(str), token, 8))
- return false;
- return true;
- }
- static uint16_t node_parse_key(json_object *jarray, int i)
- {
- json_object *jkey;
- int idx;
- jkey = json_object_array_get_idx(jarray, i);
- if (!jkey)
- return KEY_IDX_INVALID;
- if (!get_int(jkey, "index", &idx))
- return KEY_IDX_INVALID;
- return (uint16_t)idx;
- }
- static bool node_check_key_updated(json_object *jarray, int i, bool *updated)
- {
- json_object *jkey;
- jkey = json_object_array_get_idx(jarray, i);
- if (!jkey)
- return false;
- if (!get_bool(jkey, "updated", updated))
- return false;
- return true;
- }
- static int compare_group_addr(const void *a, const void *b, void *user_data)
- {
- const struct mesh_group *grp0 = a;
- const struct mesh_group *grp1 = b;
- if (grp0->addr < grp1->addr)
- return -1;
- if (grp0->addr > grp1->addr)
- return 1;
- return 0;
- }
- static bool load_composition(json_object *jnode, uint16_t unicast)
- {
- json_object *jarray;
- int i, ele_cnt;
- if (!json_object_object_get_ex(jnode, "elements", &jarray))
- return false;
- if (json_object_get_type(jarray) != json_type_array)
- return false;
- ele_cnt = json_object_array_length(jarray);
- for (i = 0; i < ele_cnt; ++i) {
- json_object *jentry, *jval, *jmods;
- int32_t index;
- int k, mod_cnt;
- jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "index", &jval))
- return false;
- index = json_object_get_int(jval);
- if (index > 0xff)
- return false;
- if (!json_object_object_get_ex(jentry, "models", &jmods))
- return false;
- mod_cnt = json_object_array_length(jmods);
- for (k = 0; k < mod_cnt; ++k) {
- json_object *jmod, *jid;
- uint32_t mod_id, len;
- const char *str;
- jmod = json_object_array_get_idx(jmods, k);
- if (!json_object_object_get_ex(jmod, "modelId", &jid))
- return false;
- str = json_object_get_string(jid);
- len = strlen(str);
- if (len != 4 && len != 8)
- return false;
- if ((len == 4) && (sscanf(str, "%04x", &mod_id) != 1))
- return false;
- if ((len == 8) && (sscanf(str, "%08x", &mod_id) != 1))
- return false;
- remote_set_model(unicast, index, mod_id, len == 8);
- }
- }
- return true;
- }
- static void load_remotes(json_object *jcfg)
- {
- json_object *jnodes;
- int i, sz, node_count = 0;
- json_object_object_get_ex(jcfg, "nodes", &jnodes);
- if (!jnodes || json_object_get_type(jnodes) != json_type_array)
- return;
- sz = json_object_array_length(jnodes);
- for (i = 0; i < sz; ++i) {
- json_object *jnode, *jval, *jarray;
- uint8_t uuid[16];
- uint16_t unicast, key_idx;
- const char *str;
- int ele_cnt, key_cnt;
- int j;
- jnode = json_object_array_get_idx(jnodes, i);
- if (!jnode)
- continue;
- if (!json_object_object_get_ex(jnode, "UUID", &jval))
- continue;
- str = json_object_get_string(jval);
- if (strlen(str) != 36)
- continue;
- if (!l_uuid_from_string(str, uuid))
- continue;
- if (!json_object_object_get_ex(jnode, "unicastAddress", &jval))
- continue;
- str = json_object_get_string(jval);
- if (sscanf(str, "%04hx", &unicast) != 1)
- continue;
- json_object_object_get_ex(jnode, "elements", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- continue;
- ele_cnt = json_object_array_length(jarray);
- if (ele_cnt > MAX_ELE_COUNT)
- continue;
- json_object_object_get_ex(jnode, "netKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- continue;
- key_cnt = json_object_array_length(jarray);
- if (key_cnt < 0)
- continue;
- key_idx = node_parse_key(jarray, 0);
- if (key_idx == KEY_IDX_INVALID)
- continue;
- remote_add_node((const uint8_t *)uuid, unicast, ele_cnt,
- key_idx);
- for (j = 1; j < key_cnt; j++) {
- bool updated = false;
- key_idx = node_parse_key(jarray, j);
- if (key_idx == KEY_IDX_INVALID)
- continue;
- remote_add_net_key(unicast, key_idx, false);
- node_check_key_updated(jarray, j, &updated);
- remote_update_net_key(unicast, key_idx, updated, false);
- }
- json_object_object_get_ex(jnode, "appKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- continue;
- key_cnt = json_object_array_length(jarray);
- for (j = 0; j < key_cnt; j++) {
- bool updated = false;
- key_idx = node_parse_key(jarray, j);
- if (key_idx == KEY_IDX_INVALID)
- continue;
- remote_add_app_key(unicast, key_idx, false);
- node_check_key_updated(jarray, j, &updated);
- remote_update_app_key(unicast, key_idx, updated, false);
- }
- if (!load_composition(jnode, unicast))
- continue;
- /* If "crpl" is present, composition's is available */
- jval = NULL;
- if (json_object_object_get_ex(jnode, "crpl", &jval) && jval)
- remote_set_composition(unicast, true);
- /* TODO: Add the rest of the configuration */
- node_count++;
- }
- if (node_count != sz)
- l_warn("The remote node configuration load is incomplete!");
- }
- static bool add_app_key(json_object *jobj, uint16_t net_idx, uint16_t app_idx)
- {
- json_object *jkey, *jarray;
- char buf[12];
- json_object_object_get_ex(jobj, "appKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jkey = json_object_new_object();
- snprintf(buf, 12, "AppKey %4.4x", app_idx);
- if (!add_string(jkey, "name", buf))
- goto fail;
- if (!write_int(jkey, "boundNetKey", (int)net_idx))
- goto fail;
- if (!write_int(jkey, "index", (int)app_idx))
- goto fail;
- json_object_array_add(jarray, jkey);
- return true;
- fail:
- json_object_put(jkey);
- return false;
- }
- static bool add_node_key(json_object *jobj, const char *desc, uint16_t idx)
- {
- json_object *jkey, *jarray;
- json_object_object_get_ex(jobj, desc, &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jkey = json_object_new_object();
- if (!write_int(jkey, "index", (int)idx))
- goto fail;
- if (!write_bool(jkey, "updated", false))
- goto fail;
- json_object_array_add(jarray, jkey);
- return save_config();
- fail:
- json_object_put(jkey);
- return false;
- }
- bool mesh_db_node_set_ttl(uint16_t unicast, uint8_t ttl)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- if (!write_int(jnode, "defaultTTL", ttl))
- return false;
- return save_config();
- }
- static bool add_transmit_info(json_object *jobj, int cnt, int interval,
- const char *desc)
- {
- json_object *jtxmt;
- json_object_object_del(jobj, desc);
- jtxmt = json_object_new_object();
- if (!write_int(jtxmt, "count", cnt))
- goto fail;
- if (!write_int(jtxmt, "interval", interval))
- goto fail;
- json_object_object_add(jobj, desc, jtxmt);
- return true;
- fail:
- json_object_put(jtxmt);
- return false;
- }
- bool mesh_db_node_set_net_transmit(uint16_t unicast, uint8_t cnt,
- uint16_t interval)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- if (!add_transmit_info(jnode, cnt, interval, "networkTransmit"))
- return false;
- return save_config();
- }
- static bool set_feature(json_object *jnode, const char *desc, uint8_t feature)
- {
- json_object *jobj;
- if (feature > MESH_MODE_UNSUPPORTED)
- return false;
- jobj = json_object_object_get(jnode, "features");
- if (!jobj) {
- jobj = json_object_new_object();
- json_object_object_add(jnode, "features", jobj);
- }
- if (!write_int(jobj, desc, feature))
- return false;
- return save_config();
- }
- bool mesh_db_node_set_relay(uint16_t unicast, uint8_t relay, uint8_t cnt,
- uint16_t interval)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- if (relay < MESH_MODE_UNSUPPORTED &&
- !add_transmit_info(jnode, cnt, interval, "relayRetransmit"))
- return false;
- return set_feature(jnode, "relay", relay);
- }
- bool mesh_db_node_set_proxy(uint16_t unicast, uint8_t proxy)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- return set_feature(jnode, "proxy", proxy);
- }
- bool mesh_db_node_set_friend(uint16_t unicast, uint8_t friend)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- return set_feature(jnode, "friend", friend);
- }
- bool mesh_db_node_set_beacon(uint16_t unicast, bool enabled)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- if (!write_bool(jnode, "secureNetworkBeacon", enabled))
- return false;
- return save_config();
- }
- static json_object *get_element(uint16_t unicast, uint16_t ele_addr)
- {
- json_object *jnode, *jarray;
- int i, ele_cnt;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- if (!json_object_object_get_ex(jnode, "elements", &jarray))
- return NULL;
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return NULL;
- ele_cnt = json_object_array_length(jarray);
- for (i = 0; i < ele_cnt; ++i) {
- json_object *jentry, *jval;
- int32_t index;
- jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "index", &jval))
- return NULL;
- index = json_object_get_int(jval);
- if (index > 0xff)
- return NULL;
- if (ele_addr == unicast + index)
- return jentry;
- }
- return NULL;
- }
- static json_object *get_model(uint16_t unicast, uint16_t ele_addr,
- uint32_t mod_id, bool vendor)
- {
- json_object *jelement, *jarray;
- int i, sz;
- jelement = get_element(unicast, ele_addr);
- if (!jelement)
- return false;
- if (!json_object_object_get_ex(jelement, "models", &jarray))
- return NULL;
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return NULL;
- if (!vendor)
- mod_id = mod_id & ~VENDOR_ID_MASK;
- sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry, *jval;
- uint32_t id, len;
- const char *str;
- jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "modelId",
- &jval))
- return NULL;
- str = json_object_get_string(jval);
- len = strlen(str);
- if (len != 4 && len != 8)
- return NULL;
- if ((len == 4 && vendor) || (len == 8 && !vendor))
- continue;
- if (sscanf(str, "%08x", &id) != 1)
- return NULL;
- if (id == mod_id)
- return jentry;
- }
- return NULL;
- }
- static void jarray_int_del(json_object *jarray, int val)
- {
- int i, sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry;
- jentry = json_object_array_get_idx(jarray, i);
- if (val == json_object_get_int(jentry)) {
- json_object_array_del_idx(jarray, i, 1);
- return;
- }
- }
- }
- static bool update_model_int_array(uint16_t unicast, uint16_t ele_addr,
- bool vendor, uint32_t mod_id,
- int val, const char *keyword, bool add)
- {
- json_object *jarray, *jmod, *jvalue;
- if (!cfg || !cfg->jcfg)
- return false;
- jmod = get_model(unicast, ele_addr, mod_id, vendor);
- if (!jmod)
- return false;
- if (!json_object_object_get_ex(jmod, keyword, &jarray))
- return false;
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jarray_int_del(jarray, val);
- if (!add)
- return true;
- jvalue = json_object_new_int(val);
- if (!jvalue)
- return false;
- json_object_array_add(jarray, jvalue);
- return save_config();
- }
- bool mesh_db_node_model_bind(uint16_t unicast, uint16_t ele_addr, bool vendor,
- uint32_t mod_id, uint16_t app_idx)
- {
- char buf[5];
- snprintf(buf, 5, "%4.4x", app_idx);
- return update_model_int_array(unicast, ele_addr, vendor, mod_id,
- (int) app_idx, "bind", true);
- }
- bool mesh_db_node_model_unbind(uint16_t unicast, uint16_t ele_addr, bool vendor,
- uint32_t mod_id, uint16_t app_idx)
- {
- char buf[5];
- snprintf(buf, 5, "%4.4x", app_idx);
- return update_model_int_array(unicast, ele_addr, vendor, mod_id,
- (int) app_idx, "bind", false);
- }
- static void jarray_string_del(json_object *jarray, const char *str, size_t len)
- {
- int i, sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry;
- char *str_entry;
- jentry = json_object_array_get_idx(jarray, i);
- str_entry = (char *)json_object_get_string(jentry);
- if (str_entry && (strlen(str_entry) == len) &&
- !strncmp(str, str_entry, len)) {
- json_object_array_del_idx(jarray, i, 1);
- return;
- }
- }
- }
- static bool add_array_string(json_object *jarray, const char *str)
- {
- json_object *jstring;
- jstring = json_object_new_string(str);
- if (!jstring)
- return false;
- json_object_array_add(jarray, jstring);
- return true;
- }
- static bool update_model_string_array(uint16_t unicast, uint16_t ele_addr,
- bool vendor, uint32_t mod_id,
- const char *str, uint32_t len,
- const char *keyword, bool add)
- {
- json_object *jarray, *jmod;
- if (!cfg || !cfg->jcfg)
- return false;
- jmod = get_model(unicast, ele_addr, mod_id, vendor);
- if (!jmod)
- return false;
- if (!json_object_object_get_ex(jmod, keyword, &jarray))
- return false;
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jarray_string_del(jarray, str, len);
- if (!add)
- return true;
- if (!add_array_string(jarray, str))
- return false;
- return save_config();
- }
- bool mesh_db_node_model_add_sub(uint16_t unicast, uint16_t ele, bool vendor,
- uint32_t mod_id, uint16_t addr)
- {
- char buf[5];
- snprintf(buf, 5, "%4.4x", addr);
- return update_model_string_array(unicast, ele, vendor, mod_id, buf, 4,
- "subscribe", true);
- }
- bool mesh_db_node_model_del_sub(uint16_t unicast, uint16_t ele, bool vendor,
- uint32_t mod_id, uint16_t addr)
- {
- char buf[5];
- snprintf(buf, 5, "%4.4x", addr);
- return update_model_string_array(unicast, ele, vendor, mod_id, buf, 4,
- "subscribe", false);
- }
- bool mesh_db_node_model_add_sub_virt(uint16_t unicast, uint16_t ele,
- bool vendor, uint32_t mod_id,
- uint8_t *label)
- {
- char buf[33];
- hex2str(label, 16, buf, sizeof(buf));
- return update_model_string_array(unicast, ele, vendor, mod_id, buf, 32,
- "subscribe", true);
- }
- bool mesh_db_node_model_del_sub_virt(uint16_t unicast, uint16_t ele,
- bool vendor, uint32_t mod_id,
- uint8_t *label)
- {
- char buf[33];
- hex2str(label, 16, buf, sizeof(buf));
- return update_model_string_array(unicast, ele, vendor, mod_id, buf, 32,
- "subscribe", false);
- }
- static json_object *delete_subs(uint16_t unicast, uint16_t ele, bool vendor,
- uint32_t mod_id)
- {
- json_object *jarray, *jmod;
- if (!cfg || !cfg->jcfg)
- return NULL;
- jmod = get_model(unicast, ele, mod_id, vendor);
- if (!jmod)
- return NULL;
- json_object_object_del(jmod, "subscribe");
- jarray = json_object_new_array();
- if (!jarray)
- return NULL;
- json_object_object_add(jmod, "subscribe", jarray);
- return jarray;
- }
- bool mesh_db_node_model_del_sub_all(uint16_t unicast, uint16_t ele, bool vendor,
- uint32_t mod_id)
- {
- if (!delete_subs(unicast, ele, vendor, mod_id))
- return false;
- return save_config();
- }
- static bool sub_overwrite(uint16_t unicast, uint16_t ele, bool vendor,
- uint32_t mod_id, char *buf)
- {
- json_object *jarray, *jstring;
- jarray = delete_subs(unicast, ele, vendor, mod_id);
- if (!jarray)
- return false;
- jstring = json_object_new_string(buf);
- if (!jstring)
- return false;
- json_object_array_add(jarray, jstring);
- return save_config();
- }
- bool mesh_db_node_model_overwrt_sub(uint16_t unicast, uint16_t ele, bool vendor,
- uint32_t mod_id, uint16_t addr)
- {
- char buf[5];
- snprintf(buf, 5, "%4.4x", addr);
- return sub_overwrite(unicast, ele, vendor, mod_id, buf);
- }
- bool mesh_db_node_model_overwrt_sub_virt(uint16_t unicast, uint16_t ele,
- bool vendor, uint32_t mod_id,
- uint8_t *label)
- {
- char buf[33];
- hex2str(label, 16, buf, sizeof(buf));
- return sub_overwrite(unicast, ele, vendor, mod_id, buf);
- }
- bool mesh_db_node_model_set_pub(uint16_t unicast, uint16_t ele_addr,
- bool vendor, uint32_t mod_id,
- struct model_pub *pub, bool virt)
- {
- json_object *jmod, *jpub, *jobj = NULL;
- if (!cfg || !cfg->jcfg)
- return false;
- jmod = get_model(unicast, ele_addr, mod_id, vendor);
- if (!jmod)
- return false;
- jpub = json_object_new_object();
- if (!virt && !write_uint16_hex(jpub, "address", pub->u.addr))
- goto fail;
- if (virt) {
- char buf[33];
- hex2str(pub->u.label, 16, buf, sizeof(buf));
- if (!add_string(jpub, "address", buf))
- goto fail;
- }
- if (!write_int(jpub, "index", pub->app_idx))
- goto fail;
- if (!write_int(jpub, "ttl", pub->ttl))
- goto fail;
- if (!write_int(jpub, "credentials", pub->cred ? 1 : 0))
- goto fail;
- if (!add_transmit_info(jpub, pub->rtx_cnt, pub->rtx_interval,
- "retransmit"))
- goto fail;
- jobj = json_object_new_object();
- if (!write_int(jobj, "numberOfSteps", pub->prd_steps))
- goto fail;
- if (!write_int(jobj, "resolution", pub->prd_res))
- goto fail;
- json_object_object_add(jpub, "period", jobj);
- json_object_object_del(jmod, "publish");
- json_object_object_add(jmod, "publish", jpub);
- return save_config();
- fail:
- if (jobj)
- json_object_put(jobj);
- json_object_put(jpub);
- return false;
- }
- bool mesh_db_node_set_hb_pub(uint16_t unicast, uint16_t dst, uint16_t net_idx,
- uint8_t period_log, uint8_t ttl,
- uint16_t features)
- {
- json_object *jnode, *jpub, *jarray = NULL;
- uint32_t period;
- if (!cfg || !cfg->jcfg)
- return false;
- if (period_log > 0x12 || ttl > 0x7F)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- jpub = json_object_new_object();
- if (!write_uint16_hex(jpub, "address", dst))
- goto fail;
- period = period_log ? 1 << (period_log - 1) : 0;
- if (!write_int(jpub, "period", period))
- goto fail;
- if (!write_int(jpub, "ttl", ttl))
- goto fail;
- if (!write_int(jpub, "index", net_idx))
- goto fail;
- jarray = json_object_new_array();
- if (features & FEATURE_PROXY)
- if (!add_array_string(jarray, "proxy"))
- goto fail;
- if (features & FEATURE_RELAY)
- if (!add_array_string(jarray, "relay"))
- goto fail;
- if (features & FEATURE_FRIEND)
- if (!add_array_string(jarray, "friend"))
- goto fail;
- if (features & FEATURE_LPN)
- if (!add_array_string(jarray, "lowPower"))
- goto fail;
- json_object_object_add(jpub, "features", jarray);
- json_object_object_del(jnode, "heartbeatPub");
- json_object_object_add(jnode, "heartbeatPub", jpub);
- return save_config();
- fail:
- if (jarray)
- json_object_put(jarray);
- json_object_put(jpub);
- return false;
- }
- bool mesh_db_node_set_hb_sub(uint16_t unicast, uint16_t src, uint16_t dst)
- {
- json_object *jnode, *jsub;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- jsub = json_object_new_object();
- if (!write_uint16_hex(jsub, "source", src))
- goto fail;
- if (!write_uint16_hex(jsub, "destination", dst))
- goto fail;
- json_object_object_del(jnode, "heartbeatSub");
- json_object_object_add(jnode, "heartbeatSub", jsub);
- return save_config();
- fail:
- json_object_put(jsub);
- return false;
- }
- static void jarray_key_del(json_object *jarray, int16_t idx)
- {
- int i, sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry;
- int val;
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "index", &val))
- continue;
- if (val == idx) {
- json_object_array_del_idx(jarray, i, 1);
- return;
- }
- }
- }
- static bool delete_key(json_object *jobj, const char *desc, uint16_t idx)
- {
- json_object *jarray;
- if (!json_object_object_get_ex(jobj, desc, &jarray))
- return true;
- jarray_key_del(jarray, idx);
- return save_config();
- }
- bool mesh_db_node_add_net_key(uint16_t unicast, uint16_t idx)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- return add_node_key(jnode, "netKeys", idx);
- }
- bool mesh_db_node_del_net_key(uint16_t unicast, uint16_t net_idx)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- return delete_key(jnode, "netKeys", net_idx);
- }
- static bool key_update(uint16_t unicast, int16_t idx, bool updated,
- const char *desc)
- {
- json_object *jnode, *jarray;
- int i, sz;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- if (!json_object_object_get_ex(jnode, desc, &jarray))
- return false;
- sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry;
- int val;
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "index", &val))
- continue;
- if ((val == idx) && write_bool(jentry, "updated", updated))
- return save_config();
- }
- return false;
- }
- bool mesh_db_node_update_net_key(uint16_t unicast, uint16_t idx, bool updated)
- {
- return key_update(unicast, idx, updated, "netKeys");
- }
- bool mesh_db_node_add_app_key(uint16_t unicast, uint16_t idx)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- return add_node_key(jnode, "appKeys", idx);
- }
- bool mesh_db_node_del_app_key(uint16_t unicast, uint16_t idx)
- {
- json_object *jnode;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- return delete_key(jnode, "appKeys", idx);
- }
- bool mesh_db_node_update_app_key(uint16_t unicast, uint16_t idx, bool updated)
- {
- return key_update(unicast, idx, updated, "appKeys");
- }
- static bool load_keys(json_object *jobj)
- {
- json_object *jarray, *jentry;
- int net_idx, app_idx;
- int i, key_cnt;
- json_object_object_get_ex(jobj, "netKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- key_cnt = json_object_array_length(jarray);
- if (key_cnt < 0)
- return false;
- for (i = 0; i < key_cnt; ++i) {
- int phase;
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "index", &net_idx))
- return false;
- keys_add_net_key((uint16_t) net_idx);
- if (!get_int(jentry, "phase", &phase))
- return false;
- keys_set_net_key_phase(net_idx, (uint8_t) phase, false);
- }
- json_object_object_get_ex(jobj, "appKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- key_cnt = json_object_array_length(jarray);
- if (key_cnt < 0)
- return false;
- for (i = 0; i < key_cnt; ++i) {
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "boundNetKey", &net_idx))
- return false;
- if (!get_int(jentry, "index", &app_idx))
- return false;
- keys_add_app_key((uint16_t) net_idx, (uint16_t) app_idx);
- }
- return true;
- }
- bool mesh_db_add_net_key(uint16_t net_idx)
- {
- json_object *jkey, *jarray;
- char buf[12];
- if (!cfg || !cfg->jcfg)
- return false;
- json_object_object_get_ex(cfg->jcfg, "netKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- if (get_key_object(jarray, net_idx))
- return true;
- jkey = json_object_new_object();
- snprintf(buf, 12, "Subnet %4.4x", net_idx);
- if (!add_string(jkey, "name", buf))
- goto fail;
- if (!write_int(jkey, "index", net_idx))
- goto fail;
- if (!write_int(jkey, "phase", KEY_REFRESH_PHASE_NONE))
- goto fail;
- if (!add_string(jkey, "minSecurity", "secure"))
- goto fail;
- if (!set_timestamp(jkey))
- goto fail;
- json_object_array_add(jarray, jkey);
- return save_config();
- fail:
- json_object_put(jkey);
- return false;
- }
- bool mesh_db_del_net_key(uint16_t net_idx)
- {
- if (!cfg || !cfg->jcfg)
- return false;
- return delete_key(cfg->jcfg, "netKeys", net_idx);
- }
- bool mesh_db_set_net_key_phase(uint16_t net_idx, uint8_t phase)
- {
- json_object *jval, *jarray, *jkey;
- if (!cfg || !cfg->jcfg)
- return false;
- json_object_object_get_ex(cfg->jcfg, "netKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jkey = get_key_object(jarray, net_idx);
- if (!jkey)
- return false;
- jval = json_object_new_int(phase);
- if (!jval)
- return false;
- json_object_object_add(jkey, "phase", jval);
- return save_config();
- }
- bool mesh_db_add_app_key(uint16_t net_idx, uint16_t app_idx)
- {
- if (!cfg || !cfg->jcfg)
- return false;
- if (!add_app_key(cfg->jcfg, net_idx, app_idx))
- return false;
- return save_config();
- }
- bool mesh_db_del_app_key(uint16_t app_idx)
- {
- if (!cfg || !cfg->jcfg)
- return false;
- return delete_key(cfg->jcfg, "appKeys", app_idx);
- }
- bool mesh_db_add_group(struct mesh_group *grp)
- {
- json_object *jgroup, *jgroups, *jval;
- char buf[16];
- if (!cfg || !cfg->jcfg)
- return false;
- if (!json_object_object_get_ex(cfg->jcfg, "groups", &jgroups))
- return false;
- jgroup = json_object_new_object();
- if (!jgroup)
- return false;
- snprintf(buf, 11, "Group_%4.4x", grp->addr);
- jval = json_object_new_string(buf);
- json_object_object_add(jgroup, "name", jval);
- if (IS_VIRTUAL(grp->addr)) {
- if (!add_u8_16(jgroup, "address", grp->label))
- goto fail;
- } else {
- if (!write_uint16_hex(jgroup, "address", grp->addr))
- goto fail;
- }
- /* Initialize parent group to unassigned address for now*/
- if (!write_uint16_hex(jgroup, "parentAddress", UNASSIGNED_ADDRESS))
- goto fail;
- json_object_array_add(jgroups, jgroup);
- return save_config();
- fail:
- json_object_put(jgroup);
- return false;
- }
- struct l_queue *mesh_db_load_groups(void)
- {
- json_object *jgroups;
- struct l_queue *groups;
- int i, sz;
- if (!cfg || !cfg->jcfg)
- return NULL;
- if (!json_object_object_get_ex(cfg->jcfg, "groups", &jgroups)) {
- jgroups = json_object_new_array();
- if (!jgroups)
- return NULL;
- json_object_object_add(cfg->jcfg, "groups", jgroups);
- }
- groups = l_queue_new();
- sz = json_object_array_length(jgroups);
- for (i = 0; i < sz; ++i) {
- json_object *jgroup, *jval;
- struct mesh_group *grp;
- uint16_t addr, addr_len;
- const char *str;
- jgroup = json_object_array_get_idx(jgroups, i);
- if (!jgroup)
- continue;
- if (!json_object_object_get_ex(jgroup, "name", &jval))
- continue;
- str = json_object_get_string(jval);
- if (strlen(str) != 10)
- continue;
- if (sscanf(str + 6, "%04hx", &addr) != 1)
- continue;
- if (!json_object_object_get_ex(jgroup, "address", &jval))
- continue;
- str = json_object_get_string(jval);
- addr_len = strlen(str);
- if (addr_len != 4 && addr_len != 32)
- continue;
- if (addr_len == 32 && !IS_VIRTUAL(addr))
- continue;
- grp = l_new(struct mesh_group, 1);
- if (addr_len == 4)
- sscanf(str, "%04hx", &grp->addr);
- else {
- str2hex(str, 32, grp->label, 16);
- grp->addr = addr;
- }
- l_queue_insert(groups, grp, compare_group_addr, NULL);
- }
- return groups;
- }
- static json_object *init_elements(uint8_t num_els)
- {
- json_object *jelements;
- uint8_t i;
- jelements = json_object_new_array();
- for (i = 0; i < num_els; ++i) {
- json_object *jelement, *jmods;
- jelement = json_object_new_object();
- write_int(jelement, "index", i);
- write_uint16_hex(jelement, "location", DEFAULT_LOCATION);
- jmods = json_object_new_array();
- json_object_object_add(jelement, "models", jmods);
- json_object_array_add(jelements, jelement);
- }
- return jelements;
- }
- bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast,
- uint16_t net_idx)
- {
- json_object *jnode;
- json_object *jelements, *jnodes, *jnetkeys, *jappkeys;
- char buf[37];
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_uuid(cfg->jcfg, uuid);
- if (jnode) {
- l_error("Node already exists");
- return false;
- }
- jnode = json_object_new_object();
- if (!jnode)
- return false;
- if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
- goto fail;
- if (!add_string(jnode, "UUID", buf))
- goto fail;
- if (!add_string(jnode, "security", "secure"))
- goto fail;
- if (!write_bool(jnode, "excluded", false))
- goto fail;
- if (!write_bool(jnode, "configComplete", false))
- goto fail;
- jelements = init_elements(num_els);
- json_object_object_add(jnode, "elements", jelements);
- jnetkeys = json_object_new_array();
- if (!jnetkeys)
- goto fail;
- json_object_object_add(jnode, "netKeys", jnetkeys);
- if (!add_node_key(jnode, "netKeys", net_idx))
- goto fail;
- jappkeys = json_object_new_array();
- if (!jappkeys)
- goto fail;
- json_object_object_add(jnode, "appKeys", jappkeys);
- if (!write_uint16_hex(jnode, "unicastAddress", unicast))
- goto fail;
- if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jnodes))
- goto fail;
- json_object_array_add(jnodes, jnode);
- return save_config();
- fail:
- json_object_put(jnode);
- return false;
- }
- bool mesh_db_del_node(uint16_t unicast)
- {
- json_object *jarray;
- int i, sz;
- if (!json_object_object_get_ex(cfg->jcfg, "nodes", &jarray))
- return false;
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- sz = json_object_array_length(jarray);
- for (i = 0; i < sz; ++i) {
- json_object *jentry, *jval;
- uint16_t addr;
- const char *str;
- jentry = json_object_array_get_idx(jarray, i);
- if (!json_object_object_get_ex(jentry, "unicastAddress",
- &jval))
- continue;
- str = json_object_get_string(jval);
- if (sscanf(str, "%04hx", &addr) != 1)
- continue;
- if (addr == unicast)
- break;
- }
- if (i == sz)
- return true;
- json_object_array_del_idx(jarray, i, 1);
- return save_config();
- }
- static json_object *init_model(uint16_t mod_id)
- {
- json_object *jmod, *jarray;
- jmod = json_object_new_object();
- if (!write_uint16_hex(jmod, "modelId", mod_id)) {
- json_object_put(jmod);
- return NULL;
- }
- jarray = json_object_new_array();
- json_object_object_add(jmod, "bind", jarray);
- jarray = json_object_new_array();
- json_object_object_add(jmod, "subscribe", jarray);
- return jmod;
- }
- static json_object *init_vendor_model(uint32_t mod_id)
- {
- json_object *jmod, *jarray;
- jmod = json_object_new_object();
- if (!write_uint32_hex(jmod, "modelId", mod_id)) {
- json_object_put(jmod);
- return NULL;
- }
- jarray = json_object_new_array();
- json_object_object_add(jmod, "bind", jarray);
- jarray = json_object_new_array();
- json_object_object_add(jmod, "subscribe", jarray);
- return jmod;
- }
- bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len)
- {
- uint16_t features;
- int sz, i = 0;
- json_object *jnode, *jobj, *jelements;
- uint16_t crpl;
- if (!cfg || !cfg->jcfg)
- return false;
- jnode = get_node_by_unicast(cfg->jcfg, unicast);
- if (!jnode)
- return false;
- /* skip page -- We only support Page Zero */
- data++;
- len--;
- /* If "crpl" property is present, composition is already recorded */
- if (json_object_object_get_ex(jnode, "crpl", &jobj))
- return true;
- if (!write_uint16_hex(jnode, "cid", l_get_le16(&data[0])))
- return false;
- if (!write_uint16_hex(jnode, "pid", l_get_le16(&data[2])))
- return false;
- if (!write_uint16_hex(jnode, "vid", l_get_le16(&data[4])))
- return false;
- crpl = l_get_le16(&data[6]);
- features = l_get_le16(&data[8]);
- data += 10;
- len -= 10;
- jobj = json_object_object_get(jnode, "features");
- if (!jobj) {
- jobj = json_object_new_object();
- json_object_object_add(jnode, "features", jobj);
- }
- if (!(features & FEATURE_RELAY))
- write_int(jobj, "relay", 2);
- if (!(features & FEATURE_FRIEND))
- write_int(jobj, "friend", 2);
- if (!(features & FEATURE_PROXY))
- write_int(jobj, "proxy", 2);
- if (!(features & FEATURE_LPN))
- write_int(jobj, "lowPower", 2);
- jelements = json_object_object_get(jnode, "elements");
- if (!jelements)
- return false;
- sz = json_object_array_length(jelements);
- while (len) {
- json_object *jentry, *jmods;
- uint32_t mod_id;
- uint8_t m, v;
- /* Mismatch in the element count */
- if (i >= sz)
- return false;
- jentry = json_object_array_get_idx(jelements, i);
- write_int(jentry, "index", i);
- if (!write_uint16_hex(jentry, "location", l_get_le16(data)))
- return false;
- data += 2;
- len -= 2;
- m = *data++;
- v = *data++;
- len -= 2;
- jmods = json_object_object_get(jentry, "models");
- if (!jmods) {
- /* For backwards compatibility */
- jmods = json_object_new_array();
- json_object_object_add(jentry, "models", jmods);
- }
- while (len >= 2 && m--) {
- mod_id = l_get_le16(data);
- jobj = init_model(mod_id);
- if (!jobj)
- goto fail;
- json_object_array_add(jmods, jobj);
- data += 2;
- len -= 2;
- }
- while (len >= 4 && v--) {
- jobj = json_object_new_object();
- mod_id = l_get_le16(data + 2);
- mod_id = l_get_le16(data) << 16 | mod_id;
- jobj = init_vendor_model(mod_id);
- if (!jobj)
- goto fail;
- json_object_array_add(jmods, jobj);
- data += 4;
- len -= 4;
- }
- i++;
- }
- /* CRPL is written last. Will be used to check composition's presence */
- if (!write_uint16_hex(jnode, "crpl", crpl))
- goto fail;
- /* Initiate remote's composition from storage */
- if (!load_composition(jnode, unicast))
- goto fail;
- return save_config();
- fail:
- /* Reset elements array */
- json_object_object_del(jnode, "elements");
- init_elements(sz);
- return false;
- }
- bool mesh_db_get_token(uint8_t token[8])
- {
- if (!cfg || !cfg->jcfg)
- return false;
- memcpy(token, cfg->token, 8);
- return true;
- }
- bool mesh_db_get_addr_range(uint16_t *low, uint16_t *high)
- {
- json_object *jprov, *jarray, *jobj, *jlow, *jhigh;
- const char *str;
- if (!cfg || !cfg->jcfg)
- return false;
- jarray = json_object_object_get(cfg->jcfg, "provisioniers");
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- /* Assumption: only one provisioner in the system */
- jprov = json_object_array_get_idx(jarray, 0);
- if (!jprov)
- return false;
- if (!json_object_object_get_ex(jprov, "allocatedUnicastRange", &jarray))
- return false;
- /* Assumption: only one contiguous range is specified */
- jobj = json_object_array_get_idx(jarray, 0);
- if (!jobj)
- return false;
- if (!json_object_object_get_ex(jobj, "lowAddress", &jlow) ||
- !json_object_object_get_ex(jobj, "highAddress", &jhigh))
- return false;
- str = json_object_get_string(jlow);
- if (sscanf(str, "%04hx", low) != 1)
- return false;
- str = json_object_get_string(jhigh);
- if (sscanf(str, "%04hx", high) != 1)
- return false;
- return true;
- }
- /*
- * This is a simplistic implementation onf allocated range, where
- * the range is one contiguous chunk of the address space.
- */
- static bool add_range(json_object *jobj, const char *keyword, uint16_t low,
- uint16_t high)
- {
- json_object *jarray, *jrange;
- jrange = json_object_new_object();
- if (!write_uint16_hex(jrange, "lowAddress", low))
- goto fail;
- if (!write_uint16_hex(jrange, "highAddress", high))
- goto fail;
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_array_add(jarray, jrange);
- json_object_object_add(jobj, keyword, jarray);
- return true;
- fail:
- json_object_put(jrange);
- return false;
- }
- bool mesh_db_add_provisioner(const char *name, uint8_t uuid[16],
- uint16_t unicast_low, uint16_t unicast_high,
- uint16_t group_low, uint16_t group_high)
- {
- json_object *jprovs, *jprov, *jscenes;
- char buf[37];
- if (!cfg || !cfg->jcfg)
- return false;
- if (!json_object_object_get_ex(cfg->jcfg, "provisioners", &jprovs))
- return false;
- if (!jprovs || json_object_get_type(jprovs) != json_type_array)
- return false;
- jprov = json_object_new_object();
- if (!add_string(jprov, "provisionerName", name))
- goto fail;
- if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
- goto fail;
- if (!add_string(jprov, "UUID", buf))
- goto fail;
- if (!add_range(jprov, "allocatedUnicastRange", unicast_low,
- unicast_high))
- goto fail;
- if (!add_range(jprov, "allocatedGroupRange", group_low, group_high))
- goto fail;
- /* Scenes are not supported. Just add an empty array */
- jscenes = json_object_new_array();
- if (!jscenes)
- goto fail;
- json_object_object_add(jprov, "allocatedSceneRange", jscenes);
- json_object_array_add(jprovs, jprov);
- return save_config();
- fail:
- json_object_put(jprov);
- return false;
- }
- uint32_t mesh_db_get_iv_index(void)
- {
- int ivi;
- if (!cfg || !cfg->jcfg)
- return 0;
- if (!get_int(cfg->jcfg, "ivIndex", &ivi))
- return 0;
- return (uint32_t) ivi;
- }
- bool mesh_db_set_iv_index(uint32_t ivi)
- {
- if (!cfg || !cfg->jcfg)
- return false;
- write_int(cfg->jcfg, "ivIndex", ivi);
- return save_config();
- }
- static int get_rejected_by_iv_index(json_object *jarray, uint32_t iv_index)
- {
- int i, cnt;
- cnt = json_object_array_length(jarray);
- for (i = 0; i < cnt; i++) {
- json_object *jentry;
- int index;
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "ivIndex", &index))
- continue;
- if (iv_index == (uint32_t)index)
- return i;
- }
- return -1;
- }
- static bool load_rejected_addresses(json_object *jobj)
- {
- json_object *jarray;
- int i, cnt;
- json_object_object_get_ex(jobj, "networkExclusions", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return true;
- cnt = json_object_array_length(jarray);
- for (i = 0; i < cnt; i++) {
- json_object *jaddrs, *jentry, *jval;
- int iv_index, addr_cnt, j;
- jentry = json_object_array_get_idx(jarray, i);
- if (!get_int(jentry, "ivIndex", &iv_index))
- return false;
- if (!json_object_object_get_ex(jentry, "addresses",
- &jaddrs))
- return false;
- addr_cnt = json_object_array_length(jaddrs);
- for (j = 0; j < addr_cnt; j++) {
- const char *str;
- uint16_t unicast;
- jval = json_object_array_get_idx(jaddrs, j);
- str = json_object_get_string(jval);
- if (sscanf(str, "%04hx", &unicast) != 1)
- return false;
- remote_add_rejected_address(unicast, iv_index, false);
- }
- }
- return true;
- }
- bool mesh_db_add_rejected_addr(uint16_t unicast, uint32_t iv_index)
- {
- json_object *jarray, *jobj, *jaddrs, *jstring;
- int idx;
- char buf[5];
- if (!cfg || !cfg->jcfg)
- return false;
- json_object_object_get_ex(cfg->jcfg, "networkExclusions", &jarray);
- if (!jarray) {
- jarray = json_object_new_array();
- json_object_object_add(cfg->jcfg, "networkExclusions", jarray);
- }
- idx = get_rejected_by_iv_index(jarray, iv_index);
- if (idx < 0) {
- jobj = json_object_new_object();
- if (!write_int(jobj, "ivIndex", iv_index))
- goto fail;
- jaddrs = json_object_new_array();
- json_object_object_add(jobj, "addresses", jaddrs);
- } else {
- jobj = json_object_array_get_idx(jarray, idx);
- }
- json_object_object_get_ex(jobj, "addresses", &jaddrs);
- snprintf(buf, 5, "%4.4x", unicast);
- jstring = json_object_new_string(buf);
- if (!jstring)
- goto fail;
- json_object_array_add(jaddrs, jstring);
- if (idx < 0)
- json_object_array_add(jarray, jobj);
- return save_config();
- fail:
- json_object_put(jobj);
- return false;
- }
- bool mesh_db_clear_rejected(uint32_t iv_index)
- {
- json_object *jarray;
- int idx;
- if (!cfg || !cfg->jcfg)
- return false;
- json_object_object_get_ex(cfg->jcfg, "networkExclusions", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- idx = get_rejected_by_iv_index(jarray, iv_index);
- if (idx < 0)
- return true;
- json_object_array_del_idx(jarray, idx, 1);
- return save_config();
- }
- bool mesh_db_create(const char *fname, const uint8_t token[8],
- const char *mesh_name)
- {
- json_object *jcfg, *jarray;
- uint8_t uuid[16];
- char buf[37];
- if (cfg)
- return false;
- if (!fname)
- return false;
- jcfg = json_object_new_object();
- if (!jcfg)
- return false;
- cfg = l_new(struct mesh_db, 1);
- cfg->jcfg = jcfg;
- cfg->cfg_fname = l_strdup(fname);
- memcpy(cfg->token, token, 8);
- if (!add_u8_8(jcfg, "token", token))
- goto fail;
- l_uuid_v4(uuid);
- if (!l_uuid_to_string(uuid, buf, sizeof(buf)))
- goto fail;
- if (!add_string(jcfg, "meshUUID", buf))
- goto fail;
- if (mesh_name && !add_string(jcfg, "meshName", mesh_name))
- goto fail;
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_object_add(jcfg, "nodes", jarray);
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_object_add(jcfg, "provisioners", jarray);
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_object_add(jcfg, "netKeys", jarray);
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_object_add(jcfg, "appKeys", jarray);
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_object_add(jcfg, "networkExclusions", jarray);
- write_int(jcfg, "ivIndex", 0);
- if (!save_config())
- goto fail;
- return true;
- fail:
- release_config();
- return false;
- }
- bool mesh_db_load(const char *fname)
- {
- int fd;
- char *str;
- struct stat st;
- ssize_t sz;
- json_object *jcfg;
- fd = open(fname, O_RDONLY);
- if (fd < 0)
- return false;
- if (fstat(fd, &st) == -1) {
- close(fd);
- return false;
- }
- str = (char *) l_new(char, st.st_size + 1);
- if (!str) {
- close(fd);
- return false;
- }
- sz = read(fd, str, st.st_size);
- if (sz != st.st_size) {
- l_error("Failed to read configuration file %s", fname);
- return false;
- }
- jcfg = json_tokener_parse(str);
- close(fd);
- l_free(str);
- if (!jcfg)
- return false;
- cfg = l_new(struct mesh_db, 1);
- cfg->jcfg = jcfg;
- cfg->cfg_fname = l_strdup(fname);
- if (!get_token(jcfg, cfg->token)) {
- l_error("Configuration file missing token");
- goto fail;
- }
- if (!load_keys(jcfg))
- goto fail;
- load_remotes(jcfg);
- load_rejected_addresses(jcfg);
- return true;
- fail:
- release_config();
- return false;
- }
- bool mesh_db_set_device_key(void *expt_cfg, uint16_t unicast, uint8_t key[16])
- {
- json_object *jnode;
- if (!expt_cfg)
- return false;
- jnode = get_node_by_unicast(expt_cfg, unicast);
- if (!jnode)
- return false;
- return add_u8_16(jnode, "deviceKey", key);
- }
- bool mesh_db_set_net_key(void *expt_cfg, uint16_t idx, uint8_t key[16],
- uint8_t *old_key, uint8_t phase)
- {
- json_object *jarray, *jkey;
- if (!expt_cfg)
- return false;
- json_object_object_get_ex(expt_cfg, "netKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jkey = get_key_object(jarray, idx);
- if (!jkey)
- return false;
- if (!write_int(jkey, "phase", phase))
- return false;
- if (!add_u8_16(jkey, "key", key))
- return false;
- if (old_key && !(!add_u8_16(jkey, "oldKey", old_key)))
- return false;
- return true;
- }
- bool mesh_db_set_app_key(void *expt_cfg, uint16_t net_idx, uint16_t app_idx,
- uint8_t key[16], uint8_t *old_key)
- {
- json_object *jarray, *jkey;
- if (!expt_cfg)
- return false;
- json_object_object_get_ex(expt_cfg, "appKeys", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
- jkey = get_key_object(jarray, app_idx);
- if (!jkey)
- return false;
- if (!add_u8_16(jkey, "key", key))
- return false;
- if (old_key && !(!add_u8_16(jkey, "oldKey", old_key)))
- return false;
- return true;
- }
- void *mesh_db_prepare_export(void)
- {
- json_object *export = NULL, *jarray;
- if (!cfg || !cfg->jcfg)
- return false;
- if (json_object_deep_copy(cfg->jcfg, &export, NULL) != 0)
- return NULL;
- /* Delete token */
- json_object_object_del(export, "token");
- /* Delete IV index */
- json_object_object_del(export, "ivIndex");
- /* Scenes are not supported. Just add an empty array */
- jarray = json_object_new_array();
- json_object_object_add(export, "scenes", jarray);
- if (!write_bool(export, "partial", false))
- l_warn("Failed to write\"partial\" property");
- return export;
- }
- bool mesh_db_finish_export(bool is_error, void *expt_cfg, const char *fname)
- {
- FILE *outfile = NULL;
- const char *str, *hdr;
- json_object *jhdr = NULL;
- bool result = false;
- char *pos;
- uint32_t sz;
- if (!expt_cfg)
- return false;
- if (is_error) {
- json_object_put(expt_cfg);
- return true;
- }
- if (!fname)
- goto done;
- outfile = fopen(fname, "w");
- if (!outfile) {
- l_error("Failed to save configuration to %s", fname);
- goto done;
- }
- jhdr = json_object_new_object();
- if (!add_string(jhdr, "$schema", js_schema))
- goto done;
- if (!add_string(jhdr, "id", schema_id))
- goto done;
- if (!add_string(jhdr, "version", schema_version))
- goto done;
- hdr = json_object_to_json_string_ext(jhdr, JSON_C_TO_STRING_PRETTY |
- JSON_C_TO_STRING_NOSLASHESCAPE);
- str = json_object_to_json_string_ext(expt_cfg, JSON_C_TO_STRING_PRETTY |
- JSON_C_TO_STRING_NOSLASHESCAPE);
- if (!hdr || !str)
- goto done;
- /*
- * Write two strings to the output while stripping closing "}" from the
- * header string and opening "{" from the config object.
- */
- pos = strrchr(hdr, '}');
- if (!pos)
- goto done;
- *pos = '\0';
- pos = strrchr(hdr, '"');
- if (!pos)
- goto done;
- pos[1] = ',';
- if (fwrite(hdr, sizeof(char), strlen(hdr), outfile) < strlen(hdr))
- goto done;
- pos = strchr(str, '{');
- if (!pos || pos[1] == '\0')
- goto done;
- pos++;
- sz = strlen(pos);
- if (fwrite(pos, sizeof(char), sz, outfile) < sz)
- goto done;
- result = true;
- done:
- if (outfile)
- fclose(outfile);
- json_object_put(expt_cfg);
- if (jhdr)
- json_object_put(jhdr);
- return result;
- }
|