1*042d53a7SEvalZero /* Bluetooth Mesh */
2*042d53a7SEvalZero
3*042d53a7SEvalZero /*
4*042d53a7SEvalZero * Copyright (c) 2017 Intel Corporation
5*042d53a7SEvalZero *
6*042d53a7SEvalZero * SPDX-License-Identifier: Apache-2.0
7*042d53a7SEvalZero */
8*042d53a7SEvalZero
9*042d53a7SEvalZero #include <errno.h>
10*042d53a7SEvalZero
11*042d53a7SEvalZero #include <os/os_mbuf.h>
12*042d53a7SEvalZero #include "mesh/mesh.h"
13*042d53a7SEvalZero
14*042d53a7SEvalZero #include "syscfg/syscfg.h"
15*042d53a7SEvalZero #define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_ACCESS))
16*042d53a7SEvalZero #include "host/ble_hs_log.h"
17*042d53a7SEvalZero
18*042d53a7SEvalZero #include "mesh_priv.h"
19*042d53a7SEvalZero #include "adv.h"
20*042d53a7SEvalZero #include "net.h"
21*042d53a7SEvalZero #include "lpn.h"
22*042d53a7SEvalZero #include "transport.h"
23*042d53a7SEvalZero #include "access.h"
24*042d53a7SEvalZero #include "foundation.h"
25*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
26*042d53a7SEvalZero #include "mesh/model_cli.h"
27*042d53a7SEvalZero #endif
28*042d53a7SEvalZero
29*042d53a7SEvalZero static const struct bt_mesh_comp *dev_comp;
30*042d53a7SEvalZero static u16_t dev_primary_addr;
31*042d53a7SEvalZero
32*042d53a7SEvalZero static const struct {
33*042d53a7SEvalZero const u16_t id;
34*042d53a7SEvalZero int (*const init)(struct bt_mesh_model *model, bool primary);
35*042d53a7SEvalZero } model_init[] = {
36*042d53a7SEvalZero { BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_init },
37*042d53a7SEvalZero { BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_init },
38*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH_CFG_CLI)
39*042d53a7SEvalZero { BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_init },
40*042d53a7SEvalZero #endif
41*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI)
42*042d53a7SEvalZero { BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_init },
43*042d53a7SEvalZero #endif
44*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
45*042d53a7SEvalZero { BT_MESH_MODEL_ID_GEN_ONOFF_CLI, bt_mesh_gen_model_cli_init },
46*042d53a7SEvalZero { BT_MESH_MODEL_ID_GEN_LEVEL_CLI, bt_mesh_gen_model_cli_init },
47*042d53a7SEvalZero #endif
48*042d53a7SEvalZero };
49*042d53a7SEvalZero
bt_mesh_model_foreach(void (* func)(struct bt_mesh_model * mod,struct bt_mesh_elem * elem,bool vnd,bool primary,void * user_data),void * user_data)50*042d53a7SEvalZero void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
51*042d53a7SEvalZero struct bt_mesh_elem *elem,
52*042d53a7SEvalZero bool vnd, bool primary,
53*042d53a7SEvalZero void *user_data),
54*042d53a7SEvalZero void *user_data)
55*042d53a7SEvalZero {
56*042d53a7SEvalZero int i, j;
57*042d53a7SEvalZero
58*042d53a7SEvalZero for (i = 0; i < dev_comp->elem_count; i++) {
59*042d53a7SEvalZero struct bt_mesh_elem *elem = &dev_comp->elem[i];
60*042d53a7SEvalZero
61*042d53a7SEvalZero for (j = 0; j < elem->model_count; j++) {
62*042d53a7SEvalZero struct bt_mesh_model *model = &elem->models[j];
63*042d53a7SEvalZero
64*042d53a7SEvalZero func(model, elem, false, i == 0, user_data);
65*042d53a7SEvalZero }
66*042d53a7SEvalZero
67*042d53a7SEvalZero for (j = 0; j < elem->vnd_model_count; j++) {
68*042d53a7SEvalZero struct bt_mesh_model *model = &elem->vnd_models[j];
69*042d53a7SEvalZero
70*042d53a7SEvalZero func(model, elem, true, i == 0, user_data);
71*042d53a7SEvalZero }
72*042d53a7SEvalZero }
73*042d53a7SEvalZero }
74*042d53a7SEvalZero
bt_mesh_model_pub_period_get(struct bt_mesh_model * mod)75*042d53a7SEvalZero s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
76*042d53a7SEvalZero {
77*042d53a7SEvalZero int period;
78*042d53a7SEvalZero
79*042d53a7SEvalZero if (!mod->pub) {
80*042d53a7SEvalZero return 0;
81*042d53a7SEvalZero }
82*042d53a7SEvalZero
83*042d53a7SEvalZero switch (mod->pub->period >> 6) {
84*042d53a7SEvalZero case 0x00:
85*042d53a7SEvalZero /* 1 step is 100 ms */
86*042d53a7SEvalZero period = K_MSEC((mod->pub->period & BIT_MASK(6)) * 100);
87*042d53a7SEvalZero break;
88*042d53a7SEvalZero case 0x01:
89*042d53a7SEvalZero /* 1 step is 1 second */
90*042d53a7SEvalZero period = K_SECONDS(mod->pub->period & BIT_MASK(6));
91*042d53a7SEvalZero break;
92*042d53a7SEvalZero case 0x02:
93*042d53a7SEvalZero /* 1 step is 10 seconds */
94*042d53a7SEvalZero period = K_SECONDS((mod->pub->period & BIT_MASK(6)) * 10);
95*042d53a7SEvalZero break;
96*042d53a7SEvalZero case 0x03:
97*042d53a7SEvalZero /* 1 step is 10 minutes */
98*042d53a7SEvalZero period = K_MINUTES((mod->pub->period & BIT_MASK(6)) * 10);
99*042d53a7SEvalZero break;
100*042d53a7SEvalZero default:
101*042d53a7SEvalZero CODE_UNREACHABLE;
102*042d53a7SEvalZero }
103*042d53a7SEvalZero
104*042d53a7SEvalZero return period >> mod->pub->period_div;
105*042d53a7SEvalZero }
106*042d53a7SEvalZero
next_period(struct bt_mesh_model * mod)107*042d53a7SEvalZero static s32_t next_period(struct bt_mesh_model *mod)
108*042d53a7SEvalZero {
109*042d53a7SEvalZero struct bt_mesh_model_pub *pub = mod->pub;
110*042d53a7SEvalZero u32_t elapsed, period;
111*042d53a7SEvalZero
112*042d53a7SEvalZero period = bt_mesh_model_pub_period_get(mod);
113*042d53a7SEvalZero if (!period) {
114*042d53a7SEvalZero return 0;
115*042d53a7SEvalZero }
116*042d53a7SEvalZero
117*042d53a7SEvalZero elapsed = k_uptime_get_32() - pub->period_start;
118*042d53a7SEvalZero
119*042d53a7SEvalZero BT_DBG("Publishing took %ums", elapsed);
120*042d53a7SEvalZero
121*042d53a7SEvalZero if (elapsed > period) {
122*042d53a7SEvalZero BT_WARN("Publication sending took longer than the period");
123*042d53a7SEvalZero /* Return smallest positive number since 0 means disabled */
124*042d53a7SEvalZero return K_MSEC(1);
125*042d53a7SEvalZero }
126*042d53a7SEvalZero
127*042d53a7SEvalZero return period - elapsed;
128*042d53a7SEvalZero }
129*042d53a7SEvalZero
publish_sent(int err,void * user_data)130*042d53a7SEvalZero static void publish_sent(int err, void *user_data)
131*042d53a7SEvalZero {
132*042d53a7SEvalZero struct bt_mesh_model *mod = user_data;
133*042d53a7SEvalZero s32_t delay;
134*042d53a7SEvalZero
135*042d53a7SEvalZero BT_DBG("err %d", err);
136*042d53a7SEvalZero
137*042d53a7SEvalZero if (mod->pub->count) {
138*042d53a7SEvalZero delay = BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit);
139*042d53a7SEvalZero } else {
140*042d53a7SEvalZero delay = next_period(mod);
141*042d53a7SEvalZero }
142*042d53a7SEvalZero
143*042d53a7SEvalZero if (delay) {
144*042d53a7SEvalZero BT_DBG("Publishing next time in %dms", delay);
145*042d53a7SEvalZero k_delayed_work_submit(&mod->pub->timer, delay);
146*042d53a7SEvalZero }
147*042d53a7SEvalZero }
148*042d53a7SEvalZero
149*042d53a7SEvalZero static const struct bt_mesh_send_cb pub_sent_cb = {
150*042d53a7SEvalZero .end = publish_sent,
151*042d53a7SEvalZero };
152*042d53a7SEvalZero
publish_retransmit(struct bt_mesh_model * mod)153*042d53a7SEvalZero static int publish_retransmit(struct bt_mesh_model *mod)
154*042d53a7SEvalZero {
155*042d53a7SEvalZero struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
156*042d53a7SEvalZero struct bt_mesh_model_pub *pub = mod->pub;
157*042d53a7SEvalZero struct bt_mesh_app_key *key;
158*042d53a7SEvalZero struct bt_mesh_msg_ctx ctx = {
159*042d53a7SEvalZero .addr = pub->addr,
160*042d53a7SEvalZero .send_ttl = pub->ttl,
161*042d53a7SEvalZero };
162*042d53a7SEvalZero struct bt_mesh_net_tx tx = {
163*042d53a7SEvalZero .ctx = &ctx,
164*042d53a7SEvalZero .src = bt_mesh_model_elem(mod)->addr,
165*042d53a7SEvalZero .xmit = bt_mesh_net_transmit_get(),
166*042d53a7SEvalZero .friend_cred = pub->cred,
167*042d53a7SEvalZero };
168*042d53a7SEvalZero int err;
169*042d53a7SEvalZero
170*042d53a7SEvalZero key = bt_mesh_app_key_find(pub->key);
171*042d53a7SEvalZero if (!key) {
172*042d53a7SEvalZero err = -EADDRNOTAVAIL;
173*042d53a7SEvalZero goto done;
174*042d53a7SEvalZero }
175*042d53a7SEvalZero
176*042d53a7SEvalZero tx.sub = bt_mesh_subnet_get(key->net_idx);
177*042d53a7SEvalZero
178*042d53a7SEvalZero ctx.net_idx = key->net_idx;
179*042d53a7SEvalZero ctx.app_idx = key->app_idx;
180*042d53a7SEvalZero
181*042d53a7SEvalZero net_buf_simple_init(sdu, 0);
182*042d53a7SEvalZero net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len);
183*042d53a7SEvalZero
184*042d53a7SEvalZero pub->count--;
185*042d53a7SEvalZero
186*042d53a7SEvalZero err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod);
187*042d53a7SEvalZero
188*042d53a7SEvalZero done:
189*042d53a7SEvalZero os_mbuf_free_chain(sdu);
190*042d53a7SEvalZero return err;
191*042d53a7SEvalZero }
192*042d53a7SEvalZero
mod_publish(struct ble_npl_event * work)193*042d53a7SEvalZero static void mod_publish(struct ble_npl_event *work)
194*042d53a7SEvalZero {
195*042d53a7SEvalZero struct bt_mesh_model_pub *pub = ble_npl_event_get_arg(work);
196*042d53a7SEvalZero s32_t period_ms;
197*042d53a7SEvalZero int err;
198*042d53a7SEvalZero
199*042d53a7SEvalZero BT_DBG("");
200*042d53a7SEvalZero
201*042d53a7SEvalZero period_ms = bt_mesh_model_pub_period_get(pub->mod);
202*042d53a7SEvalZero BT_DBG("period %u ms", period_ms);
203*042d53a7SEvalZero
204*042d53a7SEvalZero if (pub->count) {
205*042d53a7SEvalZero err = publish_retransmit(pub->mod);
206*042d53a7SEvalZero if (err) {
207*042d53a7SEvalZero BT_ERR("Failed to retransmit (err %d)", err);
208*042d53a7SEvalZero
209*042d53a7SEvalZero pub->count = 0;
210*042d53a7SEvalZero
211*042d53a7SEvalZero /* Continue with normal publication */
212*042d53a7SEvalZero if (period_ms) {
213*042d53a7SEvalZero k_delayed_work_submit(&pub->timer, period_ms);
214*042d53a7SEvalZero }
215*042d53a7SEvalZero }
216*042d53a7SEvalZero
217*042d53a7SEvalZero return;
218*042d53a7SEvalZero }
219*042d53a7SEvalZero
220*042d53a7SEvalZero if (!period_ms) {
221*042d53a7SEvalZero return;
222*042d53a7SEvalZero }
223*042d53a7SEvalZero
224*042d53a7SEvalZero __ASSERT_NO_MSG(pub->update != NULL);
225*042d53a7SEvalZero
226*042d53a7SEvalZero pub->period_start = k_uptime_get_32();
227*042d53a7SEvalZero
228*042d53a7SEvalZero err = pub->update(pub->mod);
229*042d53a7SEvalZero if (err) {
230*042d53a7SEvalZero BT_ERR("Failed to update publication message");
231*042d53a7SEvalZero return;
232*042d53a7SEvalZero }
233*042d53a7SEvalZero
234*042d53a7SEvalZero err = bt_mesh_model_publish(pub->mod);
235*042d53a7SEvalZero if (err) {
236*042d53a7SEvalZero BT_ERR("Publishing failed (err %d)", err);
237*042d53a7SEvalZero }
238*042d53a7SEvalZero
239*042d53a7SEvalZero if (pub->count) {
240*042d53a7SEvalZero /* Retransmissions also control the timer */
241*042d53a7SEvalZero k_delayed_work_cancel(&pub->timer);
242*042d53a7SEvalZero }
243*042d53a7SEvalZero }
244*042d53a7SEvalZero
bt_mesh_model_elem(struct bt_mesh_model * mod)245*042d53a7SEvalZero struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod)
246*042d53a7SEvalZero {
247*042d53a7SEvalZero return &dev_comp->elem[mod->elem_idx];
248*042d53a7SEvalZero }
249*042d53a7SEvalZero
bt_mesh_model_get(bool vnd,u8_t elem_idx,u8_t mod_idx)250*042d53a7SEvalZero struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx)
251*042d53a7SEvalZero {
252*042d53a7SEvalZero struct bt_mesh_elem *elem;
253*042d53a7SEvalZero
254*042d53a7SEvalZero if (elem_idx >= dev_comp->elem_count) {
255*042d53a7SEvalZero BT_ERR("Invalid element index %u", elem_idx);
256*042d53a7SEvalZero return NULL;
257*042d53a7SEvalZero }
258*042d53a7SEvalZero
259*042d53a7SEvalZero elem = &dev_comp->elem[elem_idx];
260*042d53a7SEvalZero
261*042d53a7SEvalZero if (vnd) {
262*042d53a7SEvalZero if (mod_idx >= elem->vnd_model_count) {
263*042d53a7SEvalZero BT_ERR("Invalid vendor model index %u", mod_idx);
264*042d53a7SEvalZero return NULL;
265*042d53a7SEvalZero }
266*042d53a7SEvalZero
267*042d53a7SEvalZero return &elem->vnd_models[mod_idx];
268*042d53a7SEvalZero } else {
269*042d53a7SEvalZero if (mod_idx >= elem->model_count) {
270*042d53a7SEvalZero BT_ERR("Invalid SIG model index %u", mod_idx);
271*042d53a7SEvalZero return NULL;
272*042d53a7SEvalZero }
273*042d53a7SEvalZero
274*042d53a7SEvalZero return &elem->models[mod_idx];
275*042d53a7SEvalZero }
276*042d53a7SEvalZero }
277*042d53a7SEvalZero
mod_init(struct bt_mesh_model * mod,struct bt_mesh_elem * elem,bool vnd,bool primary,void * user_data)278*042d53a7SEvalZero static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
279*042d53a7SEvalZero bool vnd, bool primary, void *user_data)
280*042d53a7SEvalZero {
281*042d53a7SEvalZero int i;
282*042d53a7SEvalZero
283*042d53a7SEvalZero if (mod->pub) {
284*042d53a7SEvalZero mod->pub->mod = mod;
285*042d53a7SEvalZero k_delayed_work_init(&mod->pub->timer, mod_publish);
286*042d53a7SEvalZero k_delayed_work_add_arg(&mod->pub->timer, mod->pub);
287*042d53a7SEvalZero }
288*042d53a7SEvalZero
289*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
290*042d53a7SEvalZero mod->keys[i] = BT_MESH_KEY_UNUSED;
291*042d53a7SEvalZero }
292*042d53a7SEvalZero
293*042d53a7SEvalZero mod->elem_idx = elem - dev_comp->elem;
294*042d53a7SEvalZero if (vnd) {
295*042d53a7SEvalZero mod->mod_idx = mod - elem->vnd_models;
296*042d53a7SEvalZero } else {
297*042d53a7SEvalZero mod->mod_idx = mod - elem->models;
298*042d53a7SEvalZero }
299*042d53a7SEvalZero
300*042d53a7SEvalZero if (vnd) {
301*042d53a7SEvalZero return;
302*042d53a7SEvalZero }
303*042d53a7SEvalZero
304*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(model_init); i++) {
305*042d53a7SEvalZero if (model_init[i].id == mod->id) {
306*042d53a7SEvalZero model_init[i].init(mod, primary);
307*042d53a7SEvalZero }
308*042d53a7SEvalZero }
309*042d53a7SEvalZero }
310*042d53a7SEvalZero
bt_mesh_comp_register(const struct bt_mesh_comp * comp)311*042d53a7SEvalZero int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
312*042d53a7SEvalZero {
313*042d53a7SEvalZero /* There must be at least one element */
314*042d53a7SEvalZero if (!comp->elem_count) {
315*042d53a7SEvalZero return -EINVAL;
316*042d53a7SEvalZero }
317*042d53a7SEvalZero
318*042d53a7SEvalZero dev_comp = comp;
319*042d53a7SEvalZero
320*042d53a7SEvalZero bt_mesh_model_foreach(mod_init, NULL);
321*042d53a7SEvalZero
322*042d53a7SEvalZero return 0;
323*042d53a7SEvalZero }
324*042d53a7SEvalZero
bt_mesh_comp_provision(u16_t addr)325*042d53a7SEvalZero void bt_mesh_comp_provision(u16_t addr)
326*042d53a7SEvalZero {
327*042d53a7SEvalZero int i;
328*042d53a7SEvalZero
329*042d53a7SEvalZero dev_primary_addr = addr;
330*042d53a7SEvalZero
331*042d53a7SEvalZero BT_DBG("addr 0x%04x elem_count %zu", addr, dev_comp->elem_count);
332*042d53a7SEvalZero
333*042d53a7SEvalZero for (i = 0; i < dev_comp->elem_count; i++) {
334*042d53a7SEvalZero struct bt_mesh_elem *elem = &dev_comp->elem[i];
335*042d53a7SEvalZero
336*042d53a7SEvalZero elem->addr = addr++;
337*042d53a7SEvalZero
338*042d53a7SEvalZero BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u",
339*042d53a7SEvalZero elem->addr, elem->model_count, elem->vnd_model_count);
340*042d53a7SEvalZero }
341*042d53a7SEvalZero }
342*042d53a7SEvalZero
bt_mesh_comp_unprovision(void)343*042d53a7SEvalZero void bt_mesh_comp_unprovision(void)
344*042d53a7SEvalZero {
345*042d53a7SEvalZero BT_DBG("");
346*042d53a7SEvalZero
347*042d53a7SEvalZero dev_primary_addr = BT_MESH_ADDR_UNASSIGNED;
348*042d53a7SEvalZero
349*042d53a7SEvalZero bt_mesh_model_foreach(mod_init, NULL);
350*042d53a7SEvalZero }
351*042d53a7SEvalZero
bt_mesh_primary_addr(void)352*042d53a7SEvalZero u16_t bt_mesh_primary_addr(void)
353*042d53a7SEvalZero {
354*042d53a7SEvalZero return dev_primary_addr;
355*042d53a7SEvalZero }
356*042d53a7SEvalZero
bt_mesh_model_find_group(struct bt_mesh_model * mod,u16_t addr)357*042d53a7SEvalZero u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr)
358*042d53a7SEvalZero {
359*042d53a7SEvalZero int i;
360*042d53a7SEvalZero
361*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
362*042d53a7SEvalZero if (mod->groups[i] == addr) {
363*042d53a7SEvalZero return &mod->groups[i];
364*042d53a7SEvalZero }
365*042d53a7SEvalZero }
366*042d53a7SEvalZero
367*042d53a7SEvalZero return NULL;
368*042d53a7SEvalZero }
369*042d53a7SEvalZero
bt_mesh_elem_find_group(struct bt_mesh_elem * elem,u16_t group_addr)370*042d53a7SEvalZero static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
371*042d53a7SEvalZero u16_t group_addr)
372*042d53a7SEvalZero {
373*042d53a7SEvalZero struct bt_mesh_model *model;
374*042d53a7SEvalZero u16_t *match;
375*042d53a7SEvalZero int i;
376*042d53a7SEvalZero
377*042d53a7SEvalZero for (i = 0; i < elem->model_count; i++) {
378*042d53a7SEvalZero model = &elem->models[i];
379*042d53a7SEvalZero
380*042d53a7SEvalZero match = bt_mesh_model_find_group(model, group_addr);
381*042d53a7SEvalZero if (match) {
382*042d53a7SEvalZero return model;
383*042d53a7SEvalZero }
384*042d53a7SEvalZero }
385*042d53a7SEvalZero
386*042d53a7SEvalZero for (i = 0; i < elem->vnd_model_count; i++) {
387*042d53a7SEvalZero model = &elem->vnd_models[i];
388*042d53a7SEvalZero
389*042d53a7SEvalZero match = bt_mesh_model_find_group(model, group_addr);
390*042d53a7SEvalZero if (match) {
391*042d53a7SEvalZero return model;
392*042d53a7SEvalZero }
393*042d53a7SEvalZero }
394*042d53a7SEvalZero
395*042d53a7SEvalZero return NULL;
396*042d53a7SEvalZero }
397*042d53a7SEvalZero
bt_mesh_elem_find(u16_t addr)398*042d53a7SEvalZero struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr)
399*042d53a7SEvalZero {
400*042d53a7SEvalZero int i;
401*042d53a7SEvalZero
402*042d53a7SEvalZero for (i = 0; i < dev_comp->elem_count; i++) {
403*042d53a7SEvalZero struct bt_mesh_elem *elem = &dev_comp->elem[i];
404*042d53a7SEvalZero
405*042d53a7SEvalZero if (BT_MESH_ADDR_IS_GROUP(addr) ||
406*042d53a7SEvalZero BT_MESH_ADDR_IS_VIRTUAL(addr)) {
407*042d53a7SEvalZero if (bt_mesh_elem_find_group(elem, addr)) {
408*042d53a7SEvalZero return elem;
409*042d53a7SEvalZero }
410*042d53a7SEvalZero } else if (elem->addr == addr) {
411*042d53a7SEvalZero return elem;
412*042d53a7SEvalZero }
413*042d53a7SEvalZero }
414*042d53a7SEvalZero
415*042d53a7SEvalZero return NULL;
416*042d53a7SEvalZero }
417*042d53a7SEvalZero
bt_mesh_elem_count(void)418*042d53a7SEvalZero u8_t bt_mesh_elem_count(void)
419*042d53a7SEvalZero {
420*042d53a7SEvalZero return dev_comp->elem_count;
421*042d53a7SEvalZero }
422*042d53a7SEvalZero
model_has_key(struct bt_mesh_model * mod,u16_t key)423*042d53a7SEvalZero static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
424*042d53a7SEvalZero {
425*042d53a7SEvalZero int i;
426*042d53a7SEvalZero
427*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
428*042d53a7SEvalZero if (mod->keys[i] == key) {
429*042d53a7SEvalZero return true;
430*042d53a7SEvalZero }
431*042d53a7SEvalZero }
432*042d53a7SEvalZero
433*042d53a7SEvalZero return false;
434*042d53a7SEvalZero }
435*042d53a7SEvalZero
find_op(struct bt_mesh_model * models,u8_t model_count,u16_t dst,u16_t app_idx,u32_t opcode,struct bt_mesh_model ** model)436*042d53a7SEvalZero static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
437*042d53a7SEvalZero u8_t model_count, u16_t dst,
438*042d53a7SEvalZero u16_t app_idx, u32_t opcode,
439*042d53a7SEvalZero struct bt_mesh_model **model)
440*042d53a7SEvalZero {
441*042d53a7SEvalZero u8_t i;
442*042d53a7SEvalZero
443*042d53a7SEvalZero for (i = 0; i < model_count; i++) {
444*042d53a7SEvalZero const struct bt_mesh_model_op *op;
445*042d53a7SEvalZero
446*042d53a7SEvalZero *model = &models[i];
447*042d53a7SEvalZero
448*042d53a7SEvalZero if (BT_MESH_ADDR_IS_GROUP(dst) ||
449*042d53a7SEvalZero BT_MESH_ADDR_IS_VIRTUAL(dst)) {
450*042d53a7SEvalZero if (!bt_mesh_model_find_group(*model, dst)) {
451*042d53a7SEvalZero continue;
452*042d53a7SEvalZero }
453*042d53a7SEvalZero }
454*042d53a7SEvalZero
455*042d53a7SEvalZero if (!model_has_key(*model, app_idx)) {
456*042d53a7SEvalZero continue;
457*042d53a7SEvalZero }
458*042d53a7SEvalZero
459*042d53a7SEvalZero for (op = (*model)->op; op->func; op++) {
460*042d53a7SEvalZero if (op->opcode == opcode) {
461*042d53a7SEvalZero return op;
462*042d53a7SEvalZero }
463*042d53a7SEvalZero }
464*042d53a7SEvalZero }
465*042d53a7SEvalZero
466*042d53a7SEvalZero *model = NULL;
467*042d53a7SEvalZero return NULL;
468*042d53a7SEvalZero }
469*042d53a7SEvalZero
get_opcode(struct os_mbuf * buf,u32_t * opcode)470*042d53a7SEvalZero static int get_opcode(struct os_mbuf *buf, u32_t *opcode)
471*042d53a7SEvalZero {
472*042d53a7SEvalZero switch (buf->om_data[0] >> 6) {
473*042d53a7SEvalZero case 0x00:
474*042d53a7SEvalZero case 0x01:
475*042d53a7SEvalZero if (buf->om_data[0] == 0x7f) {
476*042d53a7SEvalZero BT_ERR("Ignoring RFU OpCode");
477*042d53a7SEvalZero return -EINVAL;
478*042d53a7SEvalZero }
479*042d53a7SEvalZero
480*042d53a7SEvalZero *opcode = net_buf_simple_pull_u8(buf);
481*042d53a7SEvalZero return 0;
482*042d53a7SEvalZero case 0x02:
483*042d53a7SEvalZero if (buf->om_len < 2) {
484*042d53a7SEvalZero BT_ERR("Too short payload for 2-octet OpCode");
485*042d53a7SEvalZero return -EINVAL;
486*042d53a7SEvalZero }
487*042d53a7SEvalZero
488*042d53a7SEvalZero *opcode = net_buf_simple_pull_be16(buf);
489*042d53a7SEvalZero return 0;
490*042d53a7SEvalZero case 0x03:
491*042d53a7SEvalZero if (buf->om_len < 3) {
492*042d53a7SEvalZero BT_ERR("Too short payload for 3-octet OpCode");
493*042d53a7SEvalZero return -EINVAL;
494*042d53a7SEvalZero }
495*042d53a7SEvalZero
496*042d53a7SEvalZero *opcode = net_buf_simple_pull_u8(buf) << 16;
497*042d53a7SEvalZero *opcode |= net_buf_simple_pull_le16(buf);
498*042d53a7SEvalZero return 0;
499*042d53a7SEvalZero }
500*042d53a7SEvalZero
501*042d53a7SEvalZero CODE_UNREACHABLE;
502*042d53a7SEvalZero }
503*042d53a7SEvalZero
bt_mesh_fixed_group_match(u16_t addr)504*042d53a7SEvalZero bool bt_mesh_fixed_group_match(u16_t addr)
505*042d53a7SEvalZero {
506*042d53a7SEvalZero /* Check for fixed group addresses */
507*042d53a7SEvalZero switch (addr) {
508*042d53a7SEvalZero case BT_MESH_ADDR_ALL_NODES:
509*042d53a7SEvalZero return true;
510*042d53a7SEvalZero case BT_MESH_ADDR_PROXIES:
511*042d53a7SEvalZero /* TODO: Proxy not yet supported */
512*042d53a7SEvalZero return false;
513*042d53a7SEvalZero case BT_MESH_ADDR_FRIENDS:
514*042d53a7SEvalZero return (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED);
515*042d53a7SEvalZero case BT_MESH_ADDR_RELAYS:
516*042d53a7SEvalZero return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
517*042d53a7SEvalZero default:
518*042d53a7SEvalZero return false;
519*042d53a7SEvalZero }
520*042d53a7SEvalZero }
521*042d53a7SEvalZero
bt_mesh_model_recv(struct bt_mesh_net_rx * rx,struct os_mbuf * buf)522*042d53a7SEvalZero void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
523*042d53a7SEvalZero {
524*042d53a7SEvalZero struct bt_mesh_model *models, *model;
525*042d53a7SEvalZero const struct bt_mesh_model_op *op;
526*042d53a7SEvalZero u32_t opcode;
527*042d53a7SEvalZero u8_t count;
528*042d53a7SEvalZero int i;
529*042d53a7SEvalZero
530*042d53a7SEvalZero BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx,
531*042d53a7SEvalZero rx->ctx.addr, rx->ctx.recv_dst);
532*042d53a7SEvalZero BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
533*042d53a7SEvalZero
534*042d53a7SEvalZero if (get_opcode(buf, &opcode) < 0) {
535*042d53a7SEvalZero BT_WARN("Unable to decode OpCode");
536*042d53a7SEvalZero return;
537*042d53a7SEvalZero }
538*042d53a7SEvalZero
539*042d53a7SEvalZero BT_DBG("OpCode 0x%08x", opcode);
540*042d53a7SEvalZero
541*042d53a7SEvalZero for (i = 0; i < dev_comp->elem_count; i++) {
542*042d53a7SEvalZero struct bt_mesh_elem *elem = &dev_comp->elem[i];
543*042d53a7SEvalZero
544*042d53a7SEvalZero if (BT_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) {
545*042d53a7SEvalZero if (elem->addr != rx->ctx.recv_dst) {
546*042d53a7SEvalZero continue;
547*042d53a7SEvalZero }
548*042d53a7SEvalZero } else if (BT_MESH_ADDR_IS_GROUP(rx->ctx.recv_dst) ||
549*042d53a7SEvalZero BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
550*042d53a7SEvalZero /* find_op() will do proper model/group matching */
551*042d53a7SEvalZero } else if (i != 0 ||
552*042d53a7SEvalZero !bt_mesh_fixed_group_match(rx->ctx.recv_dst)) {
553*042d53a7SEvalZero continue;
554*042d53a7SEvalZero }
555*042d53a7SEvalZero
556*042d53a7SEvalZero /* SIG models cannot contain 3-byte (vendor) OpCodes, and
557*042d53a7SEvalZero * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so
558*042d53a7SEvalZero * we only need to do the lookup in one of the model lists.
559*042d53a7SEvalZero */
560*042d53a7SEvalZero if (opcode < 0x10000) {
561*042d53a7SEvalZero models = elem->models;
562*042d53a7SEvalZero count = elem->model_count;
563*042d53a7SEvalZero } else {
564*042d53a7SEvalZero models = elem->vnd_models;
565*042d53a7SEvalZero count = elem->vnd_model_count;
566*042d53a7SEvalZero }
567*042d53a7SEvalZero
568*042d53a7SEvalZero op = find_op(models, count, rx->ctx.recv_dst, rx->ctx.app_idx,
569*042d53a7SEvalZero opcode, &model);
570*042d53a7SEvalZero if (op) {
571*042d53a7SEvalZero struct net_buf_simple_state state;
572*042d53a7SEvalZero
573*042d53a7SEvalZero if (buf->om_len < op->min_len) {
574*042d53a7SEvalZero BT_ERR("Too short message for OpCode 0x%08x",
575*042d53a7SEvalZero opcode);
576*042d53a7SEvalZero continue;
577*042d53a7SEvalZero }
578*042d53a7SEvalZero
579*042d53a7SEvalZero /* The callback will likely parse the buffer, so
580*042d53a7SEvalZero * store the parsing state in case multiple models
581*042d53a7SEvalZero * receive the message.
582*042d53a7SEvalZero */
583*042d53a7SEvalZero net_buf_simple_save(buf, &state);
584*042d53a7SEvalZero op->func(model, &rx->ctx, buf);
585*042d53a7SEvalZero net_buf_simple_restore(buf, &state);
586*042d53a7SEvalZero
587*042d53a7SEvalZero } else {
588*042d53a7SEvalZero BT_DBG("No OpCode 0x%08x for elem %d", opcode, i);
589*042d53a7SEvalZero }
590*042d53a7SEvalZero }
591*042d53a7SEvalZero }
592*042d53a7SEvalZero
bt_mesh_model_msg_init(struct os_mbuf * msg,u32_t opcode)593*042d53a7SEvalZero void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode)
594*042d53a7SEvalZero {
595*042d53a7SEvalZero net_buf_simple_init(msg, 0);
596*042d53a7SEvalZero
597*042d53a7SEvalZero if (opcode < 0x100) {
598*042d53a7SEvalZero /* 1-byte OpCode */
599*042d53a7SEvalZero net_buf_simple_add_u8(msg, opcode);
600*042d53a7SEvalZero return;
601*042d53a7SEvalZero }
602*042d53a7SEvalZero
603*042d53a7SEvalZero if (opcode < 0x10000) {
604*042d53a7SEvalZero /* 2-byte OpCode */
605*042d53a7SEvalZero net_buf_simple_add_be16(msg, opcode);
606*042d53a7SEvalZero return;
607*042d53a7SEvalZero }
608*042d53a7SEvalZero
609*042d53a7SEvalZero /* 3-byte OpCode */
610*042d53a7SEvalZero net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
611*042d53a7SEvalZero net_buf_simple_add_le16(msg, opcode & 0xffff);
612*042d53a7SEvalZero }
613*042d53a7SEvalZero
model_send(struct bt_mesh_model * model,struct bt_mesh_net_tx * tx,bool implicit_bind,struct os_mbuf * msg,const struct bt_mesh_send_cb * cb,void * cb_data)614*042d53a7SEvalZero static int model_send(struct bt_mesh_model *model,
615*042d53a7SEvalZero struct bt_mesh_net_tx *tx, bool implicit_bind,
616*042d53a7SEvalZero struct os_mbuf *msg,
617*042d53a7SEvalZero const struct bt_mesh_send_cb *cb, void *cb_data)
618*042d53a7SEvalZero {
619*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx,
620*042d53a7SEvalZero tx->ctx->app_idx, tx->ctx->addr);
621*042d53a7SEvalZero BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len));
622*042d53a7SEvalZero
623*042d53a7SEvalZero if (!bt_mesh_is_provisioned()) {
624*042d53a7SEvalZero BT_ERR("Local node is not yet provisioned");
625*042d53a7SEvalZero return -EAGAIN;
626*042d53a7SEvalZero }
627*042d53a7SEvalZero
628*042d53a7SEvalZero if (net_buf_simple_tailroom(msg) < 4) {
629*042d53a7SEvalZero BT_ERR("Not enough tailroom for TransMIC");
630*042d53a7SEvalZero return -EINVAL;
631*042d53a7SEvalZero }
632*042d53a7SEvalZero
633*042d53a7SEvalZero if (msg->om_len > BT_MESH_TX_SDU_MAX - 4) {
634*042d53a7SEvalZero BT_ERR("Too big message");
635*042d53a7SEvalZero return -EMSGSIZE;
636*042d53a7SEvalZero }
637*042d53a7SEvalZero
638*042d53a7SEvalZero if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) {
639*042d53a7SEvalZero BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx);
640*042d53a7SEvalZero return -EINVAL;
641*042d53a7SEvalZero }
642*042d53a7SEvalZero
643*042d53a7SEvalZero return bt_mesh_trans_send(tx, msg, cb, cb_data);
644*042d53a7SEvalZero }
645*042d53a7SEvalZero
bt_mesh_model_send(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * msg,const struct bt_mesh_send_cb * cb,void * cb_data)646*042d53a7SEvalZero int bt_mesh_model_send(struct bt_mesh_model *model,
647*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
648*042d53a7SEvalZero struct os_mbuf *msg,
649*042d53a7SEvalZero const struct bt_mesh_send_cb *cb, void *cb_data)
650*042d53a7SEvalZero {
651*042d53a7SEvalZero struct bt_mesh_net_tx tx = {
652*042d53a7SEvalZero .sub = bt_mesh_subnet_get(ctx->net_idx),
653*042d53a7SEvalZero .ctx = ctx,
654*042d53a7SEvalZero .src = bt_mesh_model_elem(model)->addr,
655*042d53a7SEvalZero .xmit = bt_mesh_net_transmit_get(),
656*042d53a7SEvalZero .friend_cred = 0,
657*042d53a7SEvalZero };
658*042d53a7SEvalZero
659*042d53a7SEvalZero return model_send(model, &tx, false, msg, cb, cb_data);
660*042d53a7SEvalZero }
661*042d53a7SEvalZero
bt_mesh_model_publish(struct bt_mesh_model * model)662*042d53a7SEvalZero int bt_mesh_model_publish(struct bt_mesh_model *model)
663*042d53a7SEvalZero {
664*042d53a7SEvalZero struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
665*042d53a7SEvalZero struct bt_mesh_model_pub *pub = model->pub;
666*042d53a7SEvalZero struct bt_mesh_app_key *key;
667*042d53a7SEvalZero struct bt_mesh_msg_ctx ctx = {
668*042d53a7SEvalZero };
669*042d53a7SEvalZero struct bt_mesh_net_tx tx = {
670*042d53a7SEvalZero .ctx = &ctx,
671*042d53a7SEvalZero .src = bt_mesh_model_elem(model)->addr,
672*042d53a7SEvalZero .xmit = bt_mesh_net_transmit_get(),
673*042d53a7SEvalZero };
674*042d53a7SEvalZero int err;
675*042d53a7SEvalZero
676*042d53a7SEvalZero BT_DBG("");
677*042d53a7SEvalZero
678*042d53a7SEvalZero if (!pub) {
679*042d53a7SEvalZero err = -ENOTSUP;
680*042d53a7SEvalZero goto done;
681*042d53a7SEvalZero }
682*042d53a7SEvalZero
683*042d53a7SEvalZero if (pub->addr == BT_MESH_ADDR_UNASSIGNED) {
684*042d53a7SEvalZero err = -EADDRNOTAVAIL;
685*042d53a7SEvalZero goto done;
686*042d53a7SEvalZero }
687*042d53a7SEvalZero
688*042d53a7SEvalZero key = bt_mesh_app_key_find(pub->key);
689*042d53a7SEvalZero if (!key) {
690*042d53a7SEvalZero err = -EADDRNOTAVAIL;
691*042d53a7SEvalZero goto done;
692*042d53a7SEvalZero }
693*042d53a7SEvalZero
694*042d53a7SEvalZero if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) {
695*042d53a7SEvalZero BT_ERR("Message does not fit maximum SDU size");
696*042d53a7SEvalZero err = -EMSGSIZE;
697*042d53a7SEvalZero goto done;
698*042d53a7SEvalZero }
699*042d53a7SEvalZero
700*042d53a7SEvalZero if (pub->count) {
701*042d53a7SEvalZero BT_WARN("Clearing publish retransmit timer");
702*042d53a7SEvalZero k_delayed_work_cancel(&pub->timer);
703*042d53a7SEvalZero }
704*042d53a7SEvalZero
705*042d53a7SEvalZero net_buf_simple_init(sdu, 0);
706*042d53a7SEvalZero net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len);
707*042d53a7SEvalZero
708*042d53a7SEvalZero ctx.addr = pub->addr;
709*042d53a7SEvalZero ctx.send_ttl = pub->ttl;
710*042d53a7SEvalZero ctx.net_idx = key->net_idx;
711*042d53a7SEvalZero ctx.app_idx = key->app_idx;
712*042d53a7SEvalZero
713*042d53a7SEvalZero tx.friend_cred = pub->cred;
714*042d53a7SEvalZero tx.sub = bt_mesh_subnet_get(ctx.net_idx),
715*042d53a7SEvalZero
716*042d53a7SEvalZero pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
717*042d53a7SEvalZero
718*042d53a7SEvalZero BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count,
719*042d53a7SEvalZero BT_MESH_PUB_TRANSMIT_INT(pub->retransmit));
720*042d53a7SEvalZero
721*042d53a7SEvalZero err = model_send(model, &tx, true, sdu, &pub_sent_cb, model);
722*042d53a7SEvalZero if (err) {
723*042d53a7SEvalZero pub->count = 0;
724*042d53a7SEvalZero }
725*042d53a7SEvalZero
726*042d53a7SEvalZero done:
727*042d53a7SEvalZero os_mbuf_free_chain(sdu);
728*042d53a7SEvalZero return err;
729*042d53a7SEvalZero }
730*042d53a7SEvalZero
bt_mesh_model_find_vnd(struct bt_mesh_elem * elem,u16_t company,u16_t id)731*042d53a7SEvalZero struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,
732*042d53a7SEvalZero u16_t company, u16_t id)
733*042d53a7SEvalZero {
734*042d53a7SEvalZero u8_t i;
735*042d53a7SEvalZero
736*042d53a7SEvalZero for (i = 0; i < elem->vnd_model_count; i++) {
737*042d53a7SEvalZero if (elem->vnd_models[i].vnd.company == company &&
738*042d53a7SEvalZero elem->vnd_models[i].vnd.id == id) {
739*042d53a7SEvalZero return &elem->vnd_models[i];
740*042d53a7SEvalZero }
741*042d53a7SEvalZero }
742*042d53a7SEvalZero
743*042d53a7SEvalZero return NULL;
744*042d53a7SEvalZero }
745*042d53a7SEvalZero
bt_mesh_model_find(struct bt_mesh_elem * elem,u16_t id)746*042d53a7SEvalZero struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem,
747*042d53a7SEvalZero u16_t id)
748*042d53a7SEvalZero {
749*042d53a7SEvalZero u8_t i;
750*042d53a7SEvalZero
751*042d53a7SEvalZero for (i = 0; i < elem->model_count; i++) {
752*042d53a7SEvalZero if (elem->models[i].id == id) {
753*042d53a7SEvalZero return &elem->models[i];
754*042d53a7SEvalZero }
755*042d53a7SEvalZero }
756*042d53a7SEvalZero
757*042d53a7SEvalZero return NULL;
758*042d53a7SEvalZero }
759*042d53a7SEvalZero
bt_mesh_comp_get(void)760*042d53a7SEvalZero const struct bt_mesh_comp *bt_mesh_comp_get(void)
761*042d53a7SEvalZero {
762*042d53a7SEvalZero return dev_comp;
763*042d53a7SEvalZero }
764