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 <string.h>
10*042d53a7SEvalZero #include <errno.h>
11*042d53a7SEvalZero #include <stdbool.h>
12*042d53a7SEvalZero
13*042d53a7SEvalZero #include "mesh/mesh.h"
14*042d53a7SEvalZero
15*042d53a7SEvalZero #include "syscfg/syscfg.h"
16*042d53a7SEvalZero #define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_MODEL)
17*042d53a7SEvalZero #include "host/ble_hs_log.h"
18*042d53a7SEvalZero
19*042d53a7SEvalZero #include "mesh_priv.h"
20*042d53a7SEvalZero #include "adv.h"
21*042d53a7SEvalZero #include "net.h"
22*042d53a7SEvalZero #include "lpn.h"
23*042d53a7SEvalZero #include "transport.h"
24*042d53a7SEvalZero #include "crypto.h"
25*042d53a7SEvalZero #include "access.h"
26*042d53a7SEvalZero #include "beacon.h"
27*042d53a7SEvalZero #include "proxy.h"
28*042d53a7SEvalZero #include "foundation.h"
29*042d53a7SEvalZero #include "friend.h"
30*042d53a7SEvalZero #include "testing.h"
31*042d53a7SEvalZero #include "settings.h"
32*042d53a7SEvalZero
33*042d53a7SEvalZero #define DEFAULT_TTL 7
34*042d53a7SEvalZero
35*042d53a7SEvalZero static struct bt_mesh_cfg_srv *conf;
36*042d53a7SEvalZero
37*042d53a7SEvalZero static struct label {
38*042d53a7SEvalZero u16_t ref;
39*042d53a7SEvalZero u16_t addr;
40*042d53a7SEvalZero u8_t uuid[16];
41*042d53a7SEvalZero } labels[MYNEWT_VAL(BLE_MESH_LABEL_COUNT)];
42*042d53a7SEvalZero
hb_send(struct bt_mesh_model * model)43*042d53a7SEvalZero static void hb_send(struct bt_mesh_model *model)
44*042d53a7SEvalZero {
45*042d53a7SEvalZero
46*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
47*042d53a7SEvalZero u16_t feat = 0;
48*042d53a7SEvalZero struct __packed {
49*042d53a7SEvalZero u8_t init_ttl;
50*042d53a7SEvalZero u16_t feat;
51*042d53a7SEvalZero } hb;
52*042d53a7SEvalZero struct bt_mesh_msg_ctx ctx = {
53*042d53a7SEvalZero .net_idx = cfg->hb_pub.net_idx,
54*042d53a7SEvalZero .app_idx = BT_MESH_KEY_UNUSED,
55*042d53a7SEvalZero .addr = cfg->hb_pub.dst,
56*042d53a7SEvalZero .send_ttl = cfg->hb_pub.ttl,
57*042d53a7SEvalZero };
58*042d53a7SEvalZero struct bt_mesh_net_tx tx = {
59*042d53a7SEvalZero .sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx),
60*042d53a7SEvalZero .ctx = &ctx,
61*042d53a7SEvalZero .src = bt_mesh_model_elem(model)->addr,
62*042d53a7SEvalZero .xmit = bt_mesh_net_transmit_get(),
63*042d53a7SEvalZero };
64*042d53a7SEvalZero
65*042d53a7SEvalZero hb.init_ttl = cfg->hb_pub.ttl;
66*042d53a7SEvalZero
67*042d53a7SEvalZero if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) {
68*042d53a7SEvalZero feat |= BT_MESH_FEAT_RELAY;
69*042d53a7SEvalZero }
70*042d53a7SEvalZero
71*042d53a7SEvalZero if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
72*042d53a7SEvalZero feat |= BT_MESH_FEAT_PROXY;
73*042d53a7SEvalZero }
74*042d53a7SEvalZero
75*042d53a7SEvalZero if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) {
76*042d53a7SEvalZero feat |= BT_MESH_FEAT_FRIEND;
77*042d53a7SEvalZero }
78*042d53a7SEvalZero
79*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_MESH_LOW_POWER))
80*042d53a7SEvalZero if (bt_mesh.lpn.state != BT_MESH_LPN_DISABLED) {
81*042d53a7SEvalZero feat |= BT_MESH_FEAT_LOW_POWER;
82*042d53a7SEvalZero }
83*042d53a7SEvalZero #endif
84*042d53a7SEvalZero
85*042d53a7SEvalZero hb.feat = sys_cpu_to_be16(feat);
86*042d53a7SEvalZero
87*042d53a7SEvalZero BT_DBG("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat);
88*042d53a7SEvalZero
89*042d53a7SEvalZero bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb),
90*042d53a7SEvalZero NULL, NULL, NULL);
91*042d53a7SEvalZero }
92*042d53a7SEvalZero
comp_add_elem(struct os_mbuf * buf,struct bt_mesh_elem * elem,bool primary)93*042d53a7SEvalZero static int comp_add_elem(struct os_mbuf *buf, struct bt_mesh_elem *elem,
94*042d53a7SEvalZero bool primary)
95*042d53a7SEvalZero {
96*042d53a7SEvalZero struct bt_mesh_model *mod;
97*042d53a7SEvalZero int i;
98*042d53a7SEvalZero
99*042d53a7SEvalZero if (net_buf_simple_tailroom(buf) <
100*042d53a7SEvalZero 4 + (elem->model_count * 2) + (elem->vnd_model_count * 2)) {
101*042d53a7SEvalZero BT_ERR("Too large device composition");
102*042d53a7SEvalZero return -E2BIG;
103*042d53a7SEvalZero }
104*042d53a7SEvalZero
105*042d53a7SEvalZero net_buf_simple_add_le16(buf, elem->loc);
106*042d53a7SEvalZero
107*042d53a7SEvalZero net_buf_simple_add_u8(buf, elem->model_count);
108*042d53a7SEvalZero net_buf_simple_add_u8(buf, elem->vnd_model_count);
109*042d53a7SEvalZero
110*042d53a7SEvalZero for (i = 0; i < elem->model_count; i++) {
111*042d53a7SEvalZero mod = &elem->models[i];
112*042d53a7SEvalZero net_buf_simple_add_le16(buf, mod->id);
113*042d53a7SEvalZero }
114*042d53a7SEvalZero
115*042d53a7SEvalZero for (i = 0; i < elem->vnd_model_count; i++) {
116*042d53a7SEvalZero mod = &elem->vnd_models[i];
117*042d53a7SEvalZero net_buf_simple_add_le16(buf, mod->vnd.company);
118*042d53a7SEvalZero net_buf_simple_add_le16(buf, mod->vnd.id);
119*042d53a7SEvalZero }
120*042d53a7SEvalZero
121*042d53a7SEvalZero return 0;
122*042d53a7SEvalZero }
123*042d53a7SEvalZero
comp_get_page_0(struct os_mbuf * buf)124*042d53a7SEvalZero static int comp_get_page_0(struct os_mbuf *buf)
125*042d53a7SEvalZero {
126*042d53a7SEvalZero u16_t feat = 0;
127*042d53a7SEvalZero const struct bt_mesh_comp *comp;
128*042d53a7SEvalZero int i;
129*042d53a7SEvalZero
130*042d53a7SEvalZero comp = bt_mesh_comp_get();
131*042d53a7SEvalZero
132*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_RELAY))) {
133*042d53a7SEvalZero feat |= BT_MESH_FEAT_RELAY;
134*042d53a7SEvalZero }
135*042d53a7SEvalZero
136*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) {
137*042d53a7SEvalZero feat |= BT_MESH_FEAT_PROXY;
138*042d53a7SEvalZero }
139*042d53a7SEvalZero
140*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_FRIEND))) {
141*042d53a7SEvalZero feat |= BT_MESH_FEAT_FRIEND;
142*042d53a7SEvalZero }
143*042d53a7SEvalZero
144*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
145*042d53a7SEvalZero feat |= BT_MESH_FEAT_LOW_POWER;
146*042d53a7SEvalZero }
147*042d53a7SEvalZero
148*042d53a7SEvalZero net_buf_simple_add_le16(buf, comp->cid);
149*042d53a7SEvalZero net_buf_simple_add_le16(buf, comp->pid);
150*042d53a7SEvalZero net_buf_simple_add_le16(buf, comp->vid);
151*042d53a7SEvalZero net_buf_simple_add_le16(buf, MYNEWT_VAL(BLE_MESH_CRPL));
152*042d53a7SEvalZero net_buf_simple_add_le16(buf, feat);
153*042d53a7SEvalZero
154*042d53a7SEvalZero for (i = 0; i < comp->elem_count; i++) {
155*042d53a7SEvalZero int err;
156*042d53a7SEvalZero
157*042d53a7SEvalZero err = comp_add_elem(buf, &comp->elem[i], i == 0);
158*042d53a7SEvalZero if (err) {
159*042d53a7SEvalZero return err;
160*042d53a7SEvalZero }
161*042d53a7SEvalZero }
162*042d53a7SEvalZero
163*042d53a7SEvalZero return 0;
164*042d53a7SEvalZero }
165*042d53a7SEvalZero
dev_comp_data_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)166*042d53a7SEvalZero static void dev_comp_data_get(struct bt_mesh_model *model,
167*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
168*042d53a7SEvalZero struct os_mbuf *buf)
169*042d53a7SEvalZero {
170*042d53a7SEvalZero struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
171*042d53a7SEvalZero u8_t page;
172*042d53a7SEvalZero
173*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
174*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
175*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
176*042d53a7SEvalZero
177*042d53a7SEvalZero page = net_buf_simple_pull_u8(buf);
178*042d53a7SEvalZero if (page != 0) {
179*042d53a7SEvalZero BT_WARN("Composition page %u not available", page);
180*042d53a7SEvalZero page = 0;
181*042d53a7SEvalZero }
182*042d53a7SEvalZero
183*042d53a7SEvalZero bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS);
184*042d53a7SEvalZero
185*042d53a7SEvalZero net_buf_simple_add_u8(sdu, page);
186*042d53a7SEvalZero if (comp_get_page_0(sdu) < 0) {
187*042d53a7SEvalZero BT_ERR("Unable to get composition page 0");
188*042d53a7SEvalZero goto done;
189*042d53a7SEvalZero }
190*042d53a7SEvalZero
191*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
192*042d53a7SEvalZero BT_ERR("Unable to send Device Composition Status response");
193*042d53a7SEvalZero }
194*042d53a7SEvalZero
195*042d53a7SEvalZero done:
196*042d53a7SEvalZero os_mbuf_free_chain(sdu);
197*042d53a7SEvalZero }
198*042d53a7SEvalZero
get_model(struct bt_mesh_elem * elem,struct os_mbuf * buf,bool * vnd)199*042d53a7SEvalZero static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem,
200*042d53a7SEvalZero struct os_mbuf *buf, bool *vnd)
201*042d53a7SEvalZero {
202*042d53a7SEvalZero if (buf->om_len < 4) {
203*042d53a7SEvalZero u16_t id;
204*042d53a7SEvalZero
205*042d53a7SEvalZero id = net_buf_simple_pull_le16(buf);
206*042d53a7SEvalZero
207*042d53a7SEvalZero BT_DBG("ID 0x%04x addr 0x%04x", id, elem->addr);
208*042d53a7SEvalZero
209*042d53a7SEvalZero *vnd = false;
210*042d53a7SEvalZero
211*042d53a7SEvalZero return bt_mesh_model_find(elem, id);
212*042d53a7SEvalZero } else {
213*042d53a7SEvalZero u16_t company, id;
214*042d53a7SEvalZero
215*042d53a7SEvalZero company = net_buf_simple_pull_le16(buf);
216*042d53a7SEvalZero id = net_buf_simple_pull_le16(buf);
217*042d53a7SEvalZero
218*042d53a7SEvalZero BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id,
219*042d53a7SEvalZero elem->addr);
220*042d53a7SEvalZero
221*042d53a7SEvalZero *vnd = true;
222*042d53a7SEvalZero
223*042d53a7SEvalZero return bt_mesh_model_find_vnd(elem, company, id);
224*042d53a7SEvalZero }
225*042d53a7SEvalZero }
226*042d53a7SEvalZero
app_key_is_valid(u16_t app_idx)227*042d53a7SEvalZero static bool app_key_is_valid(u16_t app_idx)
228*042d53a7SEvalZero {
229*042d53a7SEvalZero int i;
230*042d53a7SEvalZero
231*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) {
232*042d53a7SEvalZero struct bt_mesh_app_key *key = &bt_mesh.app_keys[i];
233*042d53a7SEvalZero
234*042d53a7SEvalZero if (key->net_idx != BT_MESH_KEY_UNUSED &&
235*042d53a7SEvalZero key->app_idx == app_idx) {
236*042d53a7SEvalZero return true;
237*042d53a7SEvalZero }
238*042d53a7SEvalZero }
239*042d53a7SEvalZero
240*042d53a7SEvalZero return false;
241*042d53a7SEvalZero }
242*042d53a7SEvalZero
_mod_pub_set(struct bt_mesh_model * model,u16_t pub_addr,u16_t app_idx,u8_t cred_flag,u8_t ttl,u8_t period,u8_t retransmit,bool store)243*042d53a7SEvalZero static u8_t _mod_pub_set(struct bt_mesh_model *model, u16_t pub_addr,
244*042d53a7SEvalZero u16_t app_idx, u8_t cred_flag, u8_t ttl, u8_t period,
245*042d53a7SEvalZero u8_t retransmit, bool store)
246*042d53a7SEvalZero {
247*042d53a7SEvalZero if (!model->pub) {
248*042d53a7SEvalZero return STATUS_NVAL_PUB_PARAM;
249*042d53a7SEvalZero }
250*042d53a7SEvalZero
251*042d53a7SEvalZero if (!(MYNEWT_VAL(BLE_MESH_LOW_POWER)) && cred_flag) {
252*042d53a7SEvalZero return STATUS_FEAT_NOT_SUPP;
253*042d53a7SEvalZero }
254*042d53a7SEvalZero
255*042d53a7SEvalZero if (!model->pub->update && period) {
256*042d53a7SEvalZero return STATUS_NVAL_PUB_PARAM;
257*042d53a7SEvalZero }
258*042d53a7SEvalZero
259*042d53a7SEvalZero if (pub_addr == BT_MESH_ADDR_UNASSIGNED) {
260*042d53a7SEvalZero if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
261*042d53a7SEvalZero return STATUS_SUCCESS;
262*042d53a7SEvalZero }
263*042d53a7SEvalZero
264*042d53a7SEvalZero model->pub->addr = BT_MESH_ADDR_UNASSIGNED;
265*042d53a7SEvalZero model->pub->key = 0;
266*042d53a7SEvalZero model->pub->cred = 0;
267*042d53a7SEvalZero model->pub->ttl = 0;
268*042d53a7SEvalZero model->pub->period = 0;
269*042d53a7SEvalZero model->pub->retransmit = 0;
270*042d53a7SEvalZero model->pub->count = 0;
271*042d53a7SEvalZero
272*042d53a7SEvalZero if (model->pub->update) {
273*042d53a7SEvalZero k_delayed_work_cancel(&model->pub->timer);
274*042d53a7SEvalZero }
275*042d53a7SEvalZero
276*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
277*042d53a7SEvalZero bt_mesh_store_mod_pub(model);
278*042d53a7SEvalZero }
279*042d53a7SEvalZero
280*042d53a7SEvalZero return STATUS_SUCCESS;
281*042d53a7SEvalZero }
282*042d53a7SEvalZero
283*042d53a7SEvalZero if (!bt_mesh_app_key_find(app_idx)) {
284*042d53a7SEvalZero return STATUS_INVALID_APPKEY;
285*042d53a7SEvalZero }
286*042d53a7SEvalZero
287*042d53a7SEvalZero model->pub->addr = pub_addr;
288*042d53a7SEvalZero model->pub->key = app_idx;
289*042d53a7SEvalZero model->pub->cred = cred_flag;
290*042d53a7SEvalZero model->pub->ttl = ttl;
291*042d53a7SEvalZero model->pub->period = period;
292*042d53a7SEvalZero model->pub->retransmit = retransmit;
293*042d53a7SEvalZero
294*042d53a7SEvalZero if (model->pub->update) {
295*042d53a7SEvalZero s32_t period_ms;
296*042d53a7SEvalZero
297*042d53a7SEvalZero period_ms = bt_mesh_model_pub_period_get(model);
298*042d53a7SEvalZero BT_DBG("period %u ms", period_ms);
299*042d53a7SEvalZero
300*042d53a7SEvalZero if (period_ms) {
301*042d53a7SEvalZero k_delayed_work_submit(&model->pub->timer, period_ms);
302*042d53a7SEvalZero } else {
303*042d53a7SEvalZero k_delayed_work_cancel(&model->pub->timer);
304*042d53a7SEvalZero }
305*042d53a7SEvalZero }
306*042d53a7SEvalZero
307*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
308*042d53a7SEvalZero bt_mesh_store_mod_pub(model);
309*042d53a7SEvalZero }
310*042d53a7SEvalZero
311*042d53a7SEvalZero return STATUS_SUCCESS;
312*042d53a7SEvalZero }
313*042d53a7SEvalZero
mod_bind(struct bt_mesh_model * model,u16_t key_idx)314*042d53a7SEvalZero u8_t mod_bind(struct bt_mesh_model *model, u16_t key_idx)
315*042d53a7SEvalZero {
316*042d53a7SEvalZero int i;
317*042d53a7SEvalZero
318*042d53a7SEvalZero BT_DBG("model %p key_idx 0x%03x", model, key_idx);
319*042d53a7SEvalZero
320*042d53a7SEvalZero if (!app_key_is_valid(key_idx)) {
321*042d53a7SEvalZero return STATUS_INVALID_APPKEY;
322*042d53a7SEvalZero }
323*042d53a7SEvalZero
324*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(model->keys); i++) {
325*042d53a7SEvalZero /* Treat existing binding as success */
326*042d53a7SEvalZero if (model->keys[i] == key_idx) {
327*042d53a7SEvalZero return STATUS_SUCCESS;
328*042d53a7SEvalZero }
329*042d53a7SEvalZero }
330*042d53a7SEvalZero
331*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(model->keys); i++) {
332*042d53a7SEvalZero if (model->keys[i] == BT_MESH_KEY_UNUSED) {
333*042d53a7SEvalZero model->keys[i] = key_idx;
334*042d53a7SEvalZero
335*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
336*042d53a7SEvalZero bt_mesh_store_mod_bind(model);
337*042d53a7SEvalZero }
338*042d53a7SEvalZero
339*042d53a7SEvalZero return STATUS_SUCCESS;
340*042d53a7SEvalZero }
341*042d53a7SEvalZero }
342*042d53a7SEvalZero
343*042d53a7SEvalZero return STATUS_INSUFF_RESOURCES;
344*042d53a7SEvalZero }
345*042d53a7SEvalZero
mod_unbind(struct bt_mesh_model * model,u16_t key_idx,bool store)346*042d53a7SEvalZero u8_t mod_unbind(struct bt_mesh_model *model, u16_t key_idx, bool store)
347*042d53a7SEvalZero {
348*042d53a7SEvalZero int i;
349*042d53a7SEvalZero
350*042d53a7SEvalZero BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store);
351*042d53a7SEvalZero
352*042d53a7SEvalZero if (!app_key_is_valid(key_idx)) {
353*042d53a7SEvalZero return STATUS_INVALID_APPKEY;
354*042d53a7SEvalZero }
355*042d53a7SEvalZero
356*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(model->keys); i++) {
357*042d53a7SEvalZero if (model->keys[i] != key_idx) {
358*042d53a7SEvalZero continue;
359*042d53a7SEvalZero }
360*042d53a7SEvalZero
361*042d53a7SEvalZero model->keys[i] = BT_MESH_KEY_UNUSED;
362*042d53a7SEvalZero
363*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
364*042d53a7SEvalZero bt_mesh_store_mod_bind(model);
365*042d53a7SEvalZero }
366*042d53a7SEvalZero
367*042d53a7SEvalZero if (model->pub && model->pub->key == key_idx) {
368*042d53a7SEvalZero _mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED,
369*042d53a7SEvalZero 0, 0, 0, 0, 0, store);
370*042d53a7SEvalZero }
371*042d53a7SEvalZero }
372*042d53a7SEvalZero
373*042d53a7SEvalZero return STATUS_SUCCESS;
374*042d53a7SEvalZero }
375*042d53a7SEvalZero
bt_mesh_app_key_alloc(u16_t app_idx)376*042d53a7SEvalZero struct bt_mesh_app_key *bt_mesh_app_key_alloc(u16_t app_idx)
377*042d53a7SEvalZero {
378*042d53a7SEvalZero int i;
379*042d53a7SEvalZero
380*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) {
381*042d53a7SEvalZero struct bt_mesh_app_key *key = &bt_mesh.app_keys[i];
382*042d53a7SEvalZero
383*042d53a7SEvalZero if (key->net_idx == BT_MESH_KEY_UNUSED) {
384*042d53a7SEvalZero return key;
385*042d53a7SEvalZero }
386*042d53a7SEvalZero }
387*042d53a7SEvalZero
388*042d53a7SEvalZero return NULL;
389*042d53a7SEvalZero }
390*042d53a7SEvalZero
app_key_set(u16_t net_idx,u16_t app_idx,const u8_t val[16],bool update)391*042d53a7SEvalZero static u8_t app_key_set(u16_t net_idx, u16_t app_idx, const u8_t val[16],
392*042d53a7SEvalZero bool update)
393*042d53a7SEvalZero {
394*042d53a7SEvalZero struct bt_mesh_app_keys *keys;
395*042d53a7SEvalZero struct bt_mesh_app_key *key;
396*042d53a7SEvalZero struct bt_mesh_subnet *sub;
397*042d53a7SEvalZero
398*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx %04x update %u val %s",
399*042d53a7SEvalZero net_idx, app_idx, update, bt_hex(val, 16));
400*042d53a7SEvalZero
401*042d53a7SEvalZero sub = bt_mesh_subnet_get(net_idx);
402*042d53a7SEvalZero if (!sub) {
403*042d53a7SEvalZero return STATUS_INVALID_NETKEY;
404*042d53a7SEvalZero }
405*042d53a7SEvalZero
406*042d53a7SEvalZero key = bt_mesh_app_key_find(app_idx);
407*042d53a7SEvalZero if (update) {
408*042d53a7SEvalZero if (!key) {
409*042d53a7SEvalZero return STATUS_INVALID_APPKEY;
410*042d53a7SEvalZero }
411*042d53a7SEvalZero
412*042d53a7SEvalZero if (key->net_idx != net_idx) {
413*042d53a7SEvalZero return STATUS_INVALID_BINDING;
414*042d53a7SEvalZero }
415*042d53a7SEvalZero
416*042d53a7SEvalZero keys = &key->keys[1];
417*042d53a7SEvalZero
418*042d53a7SEvalZero /* The AppKey Update message shall generate an error when node
419*042d53a7SEvalZero * is in normal operation, Phase 2, or Phase 3 or in Phase 1
420*042d53a7SEvalZero * when the AppKey Update message on a valid AppKeyIndex when
421*042d53a7SEvalZero * the AppKey value is different.
422*042d53a7SEvalZero */
423*042d53a7SEvalZero if (sub->kr_phase != BT_MESH_KR_PHASE_1) {
424*042d53a7SEvalZero return STATUS_CANNOT_UPDATE;
425*042d53a7SEvalZero }
426*042d53a7SEvalZero
427*042d53a7SEvalZero if (key->updated) {
428*042d53a7SEvalZero if (memcmp(keys->val, val, 16)) {
429*042d53a7SEvalZero return STATUS_CANNOT_UPDATE;
430*042d53a7SEvalZero } else {
431*042d53a7SEvalZero return STATUS_SUCCESS;
432*042d53a7SEvalZero }
433*042d53a7SEvalZero }
434*042d53a7SEvalZero
435*042d53a7SEvalZero key->updated = true;
436*042d53a7SEvalZero } else {
437*042d53a7SEvalZero if (key) {
438*042d53a7SEvalZero if (key->net_idx == net_idx &&
439*042d53a7SEvalZero !memcmp(key->keys[0].val, val, 16)) {
440*042d53a7SEvalZero return STATUS_SUCCESS;
441*042d53a7SEvalZero }
442*042d53a7SEvalZero
443*042d53a7SEvalZero if (key->net_idx == net_idx) {
444*042d53a7SEvalZero return STATUS_IDX_ALREADY_STORED;
445*042d53a7SEvalZero } else {
446*042d53a7SEvalZero return STATUS_INVALID_NETKEY;
447*042d53a7SEvalZero }
448*042d53a7SEvalZero }
449*042d53a7SEvalZero
450*042d53a7SEvalZero key = bt_mesh_app_key_alloc(app_idx);
451*042d53a7SEvalZero if (!key) {
452*042d53a7SEvalZero return STATUS_INSUFF_RESOURCES;
453*042d53a7SEvalZero }
454*042d53a7SEvalZero
455*042d53a7SEvalZero keys = &key->keys[0];
456*042d53a7SEvalZero }
457*042d53a7SEvalZero
458*042d53a7SEvalZero if (bt_mesh_app_id(val, &keys->id)) {
459*042d53a7SEvalZero if (update) {
460*042d53a7SEvalZero key->updated = false;
461*042d53a7SEvalZero }
462*042d53a7SEvalZero
463*042d53a7SEvalZero return STATUS_STORAGE_FAIL;
464*042d53a7SEvalZero }
465*042d53a7SEvalZero
466*042d53a7SEvalZero BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, keys->id);
467*042d53a7SEvalZero
468*042d53a7SEvalZero key->net_idx = net_idx;
469*042d53a7SEvalZero key->app_idx = app_idx;
470*042d53a7SEvalZero memcpy(keys->val, val, 16);
471*042d53a7SEvalZero
472*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
473*042d53a7SEvalZero BT_DBG("Storing AppKey persistently");
474*042d53a7SEvalZero bt_mesh_store_app_key(key);
475*042d53a7SEvalZero }
476*042d53a7SEvalZero
477*042d53a7SEvalZero return STATUS_SUCCESS;
478*042d53a7SEvalZero }
479*042d53a7SEvalZero
app_key_add(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)480*042d53a7SEvalZero static void app_key_add(struct bt_mesh_model *model,
481*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
482*042d53a7SEvalZero struct os_mbuf *buf)
483*042d53a7SEvalZero {
484*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
485*042d53a7SEvalZero u16_t key_net_idx, key_app_idx;
486*042d53a7SEvalZero u8_t status;
487*042d53a7SEvalZero
488*042d53a7SEvalZero key_idx_unpack(buf, &key_net_idx, &key_app_idx);
489*042d53a7SEvalZero
490*042d53a7SEvalZero BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx);
491*042d53a7SEvalZero
492*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_APP_KEY_STATUS);
493*042d53a7SEvalZero
494*042d53a7SEvalZero status = app_key_set(key_net_idx, key_app_idx, buf->om_data, false);
495*042d53a7SEvalZero BT_DBG("status 0x%02x", status);
496*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
497*042d53a7SEvalZero
498*042d53a7SEvalZero key_idx_pack(msg, key_net_idx, key_app_idx);
499*042d53a7SEvalZero
500*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
501*042d53a7SEvalZero BT_ERR("Unable to send App Key Status response");
502*042d53a7SEvalZero }
503*042d53a7SEvalZero
504*042d53a7SEvalZero os_mbuf_free_chain(msg);
505*042d53a7SEvalZero }
506*042d53a7SEvalZero
app_key_update(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)507*042d53a7SEvalZero static void app_key_update(struct bt_mesh_model *model,
508*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
509*042d53a7SEvalZero struct os_mbuf *buf)
510*042d53a7SEvalZero {
511*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
512*042d53a7SEvalZero u16_t key_net_idx, key_app_idx;
513*042d53a7SEvalZero u8_t status;
514*042d53a7SEvalZero
515*042d53a7SEvalZero key_idx_unpack(buf, &key_net_idx, &key_app_idx);
516*042d53a7SEvalZero
517*042d53a7SEvalZero BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx);
518*042d53a7SEvalZero
519*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_APP_KEY_STATUS);
520*042d53a7SEvalZero
521*042d53a7SEvalZero status = app_key_set(key_net_idx, key_app_idx, buf->om_data, true);
522*042d53a7SEvalZero BT_DBG("status 0x%02x", status);
523*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
524*042d53a7SEvalZero
525*042d53a7SEvalZero key_idx_pack(msg, key_net_idx, key_app_idx);
526*042d53a7SEvalZero
527*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
528*042d53a7SEvalZero BT_ERR("Unable to send App Key Status response");
529*042d53a7SEvalZero }
530*042d53a7SEvalZero
531*042d53a7SEvalZero os_mbuf_free_chain(msg);
532*042d53a7SEvalZero }
533*042d53a7SEvalZero
534*042d53a7SEvalZero struct unbind_data {
535*042d53a7SEvalZero u16_t app_idx;
536*042d53a7SEvalZero bool store;
537*042d53a7SEvalZero };
538*042d53a7SEvalZero
_mod_unbind(struct bt_mesh_model * mod,struct bt_mesh_elem * elem,bool vnd,bool primary,void * user_data)539*042d53a7SEvalZero static void _mod_unbind(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
540*042d53a7SEvalZero bool vnd, bool primary, void *user_data)
541*042d53a7SEvalZero {
542*042d53a7SEvalZero struct unbind_data *data = user_data;
543*042d53a7SEvalZero
544*042d53a7SEvalZero mod_unbind(mod, data->app_idx, data->store);
545*042d53a7SEvalZero }
546*042d53a7SEvalZero
bt_mesh_app_key_del(struct bt_mesh_app_key * key,bool store)547*042d53a7SEvalZero void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store)
548*042d53a7SEvalZero {
549*042d53a7SEvalZero struct unbind_data data = { .app_idx = key->app_idx, .store = store };
550*042d53a7SEvalZero
551*042d53a7SEvalZero BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store);
552*042d53a7SEvalZero
553*042d53a7SEvalZero bt_mesh_model_foreach(_mod_unbind, &data);
554*042d53a7SEvalZero
555*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
556*042d53a7SEvalZero bt_mesh_clear_app_key(key);
557*042d53a7SEvalZero }
558*042d53a7SEvalZero
559*042d53a7SEvalZero key->net_idx = BT_MESH_KEY_UNUSED;
560*042d53a7SEvalZero memset(key->keys, 0, sizeof(key->keys));
561*042d53a7SEvalZero }
562*042d53a7SEvalZero
app_key_del(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)563*042d53a7SEvalZero static void app_key_del(struct bt_mesh_model *model,
564*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
565*042d53a7SEvalZero struct os_mbuf *buf)
566*042d53a7SEvalZero {
567*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
568*042d53a7SEvalZero u16_t key_net_idx, key_app_idx;
569*042d53a7SEvalZero struct bt_mesh_app_key *key;
570*042d53a7SEvalZero u8_t status;
571*042d53a7SEvalZero
572*042d53a7SEvalZero key_idx_unpack(buf, &key_net_idx, &key_app_idx);
573*042d53a7SEvalZero
574*042d53a7SEvalZero BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx);
575*042d53a7SEvalZero
576*042d53a7SEvalZero if (!bt_mesh_subnet_get(key_net_idx)) {
577*042d53a7SEvalZero status = STATUS_INVALID_NETKEY;
578*042d53a7SEvalZero goto send_status;
579*042d53a7SEvalZero }
580*042d53a7SEvalZero
581*042d53a7SEvalZero key = bt_mesh_app_key_find(key_app_idx);
582*042d53a7SEvalZero if (!key) {
583*042d53a7SEvalZero /* Treat as success since the client might have missed a
584*042d53a7SEvalZero * previous response and is resending the request.
585*042d53a7SEvalZero */
586*042d53a7SEvalZero status = STATUS_SUCCESS;
587*042d53a7SEvalZero goto send_status;
588*042d53a7SEvalZero }
589*042d53a7SEvalZero
590*042d53a7SEvalZero if (key->net_idx != key_net_idx) {
591*042d53a7SEvalZero status = STATUS_INVALID_BINDING;
592*042d53a7SEvalZero goto send_status;
593*042d53a7SEvalZero }
594*042d53a7SEvalZero
595*042d53a7SEvalZero bt_mesh_app_key_del(key, true);
596*042d53a7SEvalZero status = STATUS_SUCCESS;
597*042d53a7SEvalZero
598*042d53a7SEvalZero send_status:
599*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_APP_KEY_STATUS);
600*042d53a7SEvalZero
601*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
602*042d53a7SEvalZero
603*042d53a7SEvalZero key_idx_pack(msg, key_net_idx, key_app_idx);
604*042d53a7SEvalZero
605*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
606*042d53a7SEvalZero BT_ERR("Unable to send App Key Status response");
607*042d53a7SEvalZero }
608*042d53a7SEvalZero
609*042d53a7SEvalZero os_mbuf_free_chain(msg);
610*042d53a7SEvalZero }
611*042d53a7SEvalZero
612*042d53a7SEvalZero /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */
613*042d53a7SEvalZero #define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2)
614*042d53a7SEvalZero
app_key_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)615*042d53a7SEvalZero static void app_key_get(struct bt_mesh_model *model,
616*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
617*042d53a7SEvalZero struct os_mbuf *buf)
618*042d53a7SEvalZero {
619*042d53a7SEvalZero struct os_mbuf *msg =
620*042d53a7SEvalZero NET_BUF_SIMPLE(2 + 3 + 4 +
621*042d53a7SEvalZero IDX_LEN(MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)));
622*042d53a7SEvalZero u16_t get_idx, i, prev;
623*042d53a7SEvalZero u8_t status;
624*042d53a7SEvalZero
625*042d53a7SEvalZero get_idx = net_buf_simple_pull_le16(buf);
626*042d53a7SEvalZero if (get_idx > 0xfff) {
627*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", get_idx);
628*042d53a7SEvalZero goto done;
629*042d53a7SEvalZero }
630*042d53a7SEvalZero
631*042d53a7SEvalZero BT_DBG("idx 0x%04x", get_idx);
632*042d53a7SEvalZero
633*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_APP_KEY_LIST);
634*042d53a7SEvalZero
635*042d53a7SEvalZero if (!bt_mesh_subnet_get(get_idx)) {
636*042d53a7SEvalZero status = STATUS_INVALID_NETKEY;
637*042d53a7SEvalZero } else {
638*042d53a7SEvalZero status = STATUS_SUCCESS;
639*042d53a7SEvalZero }
640*042d53a7SEvalZero
641*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
642*042d53a7SEvalZero net_buf_simple_add_le16(msg, get_idx);
643*042d53a7SEvalZero
644*042d53a7SEvalZero if (status != STATUS_SUCCESS) {
645*042d53a7SEvalZero goto send_status;
646*042d53a7SEvalZero }
647*042d53a7SEvalZero
648*042d53a7SEvalZero prev = BT_MESH_KEY_UNUSED;
649*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) {
650*042d53a7SEvalZero struct bt_mesh_app_key *key = &bt_mesh.app_keys[i];
651*042d53a7SEvalZero
652*042d53a7SEvalZero if (key->net_idx != get_idx) {
653*042d53a7SEvalZero continue;
654*042d53a7SEvalZero }
655*042d53a7SEvalZero
656*042d53a7SEvalZero if (prev == BT_MESH_KEY_UNUSED) {
657*042d53a7SEvalZero prev = key->app_idx;
658*042d53a7SEvalZero continue;
659*042d53a7SEvalZero }
660*042d53a7SEvalZero
661*042d53a7SEvalZero key_idx_pack(msg, prev, key->app_idx);
662*042d53a7SEvalZero prev = BT_MESH_KEY_UNUSED;
663*042d53a7SEvalZero }
664*042d53a7SEvalZero
665*042d53a7SEvalZero if (prev != BT_MESH_KEY_UNUSED) {
666*042d53a7SEvalZero net_buf_simple_add_le16(msg, prev);
667*042d53a7SEvalZero }
668*042d53a7SEvalZero
669*042d53a7SEvalZero send_status:
670*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
671*042d53a7SEvalZero BT_ERR("Unable to send AppKey List");
672*042d53a7SEvalZero }
673*042d53a7SEvalZero
674*042d53a7SEvalZero done:
675*042d53a7SEvalZero os_mbuf_free_chain(msg);
676*042d53a7SEvalZero }
677*042d53a7SEvalZero
beacon_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)678*042d53a7SEvalZero static void beacon_get(struct bt_mesh_model *model,
679*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
680*042d53a7SEvalZero struct os_mbuf *buf)
681*042d53a7SEvalZero {
682*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
683*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
684*042d53a7SEvalZero
685*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
686*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
687*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
688*042d53a7SEvalZero
689*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_BEACON_STATUS);
690*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_beacon_get());
691*042d53a7SEvalZero
692*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
693*042d53a7SEvalZero BT_ERR("Unable to send Config Beacon Status response");
694*042d53a7SEvalZero }
695*042d53a7SEvalZero os_mbuf_free_chain(msg);
696*042d53a7SEvalZero }
697*042d53a7SEvalZero
beacon_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)698*042d53a7SEvalZero static void beacon_set(struct bt_mesh_model *model,
699*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
700*042d53a7SEvalZero struct os_mbuf *buf)
701*042d53a7SEvalZero {
702*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
703*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
704*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
705*042d53a7SEvalZero
706*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
707*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
708*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
709*042d53a7SEvalZero
710*042d53a7SEvalZero if (!cfg) {
711*042d53a7SEvalZero BT_WARN("No Configuration Server context available");
712*042d53a7SEvalZero } else if (buf->om_data[0] == 0x00 || buf->om_data[0] == 0x01) {
713*042d53a7SEvalZero if (buf->om_data[0] != cfg->beacon) {
714*042d53a7SEvalZero cfg->beacon = buf->om_data[0];
715*042d53a7SEvalZero
716*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
717*042d53a7SEvalZero bt_mesh_store_cfg();
718*042d53a7SEvalZero }
719*042d53a7SEvalZero
720*042d53a7SEvalZero if (cfg->beacon) {
721*042d53a7SEvalZero bt_mesh_beacon_enable();
722*042d53a7SEvalZero } else {
723*042d53a7SEvalZero bt_mesh_beacon_disable();
724*042d53a7SEvalZero }
725*042d53a7SEvalZero }
726*042d53a7SEvalZero } else {
727*042d53a7SEvalZero BT_WARN("Invalid Config Beacon value 0x%02x", buf->om_data[0]);
728*042d53a7SEvalZero goto done;
729*042d53a7SEvalZero }
730*042d53a7SEvalZero
731*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_BEACON_STATUS);
732*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_beacon_get());
733*042d53a7SEvalZero
734*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
735*042d53a7SEvalZero BT_ERR("Unable to send Config Beacon Status response");
736*042d53a7SEvalZero }
737*042d53a7SEvalZero
738*042d53a7SEvalZero done:
739*042d53a7SEvalZero os_mbuf_free_chain(msg);
740*042d53a7SEvalZero
741*042d53a7SEvalZero }
742*042d53a7SEvalZero
default_ttl_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)743*042d53a7SEvalZero static void default_ttl_get(struct bt_mesh_model *model,
744*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
745*042d53a7SEvalZero struct os_mbuf *buf)
746*042d53a7SEvalZero {
747*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
748*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
749*042d53a7SEvalZero
750*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
751*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
752*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
753*042d53a7SEvalZero
754*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_DEFAULT_TTL_STATUS);
755*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_default_ttl_get());
756*042d53a7SEvalZero
757*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
758*042d53a7SEvalZero BT_ERR("Unable to send Default TTL Status response");
759*042d53a7SEvalZero }
760*042d53a7SEvalZero
761*042d53a7SEvalZero os_mbuf_free_chain(msg);
762*042d53a7SEvalZero
763*042d53a7SEvalZero }
764*042d53a7SEvalZero
default_ttl_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)765*042d53a7SEvalZero static void default_ttl_set(struct bt_mesh_model *model,
766*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
767*042d53a7SEvalZero struct os_mbuf *buf)
768*042d53a7SEvalZero {
769*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
770*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
771*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
772*042d53a7SEvalZero
773*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
774*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
775*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
776*042d53a7SEvalZero
777*042d53a7SEvalZero if (!cfg) {
778*042d53a7SEvalZero BT_WARN("No Configuration Server context available");
779*042d53a7SEvalZero } else if (buf->om_data[0] <= BT_MESH_TTL_MAX && buf->om_data[0] != 0x01) {
780*042d53a7SEvalZero if (cfg->default_ttl != buf->om_data[0]) {
781*042d53a7SEvalZero cfg->default_ttl = buf->om_data[0];
782*042d53a7SEvalZero
783*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
784*042d53a7SEvalZero bt_mesh_store_cfg();
785*042d53a7SEvalZero }
786*042d53a7SEvalZero }
787*042d53a7SEvalZero } else {
788*042d53a7SEvalZero BT_WARN("Prohibited Default TTL value 0x%02x", buf->om_data[0]);
789*042d53a7SEvalZero goto done;
790*042d53a7SEvalZero }
791*042d53a7SEvalZero
792*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_DEFAULT_TTL_STATUS);
793*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_default_ttl_get());
794*042d53a7SEvalZero
795*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
796*042d53a7SEvalZero BT_ERR("Unable to send Default TTL Status response");
797*042d53a7SEvalZero }
798*042d53a7SEvalZero
799*042d53a7SEvalZero done:
800*042d53a7SEvalZero os_mbuf_free_chain(msg);
801*042d53a7SEvalZero }
802*042d53a7SEvalZero
send_gatt_proxy_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx)803*042d53a7SEvalZero static void send_gatt_proxy_status(struct bt_mesh_model *model,
804*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx)
805*042d53a7SEvalZero {
806*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
807*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
808*042d53a7SEvalZero
809*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_GATT_PROXY_STATUS);
810*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_gatt_proxy_get());
811*042d53a7SEvalZero
812*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
813*042d53a7SEvalZero BT_ERR("Unable to send GATT Proxy Status");
814*042d53a7SEvalZero }
815*042d53a7SEvalZero
816*042d53a7SEvalZero os_mbuf_free_chain(msg);
817*042d53a7SEvalZero
818*042d53a7SEvalZero }
819*042d53a7SEvalZero
gatt_proxy_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)820*042d53a7SEvalZero static void gatt_proxy_get(struct bt_mesh_model *model,
821*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
822*042d53a7SEvalZero struct os_mbuf *buf)
823*042d53a7SEvalZero {
824*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
825*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
826*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
827*042d53a7SEvalZero
828*042d53a7SEvalZero send_gatt_proxy_status(model, ctx);
829*042d53a7SEvalZero }
830*042d53a7SEvalZero
gatt_proxy_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)831*042d53a7SEvalZero static void gatt_proxy_set(struct bt_mesh_model *model,
832*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
833*042d53a7SEvalZero struct os_mbuf *buf)
834*042d53a7SEvalZero {
835*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
836*042d53a7SEvalZero struct bt_mesh_subnet *sub;
837*042d53a7SEvalZero
838*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
839*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
840*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
841*042d53a7SEvalZero
842*042d53a7SEvalZero if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) {
843*042d53a7SEvalZero BT_WARN("Invalid GATT Proxy value 0x%02x", buf->om_data[0]);
844*042d53a7SEvalZero return;
845*042d53a7SEvalZero }
846*042d53a7SEvalZero
847*042d53a7SEvalZero if (!(MYNEWT_VAL(BLE_MESH_GATT_PROXY)) ||
848*042d53a7SEvalZero bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_NOT_SUPPORTED) {
849*042d53a7SEvalZero goto send_status;
850*042d53a7SEvalZero }
851*042d53a7SEvalZero
852*042d53a7SEvalZero if (!cfg) {
853*042d53a7SEvalZero BT_WARN("No Configuration Server context available");
854*042d53a7SEvalZero goto send_status;
855*042d53a7SEvalZero }
856*042d53a7SEvalZero
857*042d53a7SEvalZero BT_DBG("GATT Proxy 0x%02x -> 0x%02x", cfg->gatt_proxy, buf->om_data[0]);
858*042d53a7SEvalZero
859*042d53a7SEvalZero if (cfg->gatt_proxy == buf->om_data[0]) {
860*042d53a7SEvalZero goto send_status;
861*042d53a7SEvalZero }
862*042d53a7SEvalZero
863*042d53a7SEvalZero cfg->gatt_proxy = buf->om_data[0];
864*042d53a7SEvalZero
865*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
866*042d53a7SEvalZero bt_mesh_store_cfg();
867*042d53a7SEvalZero }
868*042d53a7SEvalZero
869*042d53a7SEvalZero if (cfg->gatt_proxy == BT_MESH_GATT_PROXY_DISABLED) {
870*042d53a7SEvalZero int i;
871*042d53a7SEvalZero
872*042d53a7SEvalZero /* Section 4.2.11.1: "When the GATT Proxy state is set to
873*042d53a7SEvalZero * 0x00, the Node Identity state for all subnets shall be set
874*042d53a7SEvalZero * to 0x00 and shall not be changed."
875*042d53a7SEvalZero */
876*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
877*042d53a7SEvalZero struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
878*042d53a7SEvalZero
879*042d53a7SEvalZero if (sub->net_idx != BT_MESH_KEY_UNUSED) {
880*042d53a7SEvalZero bt_mesh_proxy_identity_stop(sub);
881*042d53a7SEvalZero }
882*042d53a7SEvalZero }
883*042d53a7SEvalZero
884*042d53a7SEvalZero /* Section 4.2.11: "Upon transition from GATT Proxy state 0x01
885*042d53a7SEvalZero * to GATT Proxy state 0x00 the GATT Bearer Server shall
886*042d53a7SEvalZero * disconnect all GATT Bearer Clients.
887*042d53a7SEvalZero */
888*042d53a7SEvalZero bt_mesh_proxy_gatt_disconnect();
889*042d53a7SEvalZero }
890*042d53a7SEvalZero
891*042d53a7SEvalZero bt_mesh_adv_update();
892*042d53a7SEvalZero
893*042d53a7SEvalZero sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
894*042d53a7SEvalZero if ((cfg->hb_pub.feat & BT_MESH_FEAT_PROXY) && sub) {
895*042d53a7SEvalZero hb_send(model);
896*042d53a7SEvalZero }
897*042d53a7SEvalZero
898*042d53a7SEvalZero send_status:
899*042d53a7SEvalZero send_gatt_proxy_status(model, ctx);
900*042d53a7SEvalZero }
901*042d53a7SEvalZero
net_transmit_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)902*042d53a7SEvalZero static void net_transmit_get(struct bt_mesh_model *model,
903*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
904*042d53a7SEvalZero struct os_mbuf *buf)
905*042d53a7SEvalZero {
906*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
907*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
908*042d53a7SEvalZero
909*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
910*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
911*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
912*042d53a7SEvalZero
913*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NET_TRANSMIT_STATUS);
914*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_net_transmit_get());
915*042d53a7SEvalZero
916*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
917*042d53a7SEvalZero BT_ERR("Unable to send Config Network Transmit Status");
918*042d53a7SEvalZero }
919*042d53a7SEvalZero
920*042d53a7SEvalZero os_mbuf_free_chain(msg);
921*042d53a7SEvalZero
922*042d53a7SEvalZero }
923*042d53a7SEvalZero
net_transmit_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)924*042d53a7SEvalZero static void net_transmit_set(struct bt_mesh_model *model,
925*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
926*042d53a7SEvalZero struct os_mbuf *buf)
927*042d53a7SEvalZero {
928*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
929*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
930*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
931*042d53a7SEvalZero
932*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
933*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
934*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
935*042d53a7SEvalZero
936*042d53a7SEvalZero BT_DBG("Transmit 0x%02x (count %u interval %ums)", buf->om_data[0],
937*042d53a7SEvalZero BT_MESH_TRANSMIT_COUNT(buf->om_data[0]),
938*042d53a7SEvalZero BT_MESH_TRANSMIT_INT(buf->om_data[0]));
939*042d53a7SEvalZero
940*042d53a7SEvalZero if (!cfg) {
941*042d53a7SEvalZero BT_WARN("No Configuration Server context available");
942*042d53a7SEvalZero } else {
943*042d53a7SEvalZero cfg->net_transmit = buf->om_data[0];
944*042d53a7SEvalZero
945*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
946*042d53a7SEvalZero bt_mesh_store_cfg();
947*042d53a7SEvalZero }
948*042d53a7SEvalZero }
949*042d53a7SEvalZero
950*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NET_TRANSMIT_STATUS);
951*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_net_transmit_get());
952*042d53a7SEvalZero
953*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
954*042d53a7SEvalZero BT_ERR("Unable to send Network Transmit Status");
955*042d53a7SEvalZero }
956*042d53a7SEvalZero
957*042d53a7SEvalZero os_mbuf_free_chain(msg);
958*042d53a7SEvalZero }
959*042d53a7SEvalZero
relay_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)960*042d53a7SEvalZero static void relay_get(struct bt_mesh_model *model,
961*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
962*042d53a7SEvalZero struct os_mbuf *buf)
963*042d53a7SEvalZero {
964*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
965*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
966*042d53a7SEvalZero
967*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
968*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
969*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
970*042d53a7SEvalZero
971*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_RELAY_STATUS);
972*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_relay_get());
973*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_relay_retransmit_get());
974*042d53a7SEvalZero
975*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
976*042d53a7SEvalZero BT_ERR("Unable to send Config Relay Status response");
977*042d53a7SEvalZero }
978*042d53a7SEvalZero
979*042d53a7SEvalZero os_mbuf_free_chain(msg);
980*042d53a7SEvalZero
981*042d53a7SEvalZero }
982*042d53a7SEvalZero
relay_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)983*042d53a7SEvalZero static void relay_set(struct bt_mesh_model *model,
984*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
985*042d53a7SEvalZero struct os_mbuf *buf)
986*042d53a7SEvalZero {
987*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
988*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
989*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
990*042d53a7SEvalZero
991*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
992*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
993*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
994*042d53a7SEvalZero
995*042d53a7SEvalZero if (!cfg) {
996*042d53a7SEvalZero BT_WARN("No Configuration Server context available");
997*042d53a7SEvalZero } else if (buf->om_data[0] == 0x00 || buf->om_data[0] == 0x01) {
998*042d53a7SEvalZero struct bt_mesh_subnet *sub;
999*042d53a7SEvalZero bool change;
1000*042d53a7SEvalZero
1001*042d53a7SEvalZero if (cfg->relay == BT_MESH_RELAY_NOT_SUPPORTED) {
1002*042d53a7SEvalZero change = false;
1003*042d53a7SEvalZero } else {
1004*042d53a7SEvalZero change = (cfg->relay != buf->om_data[0]);
1005*042d53a7SEvalZero cfg->relay = buf->om_data[0];
1006*042d53a7SEvalZero cfg->relay_retransmit = buf->om_data[1];
1007*042d53a7SEvalZero
1008*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1009*042d53a7SEvalZero bt_mesh_store_cfg();
1010*042d53a7SEvalZero }
1011*042d53a7SEvalZero }
1012*042d53a7SEvalZero
1013*042d53a7SEvalZero BT_DBG("Relay 0x%02x (%s) xmit 0x%02x (count %u interval %u)",
1014*042d53a7SEvalZero cfg->relay, change ? "changed" : "not changed",
1015*042d53a7SEvalZero cfg->relay_retransmit,
1016*042d53a7SEvalZero BT_MESH_TRANSMIT_COUNT(cfg->relay_retransmit),
1017*042d53a7SEvalZero BT_MESH_TRANSMIT_INT(cfg->relay_retransmit));
1018*042d53a7SEvalZero
1019*042d53a7SEvalZero sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
1020*042d53a7SEvalZero if ((cfg->hb_pub.feat & BT_MESH_FEAT_RELAY) && sub && change) {
1021*042d53a7SEvalZero hb_send(model);
1022*042d53a7SEvalZero }
1023*042d53a7SEvalZero } else {
1024*042d53a7SEvalZero BT_WARN("Invalid Relay value 0x%02x", buf->om_data[0]);
1025*042d53a7SEvalZero goto done;
1026*042d53a7SEvalZero }
1027*042d53a7SEvalZero
1028*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_RELAY_STATUS);
1029*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_relay_get());
1030*042d53a7SEvalZero net_buf_simple_add_u8(msg, bt_mesh_relay_retransmit_get());
1031*042d53a7SEvalZero
1032*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
1033*042d53a7SEvalZero BT_ERR("Unable to send Relay Status response");
1034*042d53a7SEvalZero }
1035*042d53a7SEvalZero
1036*042d53a7SEvalZero done:
1037*042d53a7SEvalZero os_mbuf_free_chain(msg);
1038*042d53a7SEvalZero
1039*042d53a7SEvalZero }
1040*042d53a7SEvalZero
send_mod_pub_status(struct bt_mesh_model * cfg_mod,struct bt_mesh_msg_ctx * ctx,u16_t elem_addr,u16_t pub_addr,bool vnd,struct bt_mesh_model * mod,u8_t status,u8_t * mod_id)1041*042d53a7SEvalZero static void send_mod_pub_status(struct bt_mesh_model *cfg_mod,
1042*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1043*042d53a7SEvalZero u16_t elem_addr, u16_t pub_addr,
1044*042d53a7SEvalZero bool vnd, struct bt_mesh_model *mod,
1045*042d53a7SEvalZero u8_t status, u8_t *mod_id)
1046*042d53a7SEvalZero {
1047*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
1048*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 14 + 4);
1049*042d53a7SEvalZero
1050*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_MOD_PUB_STATUS);
1051*042d53a7SEvalZero
1052*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
1053*042d53a7SEvalZero net_buf_simple_add_le16(msg, elem_addr);
1054*042d53a7SEvalZero
1055*042d53a7SEvalZero if (status != STATUS_SUCCESS) {
1056*042d53a7SEvalZero memset(net_buf_simple_add(msg, 7), 0, 7);
1057*042d53a7SEvalZero } else {
1058*042d53a7SEvalZero u16_t idx_cred;
1059*042d53a7SEvalZero
1060*042d53a7SEvalZero net_buf_simple_add_le16(msg, pub_addr);
1061*042d53a7SEvalZero
1062*042d53a7SEvalZero idx_cred = mod->pub->key | (u16_t)mod->pub->cred << 12;
1063*042d53a7SEvalZero net_buf_simple_add_le16(msg, idx_cred);
1064*042d53a7SEvalZero net_buf_simple_add_u8(msg, mod->pub->ttl);
1065*042d53a7SEvalZero net_buf_simple_add_u8(msg, mod->pub->period);
1066*042d53a7SEvalZero net_buf_simple_add_u8(msg, mod->pub->retransmit);
1067*042d53a7SEvalZero }
1068*042d53a7SEvalZero
1069*042d53a7SEvalZero if (vnd) {
1070*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, 4), mod_id, 4);
1071*042d53a7SEvalZero } else {
1072*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, 2), mod_id, 2);
1073*042d53a7SEvalZero }
1074*042d53a7SEvalZero
1075*042d53a7SEvalZero if (bt_mesh_model_send(cfg_mod, ctx, msg, NULL, NULL)) {
1076*042d53a7SEvalZero BT_ERR("Unable to send Model Publication Status");
1077*042d53a7SEvalZero }
1078*042d53a7SEvalZero
1079*042d53a7SEvalZero os_mbuf_free_chain(msg);
1080*042d53a7SEvalZero }
1081*042d53a7SEvalZero
mod_pub_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1082*042d53a7SEvalZero static void mod_pub_get(struct bt_mesh_model *model,
1083*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1084*042d53a7SEvalZero struct os_mbuf *buf)
1085*042d53a7SEvalZero {
1086*042d53a7SEvalZero u16_t elem_addr, pub_addr = 0;
1087*042d53a7SEvalZero struct bt_mesh_model *mod;
1088*042d53a7SEvalZero struct bt_mesh_elem *elem;
1089*042d53a7SEvalZero u8_t *mod_id, status;
1090*042d53a7SEvalZero bool vnd;
1091*042d53a7SEvalZero
1092*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1093*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1094*042d53a7SEvalZero BT_WARN("Prohibited element address");
1095*042d53a7SEvalZero return;
1096*042d53a7SEvalZero }
1097*042d53a7SEvalZero
1098*042d53a7SEvalZero mod_id = buf->om_data;
1099*042d53a7SEvalZero
1100*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x", elem_addr);
1101*042d53a7SEvalZero
1102*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1103*042d53a7SEvalZero if (!elem) {
1104*042d53a7SEvalZero mod = NULL;
1105*042d53a7SEvalZero vnd = (buf->om_len == 4);
1106*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1107*042d53a7SEvalZero goto send_status;
1108*042d53a7SEvalZero }
1109*042d53a7SEvalZero
1110*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1111*042d53a7SEvalZero if (!mod) {
1112*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1113*042d53a7SEvalZero goto send_status;
1114*042d53a7SEvalZero }
1115*042d53a7SEvalZero
1116*042d53a7SEvalZero if (!mod->pub) {
1117*042d53a7SEvalZero status = STATUS_NVAL_PUB_PARAM;
1118*042d53a7SEvalZero goto send_status;
1119*042d53a7SEvalZero }
1120*042d53a7SEvalZero
1121*042d53a7SEvalZero pub_addr = mod->pub->addr;
1122*042d53a7SEvalZero status = STATUS_SUCCESS;
1123*042d53a7SEvalZero
1124*042d53a7SEvalZero send_status:
1125*042d53a7SEvalZero send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod,
1126*042d53a7SEvalZero status, mod_id);
1127*042d53a7SEvalZero }
1128*042d53a7SEvalZero
mod_pub_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1129*042d53a7SEvalZero static void mod_pub_set(struct bt_mesh_model *model,
1130*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1131*042d53a7SEvalZero struct os_mbuf *buf)
1132*042d53a7SEvalZero {
1133*042d53a7SEvalZero u8_t retransmit, status, pub_ttl, pub_period, cred_flag;
1134*042d53a7SEvalZero u16_t elem_addr, pub_addr, pub_app_idx;
1135*042d53a7SEvalZero struct bt_mesh_model *mod;
1136*042d53a7SEvalZero struct bt_mesh_elem *elem;
1137*042d53a7SEvalZero u8_t *mod_id;
1138*042d53a7SEvalZero bool vnd;
1139*042d53a7SEvalZero
1140*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1141*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1142*042d53a7SEvalZero BT_WARN("Prohibited element address");
1143*042d53a7SEvalZero return;
1144*042d53a7SEvalZero }
1145*042d53a7SEvalZero
1146*042d53a7SEvalZero pub_addr = net_buf_simple_pull_le16(buf);
1147*042d53a7SEvalZero pub_app_idx = net_buf_simple_pull_le16(buf);
1148*042d53a7SEvalZero cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1));
1149*042d53a7SEvalZero pub_app_idx &= BIT_MASK(12);
1150*042d53a7SEvalZero
1151*042d53a7SEvalZero pub_ttl = net_buf_simple_pull_u8(buf);
1152*042d53a7SEvalZero if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) {
1153*042d53a7SEvalZero BT_ERR("Invalid TTL value 0x%02x", pub_ttl);
1154*042d53a7SEvalZero return;
1155*042d53a7SEvalZero }
1156*042d53a7SEvalZero
1157*042d53a7SEvalZero pub_period = net_buf_simple_pull_u8(buf);
1158*042d53a7SEvalZero retransmit = net_buf_simple_pull_u8(buf);
1159*042d53a7SEvalZero mod_id = buf->om_data;
1160*042d53a7SEvalZero
1161*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u",
1162*042d53a7SEvalZero elem_addr, pub_addr, cred_flag);
1163*042d53a7SEvalZero BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x",
1164*042d53a7SEvalZero pub_app_idx, pub_ttl, pub_period);
1165*042d53a7SEvalZero BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit,
1166*042d53a7SEvalZero BT_MESH_PUB_TRANSMIT_COUNT(retransmit),
1167*042d53a7SEvalZero BT_MESH_PUB_TRANSMIT_INT(retransmit));
1168*042d53a7SEvalZero
1169*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1170*042d53a7SEvalZero if (!elem) {
1171*042d53a7SEvalZero mod = NULL;
1172*042d53a7SEvalZero vnd = (buf->om_len == 4);
1173*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1174*042d53a7SEvalZero goto send_status;
1175*042d53a7SEvalZero }
1176*042d53a7SEvalZero
1177*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1178*042d53a7SEvalZero if (!mod) {
1179*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1180*042d53a7SEvalZero goto send_status;
1181*042d53a7SEvalZero }
1182*042d53a7SEvalZero
1183*042d53a7SEvalZero status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl,
1184*042d53a7SEvalZero pub_period, retransmit, true);
1185*042d53a7SEvalZero
1186*042d53a7SEvalZero send_status:
1187*042d53a7SEvalZero send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod,
1188*042d53a7SEvalZero status, mod_id);
1189*042d53a7SEvalZero }
1190*042d53a7SEvalZero
1191*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH_LABEL_COUNT) > 0
va_add(u8_t * label_uuid,u16_t * addr)1192*042d53a7SEvalZero static u8_t va_add(u8_t *label_uuid, u16_t *addr)
1193*042d53a7SEvalZero {
1194*042d53a7SEvalZero struct label *free_slot = NULL;
1195*042d53a7SEvalZero int i;
1196*042d53a7SEvalZero
1197*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(labels); i++) {
1198*042d53a7SEvalZero if (!labels[i].ref) {
1199*042d53a7SEvalZero free_slot = &labels[i];
1200*042d53a7SEvalZero continue;
1201*042d53a7SEvalZero }
1202*042d53a7SEvalZero
1203*042d53a7SEvalZero if (!memcmp(labels[i].uuid, label_uuid, 16)) {
1204*042d53a7SEvalZero *addr = labels[i].addr;
1205*042d53a7SEvalZero labels[i].ref++;
1206*042d53a7SEvalZero return STATUS_SUCCESS;
1207*042d53a7SEvalZero }
1208*042d53a7SEvalZero }
1209*042d53a7SEvalZero
1210*042d53a7SEvalZero if (!free_slot) {
1211*042d53a7SEvalZero return STATUS_INSUFF_RESOURCES;
1212*042d53a7SEvalZero }
1213*042d53a7SEvalZero
1214*042d53a7SEvalZero if (bt_mesh_virtual_addr(label_uuid, addr) < 0) {
1215*042d53a7SEvalZero return STATUS_UNSPECIFIED;
1216*042d53a7SEvalZero }
1217*042d53a7SEvalZero
1218*042d53a7SEvalZero free_slot->ref = 1;
1219*042d53a7SEvalZero free_slot->addr = *addr;
1220*042d53a7SEvalZero memcpy(free_slot->uuid, label_uuid, 16);
1221*042d53a7SEvalZero
1222*042d53a7SEvalZero return STATUS_SUCCESS;
1223*042d53a7SEvalZero }
1224*042d53a7SEvalZero
va_del(u8_t * label_uuid,u16_t * addr)1225*042d53a7SEvalZero static u8_t va_del(u8_t *label_uuid, u16_t *addr)
1226*042d53a7SEvalZero {
1227*042d53a7SEvalZero int i;
1228*042d53a7SEvalZero
1229*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(labels); i++) {
1230*042d53a7SEvalZero if (!memcmp(labels[i].uuid, label_uuid, 16)) {
1231*042d53a7SEvalZero if (addr) {
1232*042d53a7SEvalZero *addr = labels[i].addr;
1233*042d53a7SEvalZero }
1234*042d53a7SEvalZero
1235*042d53a7SEvalZero labels[i].ref--;
1236*042d53a7SEvalZero return STATUS_SUCCESS;
1237*042d53a7SEvalZero }
1238*042d53a7SEvalZero }
1239*042d53a7SEvalZero
1240*042d53a7SEvalZero if (addr) {
1241*042d53a7SEvalZero *addr = BT_MESH_ADDR_UNASSIGNED;
1242*042d53a7SEvalZero }
1243*042d53a7SEvalZero
1244*042d53a7SEvalZero return STATUS_CANNOT_REMOVE;
1245*042d53a7SEvalZero }
1246*042d53a7SEvalZero
mod_sub_list_clear(struct bt_mesh_model * mod)1247*042d53a7SEvalZero static void mod_sub_list_clear(struct bt_mesh_model *mod)
1248*042d53a7SEvalZero {
1249*042d53a7SEvalZero u8_t *label_uuid;
1250*042d53a7SEvalZero int i;
1251*042d53a7SEvalZero
1252*042d53a7SEvalZero /* Unref stored labels related to this model */
1253*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
1254*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) {
1255*042d53a7SEvalZero continue;
1256*042d53a7SEvalZero }
1257*042d53a7SEvalZero
1258*042d53a7SEvalZero label_uuid = bt_mesh_label_uuid_get(mod->groups[i]);
1259*042d53a7SEvalZero if (!label_uuid) {
1260*042d53a7SEvalZero BT_ERR("Label UUID not found");
1261*042d53a7SEvalZero continue;
1262*042d53a7SEvalZero }
1263*042d53a7SEvalZero
1264*042d53a7SEvalZero va_del(label_uuid, NULL);
1265*042d53a7SEvalZero }
1266*042d53a7SEvalZero
1267*042d53a7SEvalZero /* Clear all subscriptions (0x0000 is the unassigned address) */
1268*042d53a7SEvalZero memset(mod->groups, 0, sizeof(mod->groups));
1269*042d53a7SEvalZero }
1270*042d53a7SEvalZero
mod_pub_va_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1271*042d53a7SEvalZero static void mod_pub_va_set(struct bt_mesh_model *model,
1272*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1273*042d53a7SEvalZero struct os_mbuf *buf)
1274*042d53a7SEvalZero {
1275*042d53a7SEvalZero u8_t retransmit, status, pub_ttl, pub_period, cred_flag;
1276*042d53a7SEvalZero u16_t elem_addr, pub_addr, pub_app_idx;
1277*042d53a7SEvalZero struct bt_mesh_model *mod;
1278*042d53a7SEvalZero struct bt_mesh_elem *elem;
1279*042d53a7SEvalZero u8_t *label_uuid;
1280*042d53a7SEvalZero u8_t *mod_id;
1281*042d53a7SEvalZero bool vnd;
1282*042d53a7SEvalZero
1283*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1284*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1285*042d53a7SEvalZero BT_WARN("Prohibited element address");
1286*042d53a7SEvalZero return;
1287*042d53a7SEvalZero }
1288*042d53a7SEvalZero
1289*042d53a7SEvalZero label_uuid = buf->om_data;
1290*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
1291*042d53a7SEvalZero
1292*042d53a7SEvalZero pub_app_idx = net_buf_simple_pull_le16(buf);
1293*042d53a7SEvalZero cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1));
1294*042d53a7SEvalZero pub_app_idx &= BIT_MASK(12);
1295*042d53a7SEvalZero pub_ttl = net_buf_simple_pull_u8(buf);
1296*042d53a7SEvalZero if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) {
1297*042d53a7SEvalZero BT_ERR("Invalid TTL value 0x%02x", pub_ttl);
1298*042d53a7SEvalZero return;
1299*042d53a7SEvalZero }
1300*042d53a7SEvalZero
1301*042d53a7SEvalZero pub_period = net_buf_simple_pull_u8(buf);
1302*042d53a7SEvalZero retransmit = net_buf_simple_pull_u8(buf);
1303*042d53a7SEvalZero mod_id = buf->om_data;
1304*042d53a7SEvalZero
1305*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u",
1306*042d53a7SEvalZero elem_addr, pub_addr, cred_flag);
1307*042d53a7SEvalZero BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x",
1308*042d53a7SEvalZero pub_app_idx, pub_ttl, pub_period);
1309*042d53a7SEvalZero BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit,
1310*042d53a7SEvalZero BT_MESH_PUB_TRANSMIT_COUNT(retransmit),
1311*042d53a7SEvalZero BT_MESH_PUB_TRANSMIT_INT(retransmit));
1312*042d53a7SEvalZero
1313*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1314*042d53a7SEvalZero if (!elem) {
1315*042d53a7SEvalZero mod = NULL;
1316*042d53a7SEvalZero vnd = (buf->om_len == 4);
1317*042d53a7SEvalZero pub_addr = 0;
1318*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1319*042d53a7SEvalZero goto send_status;
1320*042d53a7SEvalZero }
1321*042d53a7SEvalZero
1322*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1323*042d53a7SEvalZero if (!mod) {
1324*042d53a7SEvalZero pub_addr = 0;
1325*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1326*042d53a7SEvalZero goto send_status;
1327*042d53a7SEvalZero }
1328*042d53a7SEvalZero
1329*042d53a7SEvalZero status = va_add(label_uuid, &pub_addr);
1330*042d53a7SEvalZero if (status == STATUS_SUCCESS) {
1331*042d53a7SEvalZero status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag,
1332*042d53a7SEvalZero pub_ttl, pub_period, retransmit, true);
1333*042d53a7SEvalZero }
1334*042d53a7SEvalZero
1335*042d53a7SEvalZero send_status:
1336*042d53a7SEvalZero send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod,
1337*042d53a7SEvalZero status, mod_id);
1338*042d53a7SEvalZero }
1339*042d53a7SEvalZero #else
mod_sub_list_clear(struct bt_mesh_model * mod)1340*042d53a7SEvalZero static void mod_sub_list_clear(struct bt_mesh_model *mod)
1341*042d53a7SEvalZero {
1342*042d53a7SEvalZero /* Clear all subscriptions (0x0000 is the unassigned address) */
1343*042d53a7SEvalZero memset(mod->groups, 0, sizeof(mod->groups));
1344*042d53a7SEvalZero }
1345*042d53a7SEvalZero
mod_pub_va_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1346*042d53a7SEvalZero static void mod_pub_va_set(struct bt_mesh_model *model,
1347*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1348*042d53a7SEvalZero struct os_mbuf *buf)
1349*042d53a7SEvalZero {
1350*042d53a7SEvalZero u8_t *mod_id, status;
1351*042d53a7SEvalZero struct bt_mesh_model *mod;
1352*042d53a7SEvalZero struct bt_mesh_elem *elem;
1353*042d53a7SEvalZero u16_t elem_addr, pub_addr = 0;
1354*042d53a7SEvalZero bool vnd;
1355*042d53a7SEvalZero
1356*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1357*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1358*042d53a7SEvalZero BT_WARN("Prohibited element address");
1359*042d53a7SEvalZero return;
1360*042d53a7SEvalZero }
1361*042d53a7SEvalZero
1362*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
1363*042d53a7SEvalZero mod_id = net_buf_simple_pull(buf, 4);
1364*042d53a7SEvalZero
1365*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x", elem_addr);
1366*042d53a7SEvalZero
1367*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1368*042d53a7SEvalZero if (!elem) {
1369*042d53a7SEvalZero mod = NULL;
1370*042d53a7SEvalZero vnd = (buf->om_len == 4);
1371*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1372*042d53a7SEvalZero goto send_status;
1373*042d53a7SEvalZero }
1374*042d53a7SEvalZero
1375*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1376*042d53a7SEvalZero if (!mod) {
1377*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1378*042d53a7SEvalZero goto send_status;
1379*042d53a7SEvalZero }
1380*042d53a7SEvalZero
1381*042d53a7SEvalZero if (!mod->pub) {
1382*042d53a7SEvalZero status = STATUS_NVAL_PUB_PARAM;
1383*042d53a7SEvalZero goto send_status;
1384*042d53a7SEvalZero }
1385*042d53a7SEvalZero
1386*042d53a7SEvalZero pub_addr = mod->pub->addr;
1387*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
1388*042d53a7SEvalZero
1389*042d53a7SEvalZero send_status:
1390*042d53a7SEvalZero send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod,
1391*042d53a7SEvalZero status, mod_id);
1392*042d53a7SEvalZero }
1393*042d53a7SEvalZero #endif /* MYNEWT_VAL(BLE_MESH_LABEL_COUNT) > 0 */
1394*042d53a7SEvalZero
send_mod_sub_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,u8_t status,u16_t elem_addr,u16_t sub_addr,u8_t * mod_id,bool vnd)1395*042d53a7SEvalZero static void send_mod_sub_status(struct bt_mesh_model *model,
1396*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx, u8_t status,
1397*042d53a7SEvalZero u16_t elem_addr, u16_t sub_addr, u8_t *mod_id,
1398*042d53a7SEvalZero bool vnd)
1399*042d53a7SEvalZero {
1400*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
1401*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
1402*042d53a7SEvalZero
1403*042d53a7SEvalZero BT_DBG("status 0x%02x elem_addr 0x%04x sub_addr 0x%04x", status,
1404*042d53a7SEvalZero elem_addr, sub_addr);
1405*042d53a7SEvalZero
1406*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_MOD_SUB_STATUS);
1407*042d53a7SEvalZero
1408*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
1409*042d53a7SEvalZero net_buf_simple_add_le16(msg, elem_addr);
1410*042d53a7SEvalZero net_buf_simple_add_le16(msg, sub_addr);
1411*042d53a7SEvalZero
1412*042d53a7SEvalZero if (vnd) {
1413*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, 4), mod_id, 4);
1414*042d53a7SEvalZero } else {
1415*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, 2), mod_id, 2);
1416*042d53a7SEvalZero }
1417*042d53a7SEvalZero
1418*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
1419*042d53a7SEvalZero BT_ERR("Unable to send Model Subscription Status");
1420*042d53a7SEvalZero }
1421*042d53a7SEvalZero
1422*042d53a7SEvalZero os_mbuf_free_chain(msg);
1423*042d53a7SEvalZero }
1424*042d53a7SEvalZero
mod_sub_add(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1425*042d53a7SEvalZero static void mod_sub_add(struct bt_mesh_model *model,
1426*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1427*042d53a7SEvalZero struct os_mbuf *buf)
1428*042d53a7SEvalZero {
1429*042d53a7SEvalZero u16_t elem_addr, sub_addr;
1430*042d53a7SEvalZero struct bt_mesh_model *mod;
1431*042d53a7SEvalZero struct bt_mesh_elem *elem;
1432*042d53a7SEvalZero u8_t *mod_id;
1433*042d53a7SEvalZero u8_t status;
1434*042d53a7SEvalZero bool vnd;
1435*042d53a7SEvalZero int i;
1436*042d53a7SEvalZero
1437*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1438*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1439*042d53a7SEvalZero BT_WARN("Prohibited element address");
1440*042d53a7SEvalZero return;
1441*042d53a7SEvalZero }
1442*042d53a7SEvalZero
1443*042d53a7SEvalZero sub_addr = net_buf_simple_pull_le16(buf);
1444*042d53a7SEvalZero
1445*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x, sub_addr 0x%04x", elem_addr, sub_addr);
1446*042d53a7SEvalZero
1447*042d53a7SEvalZero mod_id = buf->om_data;
1448*042d53a7SEvalZero
1449*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1450*042d53a7SEvalZero if (!elem) {
1451*042d53a7SEvalZero mod = NULL;
1452*042d53a7SEvalZero vnd = (buf->om_len == 4);
1453*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1454*042d53a7SEvalZero goto send_status;
1455*042d53a7SEvalZero }
1456*042d53a7SEvalZero
1457*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1458*042d53a7SEvalZero if (!mod) {
1459*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1460*042d53a7SEvalZero goto send_status;
1461*042d53a7SEvalZero }
1462*042d53a7SEvalZero
1463*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) {
1464*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1465*042d53a7SEvalZero goto send_status;
1466*042d53a7SEvalZero }
1467*042d53a7SEvalZero
1468*042d53a7SEvalZero if (bt_mesh_model_find_group(mod, sub_addr)) {
1469*042d53a7SEvalZero /* Tried to add existing subscription */
1470*042d53a7SEvalZero status = STATUS_SUCCESS;
1471*042d53a7SEvalZero goto send_status;
1472*042d53a7SEvalZero }
1473*042d53a7SEvalZero
1474*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
1475*042d53a7SEvalZero if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
1476*042d53a7SEvalZero mod->groups[i] = sub_addr;
1477*042d53a7SEvalZero break;
1478*042d53a7SEvalZero }
1479*042d53a7SEvalZero }
1480*042d53a7SEvalZero
1481*042d53a7SEvalZero if (i == ARRAY_SIZE(mod->groups)) {
1482*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
1483*042d53a7SEvalZero } else {
1484*042d53a7SEvalZero status = STATUS_SUCCESS;
1485*042d53a7SEvalZero
1486*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1487*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
1488*042d53a7SEvalZero }
1489*042d53a7SEvalZero
1490*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
1491*042d53a7SEvalZero bt_mesh_lpn_group_add(sub_addr);
1492*042d53a7SEvalZero }
1493*042d53a7SEvalZero }
1494*042d53a7SEvalZero
1495*042d53a7SEvalZero send_status:
1496*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
1497*042d53a7SEvalZero mod_id, vnd);
1498*042d53a7SEvalZero }
1499*042d53a7SEvalZero
mod_sub_del(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1500*042d53a7SEvalZero static void mod_sub_del(struct bt_mesh_model *model,
1501*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1502*042d53a7SEvalZero struct os_mbuf *buf)
1503*042d53a7SEvalZero {
1504*042d53a7SEvalZero u16_t elem_addr, sub_addr;
1505*042d53a7SEvalZero struct bt_mesh_model *mod;
1506*042d53a7SEvalZero struct bt_mesh_elem *elem;
1507*042d53a7SEvalZero u8_t *mod_id;
1508*042d53a7SEvalZero u16_t *match;
1509*042d53a7SEvalZero u8_t status;
1510*042d53a7SEvalZero bool vnd;
1511*042d53a7SEvalZero
1512*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1513*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1514*042d53a7SEvalZero BT_WARN("Prohibited element address");
1515*042d53a7SEvalZero return;
1516*042d53a7SEvalZero }
1517*042d53a7SEvalZero
1518*042d53a7SEvalZero sub_addr = net_buf_simple_pull_le16(buf);
1519*042d53a7SEvalZero
1520*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr);
1521*042d53a7SEvalZero
1522*042d53a7SEvalZero mod_id = buf->om_data;
1523*042d53a7SEvalZero
1524*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1525*042d53a7SEvalZero if (!elem) {
1526*042d53a7SEvalZero mod = NULL;
1527*042d53a7SEvalZero vnd = (buf->om_len == 4);
1528*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1529*042d53a7SEvalZero goto send_status;
1530*042d53a7SEvalZero }
1531*042d53a7SEvalZero
1532*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1533*042d53a7SEvalZero if (!mod) {
1534*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1535*042d53a7SEvalZero goto send_status;
1536*042d53a7SEvalZero }
1537*042d53a7SEvalZero
1538*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) {
1539*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1540*042d53a7SEvalZero goto send_status;
1541*042d53a7SEvalZero }
1542*042d53a7SEvalZero
1543*042d53a7SEvalZero /* An attempt to remove a non-existing address shall be treated
1544*042d53a7SEvalZero * as a success.
1545*042d53a7SEvalZero */
1546*042d53a7SEvalZero status = STATUS_SUCCESS;
1547*042d53a7SEvalZero
1548*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
1549*042d53a7SEvalZero bt_mesh_lpn_group_del(&sub_addr, 1);
1550*042d53a7SEvalZero }
1551*042d53a7SEvalZero
1552*042d53a7SEvalZero match = bt_mesh_model_find_group(mod, sub_addr);
1553*042d53a7SEvalZero if (match) {
1554*042d53a7SEvalZero *match = BT_MESH_ADDR_UNASSIGNED;
1555*042d53a7SEvalZero
1556*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1557*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
1558*042d53a7SEvalZero }
1559*042d53a7SEvalZero }
1560*042d53a7SEvalZero
1561*042d53a7SEvalZero send_status:
1562*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
1563*042d53a7SEvalZero mod_id, vnd);
1564*042d53a7SEvalZero }
1565*042d53a7SEvalZero
mod_sub_overwrite(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1566*042d53a7SEvalZero static void mod_sub_overwrite(struct bt_mesh_model *model,
1567*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1568*042d53a7SEvalZero struct os_mbuf *buf)
1569*042d53a7SEvalZero {
1570*042d53a7SEvalZero u16_t elem_addr, sub_addr;
1571*042d53a7SEvalZero struct bt_mesh_model *mod;
1572*042d53a7SEvalZero struct bt_mesh_elem *elem;
1573*042d53a7SEvalZero u8_t *mod_id;
1574*042d53a7SEvalZero u8_t status;
1575*042d53a7SEvalZero bool vnd;
1576*042d53a7SEvalZero
1577*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1578*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1579*042d53a7SEvalZero BT_WARN("Prohibited element address");
1580*042d53a7SEvalZero return;
1581*042d53a7SEvalZero }
1582*042d53a7SEvalZero
1583*042d53a7SEvalZero sub_addr = net_buf_simple_pull_le16(buf);
1584*042d53a7SEvalZero
1585*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr);
1586*042d53a7SEvalZero
1587*042d53a7SEvalZero mod_id = buf->om_data;
1588*042d53a7SEvalZero
1589*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1590*042d53a7SEvalZero if (!elem) {
1591*042d53a7SEvalZero mod = NULL;
1592*042d53a7SEvalZero vnd = (buf->om_len == 4);
1593*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1594*042d53a7SEvalZero goto send_status;
1595*042d53a7SEvalZero }
1596*042d53a7SEvalZero
1597*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1598*042d53a7SEvalZero if (!mod) {
1599*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1600*042d53a7SEvalZero goto send_status;
1601*042d53a7SEvalZero }
1602*042d53a7SEvalZero
1603*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) {
1604*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1605*042d53a7SEvalZero goto send_status;
1606*042d53a7SEvalZero }
1607*042d53a7SEvalZero
1608*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
1609*042d53a7SEvalZero bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
1610*042d53a7SEvalZero }
1611*042d53a7SEvalZero
1612*042d53a7SEvalZero mod_sub_list_clear(mod);
1613*042d53a7SEvalZero
1614*042d53a7SEvalZero if (ARRAY_SIZE(mod->groups) > 0) {
1615*042d53a7SEvalZero mod->groups[0] = sub_addr;
1616*042d53a7SEvalZero status = STATUS_SUCCESS;
1617*042d53a7SEvalZero
1618*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1619*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
1620*042d53a7SEvalZero }
1621*042d53a7SEvalZero
1622*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
1623*042d53a7SEvalZero bt_mesh_lpn_group_add(sub_addr);
1624*042d53a7SEvalZero }
1625*042d53a7SEvalZero } else {
1626*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
1627*042d53a7SEvalZero }
1628*042d53a7SEvalZero
1629*042d53a7SEvalZero
1630*042d53a7SEvalZero send_status:
1631*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
1632*042d53a7SEvalZero mod_id, vnd);
1633*042d53a7SEvalZero }
1634*042d53a7SEvalZero
mod_sub_del_all(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1635*042d53a7SEvalZero static void mod_sub_del_all(struct bt_mesh_model *model,
1636*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1637*042d53a7SEvalZero struct os_mbuf *buf)
1638*042d53a7SEvalZero {
1639*042d53a7SEvalZero struct bt_mesh_model *mod;
1640*042d53a7SEvalZero struct bt_mesh_elem *elem;
1641*042d53a7SEvalZero u16_t elem_addr;
1642*042d53a7SEvalZero u8_t *mod_id;
1643*042d53a7SEvalZero u8_t status;
1644*042d53a7SEvalZero bool vnd;
1645*042d53a7SEvalZero
1646*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1647*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1648*042d53a7SEvalZero BT_WARN("Prohibited element address");
1649*042d53a7SEvalZero return;
1650*042d53a7SEvalZero }
1651*042d53a7SEvalZero
1652*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x", elem_addr);
1653*042d53a7SEvalZero
1654*042d53a7SEvalZero mod_id = buf->om_data;
1655*042d53a7SEvalZero
1656*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1657*042d53a7SEvalZero if (!elem) {
1658*042d53a7SEvalZero mod = NULL;
1659*042d53a7SEvalZero vnd = (buf->om_len == 4);
1660*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1661*042d53a7SEvalZero goto send_status;
1662*042d53a7SEvalZero }
1663*042d53a7SEvalZero
1664*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1665*042d53a7SEvalZero if (!mod) {
1666*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1667*042d53a7SEvalZero goto send_status;
1668*042d53a7SEvalZero }
1669*042d53a7SEvalZero
1670*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
1671*042d53a7SEvalZero bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
1672*042d53a7SEvalZero }
1673*042d53a7SEvalZero
1674*042d53a7SEvalZero mod_sub_list_clear(mod);
1675*042d53a7SEvalZero
1676*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1677*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
1678*042d53a7SEvalZero }
1679*042d53a7SEvalZero
1680*042d53a7SEvalZero status = STATUS_SUCCESS;
1681*042d53a7SEvalZero
1682*042d53a7SEvalZero send_status:
1683*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr,
1684*042d53a7SEvalZero BT_MESH_ADDR_UNASSIGNED, mod_id, vnd);
1685*042d53a7SEvalZero }
1686*042d53a7SEvalZero
mod_sub_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1687*042d53a7SEvalZero static void mod_sub_get(struct bt_mesh_model *model,
1688*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1689*042d53a7SEvalZero struct os_mbuf *buf)
1690*042d53a7SEvalZero {
1691*042d53a7SEvalZero struct os_mbuf *msg =
1692*042d53a7SEvalZero NET_BUF_SIMPLE(2 + 5 + 4 +
1693*042d53a7SEvalZero MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) * 2);
1694*042d53a7SEvalZero struct bt_mesh_model *mod;
1695*042d53a7SEvalZero struct bt_mesh_elem *elem;
1696*042d53a7SEvalZero u16_t addr, id;
1697*042d53a7SEvalZero int i;
1698*042d53a7SEvalZero
1699*042d53a7SEvalZero addr = net_buf_simple_pull_le16(buf);
1700*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
1701*042d53a7SEvalZero BT_WARN("Prohibited element address");
1702*042d53a7SEvalZero goto done;
1703*042d53a7SEvalZero }
1704*042d53a7SEvalZero
1705*042d53a7SEvalZero id = net_buf_simple_pull_le16(buf);
1706*042d53a7SEvalZero
1707*042d53a7SEvalZero BT_DBG("addr 0x%04x id 0x%04x", addr, id);
1708*042d53a7SEvalZero
1709*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_MOD_SUB_LIST);
1710*042d53a7SEvalZero
1711*042d53a7SEvalZero elem = bt_mesh_elem_find(addr);
1712*042d53a7SEvalZero if (!elem) {
1713*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_INVALID_ADDRESS);
1714*042d53a7SEvalZero net_buf_simple_add_le16(msg, addr);
1715*042d53a7SEvalZero net_buf_simple_add_le16(msg, id);
1716*042d53a7SEvalZero goto send_list;
1717*042d53a7SEvalZero }
1718*042d53a7SEvalZero
1719*042d53a7SEvalZero mod = bt_mesh_model_find(elem, id);
1720*042d53a7SEvalZero if (!mod) {
1721*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_INVALID_MODEL);
1722*042d53a7SEvalZero net_buf_simple_add_le16(msg, addr);
1723*042d53a7SEvalZero net_buf_simple_add_le16(msg, id);
1724*042d53a7SEvalZero goto send_list;
1725*042d53a7SEvalZero }
1726*042d53a7SEvalZero
1727*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_SUCCESS);
1728*042d53a7SEvalZero
1729*042d53a7SEvalZero net_buf_simple_add_le16(msg, addr);
1730*042d53a7SEvalZero net_buf_simple_add_le16(msg, id);
1731*042d53a7SEvalZero
1732*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
1733*042d53a7SEvalZero if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
1734*042d53a7SEvalZero net_buf_simple_add_le16(msg, mod->groups[i]);
1735*042d53a7SEvalZero }
1736*042d53a7SEvalZero }
1737*042d53a7SEvalZero
1738*042d53a7SEvalZero send_list:
1739*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
1740*042d53a7SEvalZero BT_ERR("Unable to send Model Subscription List");
1741*042d53a7SEvalZero }
1742*042d53a7SEvalZero
1743*042d53a7SEvalZero done:
1744*042d53a7SEvalZero os_mbuf_free_chain(msg);
1745*042d53a7SEvalZero
1746*042d53a7SEvalZero }
1747*042d53a7SEvalZero
mod_sub_get_vnd(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1748*042d53a7SEvalZero static void mod_sub_get_vnd(struct bt_mesh_model *model,
1749*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1750*042d53a7SEvalZero struct os_mbuf *buf)
1751*042d53a7SEvalZero {
1752*042d53a7SEvalZero struct os_mbuf *msg =
1753*042d53a7SEvalZero NET_BUF_SIMPLE(2 + 7 + 4 +
1754*042d53a7SEvalZero MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) * 2);
1755*042d53a7SEvalZero struct bt_mesh_model *mod;
1756*042d53a7SEvalZero struct bt_mesh_elem *elem;
1757*042d53a7SEvalZero u16_t company, addr, id;
1758*042d53a7SEvalZero int i;
1759*042d53a7SEvalZero
1760*042d53a7SEvalZero addr = net_buf_simple_pull_le16(buf);
1761*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
1762*042d53a7SEvalZero BT_WARN("Prohibited element address");
1763*042d53a7SEvalZero goto done;
1764*042d53a7SEvalZero }
1765*042d53a7SEvalZero
1766*042d53a7SEvalZero company = net_buf_simple_pull_le16(buf);
1767*042d53a7SEvalZero id = net_buf_simple_pull_le16(buf);
1768*042d53a7SEvalZero
1769*042d53a7SEvalZero BT_DBG("addr 0x%04x company 0x%04x id 0x%04x", addr, company, id);
1770*042d53a7SEvalZero
1771*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_MOD_SUB_LIST_VND);
1772*042d53a7SEvalZero
1773*042d53a7SEvalZero elem = bt_mesh_elem_find(addr);
1774*042d53a7SEvalZero if (!elem) {
1775*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_INVALID_ADDRESS);
1776*042d53a7SEvalZero net_buf_simple_add_le16(msg, addr);
1777*042d53a7SEvalZero net_buf_simple_add_le16(msg, company);
1778*042d53a7SEvalZero net_buf_simple_add_le16(msg, id);
1779*042d53a7SEvalZero goto send_list;
1780*042d53a7SEvalZero }
1781*042d53a7SEvalZero
1782*042d53a7SEvalZero mod = bt_mesh_model_find_vnd(elem, company, id);
1783*042d53a7SEvalZero if (!mod) {
1784*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_INVALID_MODEL);
1785*042d53a7SEvalZero net_buf_simple_add_le16(msg, addr);
1786*042d53a7SEvalZero net_buf_simple_add_le16(msg, company);
1787*042d53a7SEvalZero net_buf_simple_add_le16(msg, id);
1788*042d53a7SEvalZero goto send_list;
1789*042d53a7SEvalZero }
1790*042d53a7SEvalZero
1791*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_SUCCESS);
1792*042d53a7SEvalZero
1793*042d53a7SEvalZero net_buf_simple_add_le16(msg, addr);
1794*042d53a7SEvalZero net_buf_simple_add_le16(msg, company);
1795*042d53a7SEvalZero net_buf_simple_add_le16(msg, id);
1796*042d53a7SEvalZero
1797*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
1798*042d53a7SEvalZero if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
1799*042d53a7SEvalZero net_buf_simple_add_le16(msg, mod->groups[i]);
1800*042d53a7SEvalZero }
1801*042d53a7SEvalZero }
1802*042d53a7SEvalZero
1803*042d53a7SEvalZero send_list:
1804*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
1805*042d53a7SEvalZero BT_ERR("Unable to send Vendor Model Subscription List");
1806*042d53a7SEvalZero }
1807*042d53a7SEvalZero
1808*042d53a7SEvalZero done:
1809*042d53a7SEvalZero os_mbuf_free_chain(msg);
1810*042d53a7SEvalZero
1811*042d53a7SEvalZero }
1812*042d53a7SEvalZero
1813*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH_LABEL_COUNT) > 0
mod_sub_va_add(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1814*042d53a7SEvalZero static void mod_sub_va_add(struct bt_mesh_model *model,
1815*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1816*042d53a7SEvalZero struct os_mbuf *buf)
1817*042d53a7SEvalZero {
1818*042d53a7SEvalZero u16_t elem_addr, sub_addr;
1819*042d53a7SEvalZero struct bt_mesh_model *mod;
1820*042d53a7SEvalZero struct bt_mesh_elem *elem;
1821*042d53a7SEvalZero u8_t *label_uuid;
1822*042d53a7SEvalZero u8_t *mod_id;
1823*042d53a7SEvalZero u8_t status;
1824*042d53a7SEvalZero bool vnd;
1825*042d53a7SEvalZero int i;
1826*042d53a7SEvalZero
1827*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1828*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1829*042d53a7SEvalZero BT_WARN("Prohibited element address");
1830*042d53a7SEvalZero return;
1831*042d53a7SEvalZero }
1832*042d53a7SEvalZero
1833*042d53a7SEvalZero label_uuid = buf->om_data;
1834*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
1835*042d53a7SEvalZero
1836*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x", elem_addr);
1837*042d53a7SEvalZero
1838*042d53a7SEvalZero mod_id = buf->om_data;
1839*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1840*042d53a7SEvalZero if (!elem) {
1841*042d53a7SEvalZero mod = NULL;
1842*042d53a7SEvalZero vnd = (buf->om_len == 4);
1843*042d53a7SEvalZero sub_addr = BT_MESH_ADDR_UNASSIGNED;
1844*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1845*042d53a7SEvalZero goto send_status;
1846*042d53a7SEvalZero }
1847*042d53a7SEvalZero
1848*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1849*042d53a7SEvalZero if (!mod) {
1850*042d53a7SEvalZero sub_addr = BT_MESH_ADDR_UNASSIGNED;
1851*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1852*042d53a7SEvalZero goto send_status;
1853*042d53a7SEvalZero }
1854*042d53a7SEvalZero
1855*042d53a7SEvalZero status = va_add(label_uuid, &sub_addr);
1856*042d53a7SEvalZero if (status != STATUS_SUCCESS) {
1857*042d53a7SEvalZero goto send_status;
1858*042d53a7SEvalZero }
1859*042d53a7SEvalZero
1860*042d53a7SEvalZero if (bt_mesh_model_find_group(mod, sub_addr)) {
1861*042d53a7SEvalZero /* Tried to add existing subscription */
1862*042d53a7SEvalZero status = STATUS_SUCCESS;
1863*042d53a7SEvalZero goto send_status;
1864*042d53a7SEvalZero }
1865*042d53a7SEvalZero
1866*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
1867*042d53a7SEvalZero if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
1868*042d53a7SEvalZero mod->groups[i] = sub_addr;
1869*042d53a7SEvalZero break;
1870*042d53a7SEvalZero }
1871*042d53a7SEvalZero }
1872*042d53a7SEvalZero
1873*042d53a7SEvalZero if (i == ARRAY_SIZE(mod->groups)) {
1874*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
1875*042d53a7SEvalZero } else {
1876*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
1877*042d53a7SEvalZero bt_mesh_lpn_group_add(sub_addr);
1878*042d53a7SEvalZero }
1879*042d53a7SEvalZero
1880*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1881*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
1882*042d53a7SEvalZero }
1883*042d53a7SEvalZero
1884*042d53a7SEvalZero status = STATUS_SUCCESS;
1885*042d53a7SEvalZero }
1886*042d53a7SEvalZero
1887*042d53a7SEvalZero send_status:
1888*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
1889*042d53a7SEvalZero mod_id, vnd);
1890*042d53a7SEvalZero }
1891*042d53a7SEvalZero
mod_sub_va_del(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1892*042d53a7SEvalZero static void mod_sub_va_del(struct bt_mesh_model *model,
1893*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1894*042d53a7SEvalZero struct os_mbuf *buf)
1895*042d53a7SEvalZero {
1896*042d53a7SEvalZero u16_t elem_addr, sub_addr;
1897*042d53a7SEvalZero struct bt_mesh_model *mod;
1898*042d53a7SEvalZero struct bt_mesh_elem *elem;
1899*042d53a7SEvalZero u8_t *label_uuid;
1900*042d53a7SEvalZero u8_t *mod_id;
1901*042d53a7SEvalZero u16_t *match;
1902*042d53a7SEvalZero u8_t status;
1903*042d53a7SEvalZero bool vnd;
1904*042d53a7SEvalZero
1905*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1906*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1907*042d53a7SEvalZero BT_WARN("Prohibited element address");
1908*042d53a7SEvalZero return;
1909*042d53a7SEvalZero }
1910*042d53a7SEvalZero
1911*042d53a7SEvalZero label_uuid = buf->om_data;
1912*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
1913*042d53a7SEvalZero
1914*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x", elem_addr);
1915*042d53a7SEvalZero
1916*042d53a7SEvalZero mod_id = buf->om_data;
1917*042d53a7SEvalZero
1918*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1919*042d53a7SEvalZero if (!elem) {
1920*042d53a7SEvalZero mod = NULL;
1921*042d53a7SEvalZero vnd = (buf->om_len == 4);
1922*042d53a7SEvalZero sub_addr = BT_MESH_ADDR_UNASSIGNED;
1923*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1924*042d53a7SEvalZero goto send_status;
1925*042d53a7SEvalZero }
1926*042d53a7SEvalZero
1927*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1928*042d53a7SEvalZero if (!mod) {
1929*042d53a7SEvalZero sub_addr = BT_MESH_ADDR_UNASSIGNED;
1930*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1931*042d53a7SEvalZero goto send_status;
1932*042d53a7SEvalZero }
1933*042d53a7SEvalZero
1934*042d53a7SEvalZero status = va_del(label_uuid, &sub_addr);
1935*042d53a7SEvalZero if (sub_addr == BT_MESH_ADDR_UNASSIGNED) {
1936*042d53a7SEvalZero goto send_status;
1937*042d53a7SEvalZero }
1938*042d53a7SEvalZero
1939*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
1940*042d53a7SEvalZero bt_mesh_lpn_group_del(&sub_addr, 1);
1941*042d53a7SEvalZero }
1942*042d53a7SEvalZero
1943*042d53a7SEvalZero match = bt_mesh_model_find_group(mod, sub_addr);
1944*042d53a7SEvalZero if (match) {
1945*042d53a7SEvalZero *match = BT_MESH_ADDR_UNASSIGNED;
1946*042d53a7SEvalZero
1947*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
1948*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
1949*042d53a7SEvalZero }
1950*042d53a7SEvalZero
1951*042d53a7SEvalZero status = STATUS_SUCCESS;
1952*042d53a7SEvalZero } else {
1953*042d53a7SEvalZero status = STATUS_CANNOT_REMOVE;
1954*042d53a7SEvalZero }
1955*042d53a7SEvalZero
1956*042d53a7SEvalZero send_status:
1957*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
1958*042d53a7SEvalZero mod_id, vnd);
1959*042d53a7SEvalZero }
1960*042d53a7SEvalZero
mod_sub_va_overwrite(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)1961*042d53a7SEvalZero static void mod_sub_va_overwrite(struct bt_mesh_model *model,
1962*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
1963*042d53a7SEvalZero struct os_mbuf *buf)
1964*042d53a7SEvalZero {
1965*042d53a7SEvalZero u16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED;
1966*042d53a7SEvalZero struct bt_mesh_model *mod;
1967*042d53a7SEvalZero struct bt_mesh_elem *elem;
1968*042d53a7SEvalZero u8_t *label_uuid;
1969*042d53a7SEvalZero u8_t *mod_id;
1970*042d53a7SEvalZero u8_t status;
1971*042d53a7SEvalZero bool vnd;
1972*042d53a7SEvalZero
1973*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
1974*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
1975*042d53a7SEvalZero BT_WARN("Prohibited element address");
1976*042d53a7SEvalZero return;
1977*042d53a7SEvalZero }
1978*042d53a7SEvalZero
1979*042d53a7SEvalZero label_uuid = buf->om_data;
1980*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
1981*042d53a7SEvalZero mod_id = buf->om_data;
1982*042d53a7SEvalZero
1983*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x, addr %s, mod_id %s", elem_addr,
1984*042d53a7SEvalZero bt_hex(label_uuid, 16), bt_hex(mod_id, buf->om_len));
1985*042d53a7SEvalZero
1986*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
1987*042d53a7SEvalZero if (!elem) {
1988*042d53a7SEvalZero mod = NULL;
1989*042d53a7SEvalZero vnd = (buf->om_len == 4);
1990*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
1991*042d53a7SEvalZero goto send_status;
1992*042d53a7SEvalZero }
1993*042d53a7SEvalZero
1994*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
1995*042d53a7SEvalZero if (!mod) {
1996*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
1997*042d53a7SEvalZero goto send_status;
1998*042d53a7SEvalZero }
1999*042d53a7SEvalZero
2000*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
2001*042d53a7SEvalZero bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
2002*042d53a7SEvalZero }
2003*042d53a7SEvalZero
2004*042d53a7SEvalZero mod_sub_list_clear(mod);
2005*042d53a7SEvalZero
2006*042d53a7SEvalZero if (ARRAY_SIZE(mod->groups) > 0) {
2007*042d53a7SEvalZero status = va_add(label_uuid, &sub_addr);
2008*042d53a7SEvalZero if (status == STATUS_SUCCESS) {
2009*042d53a7SEvalZero mod->groups[0] = sub_addr;
2010*042d53a7SEvalZero
2011*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
2012*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
2013*042d53a7SEvalZero }
2014*042d53a7SEvalZero
2015*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
2016*042d53a7SEvalZero bt_mesh_lpn_group_add(sub_addr);
2017*042d53a7SEvalZero }
2018*042d53a7SEvalZero }
2019*042d53a7SEvalZero } else {
2020*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
2021*042d53a7SEvalZero }
2022*042d53a7SEvalZero
2023*042d53a7SEvalZero send_status:
2024*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
2025*042d53a7SEvalZero mod_id, vnd);
2026*042d53a7SEvalZero }
2027*042d53a7SEvalZero #else
mod_sub_va_add(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2028*042d53a7SEvalZero static void mod_sub_va_add(struct bt_mesh_model *model,
2029*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2030*042d53a7SEvalZero struct os_mbuf *buf)
2031*042d53a7SEvalZero {
2032*042d53a7SEvalZero struct bt_mesh_model *mod;
2033*042d53a7SEvalZero struct bt_mesh_elem *elem;
2034*042d53a7SEvalZero u16_t elem_addr;
2035*042d53a7SEvalZero u8_t *mod_id;
2036*042d53a7SEvalZero u8_t status;
2037*042d53a7SEvalZero bool vnd;
2038*042d53a7SEvalZero
2039*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
2040*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
2041*042d53a7SEvalZero BT_WARN("Prohibited element address");
2042*042d53a7SEvalZero return;
2043*042d53a7SEvalZero }
2044*042d53a7SEvalZero
2045*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
2046*042d53a7SEvalZero
2047*042d53a7SEvalZero mod_id = buf->om_data;
2048*042d53a7SEvalZero
2049*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
2050*042d53a7SEvalZero if (!elem) {
2051*042d53a7SEvalZero mod = NULL;
2052*042d53a7SEvalZero vnd = (buf->om_len == 4);
2053*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
2054*042d53a7SEvalZero goto send_status;
2055*042d53a7SEvalZero }
2056*042d53a7SEvalZero
2057*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
2058*042d53a7SEvalZero if (!mod) {
2059*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
2060*042d53a7SEvalZero goto send_status;
2061*042d53a7SEvalZero }
2062*042d53a7SEvalZero
2063*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
2064*042d53a7SEvalZero
2065*042d53a7SEvalZero send_status:
2066*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr,
2067*042d53a7SEvalZero BT_MESH_ADDR_UNASSIGNED, mod_id, vnd);
2068*042d53a7SEvalZero }
2069*042d53a7SEvalZero
mod_sub_va_del(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2070*042d53a7SEvalZero static void mod_sub_va_del(struct bt_mesh_model *model,
2071*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2072*042d53a7SEvalZero struct os_mbuf *buf)
2073*042d53a7SEvalZero {
2074*042d53a7SEvalZero struct bt_mesh_elem *elem;
2075*042d53a7SEvalZero u16_t elem_addr;
2076*042d53a7SEvalZero u8_t *mod_id;
2077*042d53a7SEvalZero u8_t status;
2078*042d53a7SEvalZero bool vnd;
2079*042d53a7SEvalZero
2080*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
2081*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
2082*042d53a7SEvalZero BT_WARN("Prohibited element address");
2083*042d53a7SEvalZero return;
2084*042d53a7SEvalZero }
2085*042d53a7SEvalZero
2086*042d53a7SEvalZero net_buf_simple_pull(buf, 16);
2087*042d53a7SEvalZero
2088*042d53a7SEvalZero mod_id = buf->om_data;
2089*042d53a7SEvalZero
2090*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
2091*042d53a7SEvalZero if (!elem) {
2092*042d53a7SEvalZero vnd = (buf->om_len == 4);
2093*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
2094*042d53a7SEvalZero goto send_status;
2095*042d53a7SEvalZero }
2096*042d53a7SEvalZero
2097*042d53a7SEvalZero if (!get_model(elem, buf, &vnd)) {
2098*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
2099*042d53a7SEvalZero goto send_status;
2100*042d53a7SEvalZero }
2101*042d53a7SEvalZero
2102*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
2103*042d53a7SEvalZero
2104*042d53a7SEvalZero send_status:
2105*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr,
2106*042d53a7SEvalZero BT_MESH_ADDR_UNASSIGNED, mod_id, vnd);
2107*042d53a7SEvalZero }
2108*042d53a7SEvalZero
mod_sub_va_overwrite(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2109*042d53a7SEvalZero static void mod_sub_va_overwrite(struct bt_mesh_model *model,
2110*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2111*042d53a7SEvalZero struct os_mbuf *buf)
2112*042d53a7SEvalZero {
2113*042d53a7SEvalZero struct bt_mesh_elem *elem;
2114*042d53a7SEvalZero u16_t elem_addr;
2115*042d53a7SEvalZero u8_t *mod_id;
2116*042d53a7SEvalZero u8_t status;
2117*042d53a7SEvalZero bool vnd;
2118*042d53a7SEvalZero
2119*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
2120*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
2121*042d53a7SEvalZero BT_WARN("Prohibited element address");
2122*042d53a7SEvalZero return;
2123*042d53a7SEvalZero }
2124*042d53a7SEvalZero
2125*042d53a7SEvalZero net_buf_simple_pull(buf, 18);
2126*042d53a7SEvalZero
2127*042d53a7SEvalZero mod_id = buf->om_data;
2128*042d53a7SEvalZero
2129*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
2130*042d53a7SEvalZero if (!elem) {
2131*042d53a7SEvalZero vnd = (buf->om_len == 4);
2132*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
2133*042d53a7SEvalZero goto send_status;
2134*042d53a7SEvalZero }
2135*042d53a7SEvalZero
2136*042d53a7SEvalZero if (!get_model(elem, buf, &vnd)) {
2137*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
2138*042d53a7SEvalZero goto send_status;
2139*042d53a7SEvalZero }
2140*042d53a7SEvalZero
2141*042d53a7SEvalZero status = STATUS_INSUFF_RESOURCES;
2142*042d53a7SEvalZero
2143*042d53a7SEvalZero send_status:
2144*042d53a7SEvalZero send_mod_sub_status(model, ctx, status, elem_addr,
2145*042d53a7SEvalZero BT_MESH_ADDR_UNASSIGNED, mod_id, vnd);
2146*042d53a7SEvalZero }
2147*042d53a7SEvalZero #endif /* MYNEWT_VAL(BLE_MESH_LABEL_COUNT) > 0 */
2148*042d53a7SEvalZero
send_net_key_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,u16_t idx,u8_t status)2149*042d53a7SEvalZero static void send_net_key_status(struct bt_mesh_model *model,
2150*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2151*042d53a7SEvalZero u16_t idx, u8_t status)
2152*042d53a7SEvalZero {
2153*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2154*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
2155*042d53a7SEvalZero
2156*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NET_KEY_STATUS);
2157*042d53a7SEvalZero
2158*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
2159*042d53a7SEvalZero net_buf_simple_add_le16(msg, idx);
2160*042d53a7SEvalZero
2161*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2162*042d53a7SEvalZero BT_ERR("Unable to send NetKey Status");
2163*042d53a7SEvalZero }
2164*042d53a7SEvalZero
2165*042d53a7SEvalZero os_mbuf_free_chain(msg);
2166*042d53a7SEvalZero }
2167*042d53a7SEvalZero
net_key_add(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2168*042d53a7SEvalZero static void net_key_add(struct bt_mesh_model *model,
2169*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2170*042d53a7SEvalZero struct os_mbuf *buf)
2171*042d53a7SEvalZero {
2172*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2173*042d53a7SEvalZero u16_t idx;
2174*042d53a7SEvalZero int err;
2175*042d53a7SEvalZero
2176*042d53a7SEvalZero idx = net_buf_simple_pull_le16(buf);
2177*042d53a7SEvalZero if (idx > 0xfff) {
2178*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
2179*042d53a7SEvalZero return;
2180*042d53a7SEvalZero }
2181*042d53a7SEvalZero
2182*042d53a7SEvalZero BT_DBG("idx 0x%04x", idx);
2183*042d53a7SEvalZero
2184*042d53a7SEvalZero sub = bt_mesh_subnet_get(idx);
2185*042d53a7SEvalZero if (!sub) {
2186*042d53a7SEvalZero int i;
2187*042d53a7SEvalZero
2188*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
2189*042d53a7SEvalZero if (bt_mesh.sub[i].net_idx == BT_MESH_KEY_UNUSED) {
2190*042d53a7SEvalZero sub = &bt_mesh.sub[i];
2191*042d53a7SEvalZero break;
2192*042d53a7SEvalZero }
2193*042d53a7SEvalZero }
2194*042d53a7SEvalZero
2195*042d53a7SEvalZero if (!sub) {
2196*042d53a7SEvalZero send_net_key_status(model, ctx, idx,
2197*042d53a7SEvalZero STATUS_INSUFF_RESOURCES);
2198*042d53a7SEvalZero return;
2199*042d53a7SEvalZero }
2200*042d53a7SEvalZero }
2201*042d53a7SEvalZero
2202*042d53a7SEvalZero /* Check for already existing subnet */
2203*042d53a7SEvalZero if (sub->net_idx == idx) {
2204*042d53a7SEvalZero u8_t status;
2205*042d53a7SEvalZero
2206*042d53a7SEvalZero if (memcmp(buf->om_data, sub->keys[0].net, 16)) {
2207*042d53a7SEvalZero status = STATUS_IDX_ALREADY_STORED;
2208*042d53a7SEvalZero } else {
2209*042d53a7SEvalZero status = STATUS_SUCCESS;
2210*042d53a7SEvalZero }
2211*042d53a7SEvalZero
2212*042d53a7SEvalZero send_net_key_status(model, ctx, idx, status);
2213*042d53a7SEvalZero return;
2214*042d53a7SEvalZero }
2215*042d53a7SEvalZero
2216*042d53a7SEvalZero err = bt_mesh_net_keys_create(&sub->keys[0], buf->om_data);
2217*042d53a7SEvalZero if (err) {
2218*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED);
2219*042d53a7SEvalZero return;
2220*042d53a7SEvalZero }
2221*042d53a7SEvalZero
2222*042d53a7SEvalZero sub->net_idx = idx;
2223*042d53a7SEvalZero
2224*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
2225*042d53a7SEvalZero BT_DBG("Storing NetKey persistently");
2226*042d53a7SEvalZero bt_mesh_store_subnet(sub);
2227*042d53a7SEvalZero }
2228*042d53a7SEvalZero
2229*042d53a7SEvalZero /* Make sure we have valid beacon data to be sent */
2230*042d53a7SEvalZero bt_mesh_net_beacon_update(sub);
2231*042d53a7SEvalZero
2232*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) {
2233*042d53a7SEvalZero sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
2234*042d53a7SEvalZero bt_mesh_proxy_beacon_send(sub);
2235*042d53a7SEvalZero bt_mesh_adv_update();
2236*042d53a7SEvalZero } else {
2237*042d53a7SEvalZero sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED;
2238*042d53a7SEvalZero }
2239*042d53a7SEvalZero
2240*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_SUCCESS);
2241*042d53a7SEvalZero }
2242*042d53a7SEvalZero
net_key_update(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2243*042d53a7SEvalZero static void net_key_update(struct bt_mesh_model *model,
2244*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2245*042d53a7SEvalZero struct os_mbuf *buf)
2246*042d53a7SEvalZero {
2247*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2248*042d53a7SEvalZero u16_t idx;
2249*042d53a7SEvalZero int err;
2250*042d53a7SEvalZero
2251*042d53a7SEvalZero idx = net_buf_simple_pull_le16(buf);
2252*042d53a7SEvalZero if (idx > 0xfff) {
2253*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
2254*042d53a7SEvalZero return;
2255*042d53a7SEvalZero }
2256*042d53a7SEvalZero
2257*042d53a7SEvalZero BT_DBG("idx 0x%04x", idx);
2258*042d53a7SEvalZero
2259*042d53a7SEvalZero sub = bt_mesh_subnet_get(idx);
2260*042d53a7SEvalZero if (!sub) {
2261*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_INVALID_NETKEY);
2262*042d53a7SEvalZero return;
2263*042d53a7SEvalZero }
2264*042d53a7SEvalZero
2265*042d53a7SEvalZero /* The node shall successfully process a NetKey Update message on a
2266*042d53a7SEvalZero * valid NetKeyIndex when the NetKey value is different and the Key
2267*042d53a7SEvalZero * Refresh procedure has not been started, or when the NetKey value is
2268*042d53a7SEvalZero * the same in Phase 1. The NetKey Update message shall generate an
2269*042d53a7SEvalZero * error when the node is in Phase 2, or Phase 3.
2270*042d53a7SEvalZero */
2271*042d53a7SEvalZero switch (sub->kr_phase) {
2272*042d53a7SEvalZero case BT_MESH_KR_NORMAL:
2273*042d53a7SEvalZero if (!memcmp(buf->om_data, sub->keys[0].net, 16)) {
2274*042d53a7SEvalZero return;
2275*042d53a7SEvalZero }
2276*042d53a7SEvalZero break;
2277*042d53a7SEvalZero case BT_MESH_KR_PHASE_1:
2278*042d53a7SEvalZero if (!memcmp(buf->om_data, sub->keys[1].net, 16)) {
2279*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_SUCCESS);
2280*042d53a7SEvalZero return;
2281*042d53a7SEvalZero }
2282*042d53a7SEvalZero /* fall through */
2283*042d53a7SEvalZero case BT_MESH_KR_PHASE_2:
2284*042d53a7SEvalZero case BT_MESH_KR_PHASE_3:
2285*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_CANNOT_UPDATE);
2286*042d53a7SEvalZero return;
2287*042d53a7SEvalZero }
2288*042d53a7SEvalZero
2289*042d53a7SEvalZero err = bt_mesh_net_keys_create(&sub->keys[1], buf->om_data);
2290*042d53a7SEvalZero if (!err && ((MYNEWT_VAL(BLE_MESH_LOW_POWER)) ||
2291*042d53a7SEvalZero (MYNEWT_VAL(BLE_MESH_FRIEND)))) {
2292*042d53a7SEvalZero err = friend_cred_update(sub);
2293*042d53a7SEvalZero }
2294*042d53a7SEvalZero
2295*042d53a7SEvalZero if (err) {
2296*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED);
2297*042d53a7SEvalZero return;
2298*042d53a7SEvalZero }
2299*042d53a7SEvalZero
2300*042d53a7SEvalZero sub->kr_phase = BT_MESH_KR_PHASE_1;
2301*042d53a7SEvalZero
2302*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
2303*042d53a7SEvalZero BT_DBG("Storing NetKey persistently");
2304*042d53a7SEvalZero bt_mesh_store_subnet(sub);
2305*042d53a7SEvalZero }
2306*042d53a7SEvalZero
2307*042d53a7SEvalZero bt_mesh_net_beacon_update(sub);
2308*042d53a7SEvalZero
2309*042d53a7SEvalZero send_net_key_status(model, ctx, idx, STATUS_SUCCESS);
2310*042d53a7SEvalZero }
2311*042d53a7SEvalZero
hb_pub_disable(struct bt_mesh_cfg_srv * cfg)2312*042d53a7SEvalZero static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg)
2313*042d53a7SEvalZero {
2314*042d53a7SEvalZero BT_DBG("");
2315*042d53a7SEvalZero
2316*042d53a7SEvalZero cfg->hb_pub.dst = BT_MESH_ADDR_UNASSIGNED;
2317*042d53a7SEvalZero cfg->hb_pub.count = 0;
2318*042d53a7SEvalZero cfg->hb_pub.ttl = 0;
2319*042d53a7SEvalZero cfg->hb_pub.period = 0;
2320*042d53a7SEvalZero
2321*042d53a7SEvalZero k_delayed_work_cancel(&cfg->hb_pub.timer);
2322*042d53a7SEvalZero }
2323*042d53a7SEvalZero
net_key_del(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2324*042d53a7SEvalZero static void net_key_del(struct bt_mesh_model *model,
2325*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2326*042d53a7SEvalZero struct os_mbuf *buf)
2327*042d53a7SEvalZero {
2328*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2329*042d53a7SEvalZero u16_t del_idx;
2330*042d53a7SEvalZero u8_t status;
2331*042d53a7SEvalZero
2332*042d53a7SEvalZero del_idx = net_buf_simple_pull_le16(buf);
2333*042d53a7SEvalZero if (del_idx > 0xfff) {
2334*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", del_idx);
2335*042d53a7SEvalZero return;
2336*042d53a7SEvalZero }
2337*042d53a7SEvalZero
2338*042d53a7SEvalZero BT_DBG("idx 0x%04x", del_idx);
2339*042d53a7SEvalZero
2340*042d53a7SEvalZero sub = bt_mesh_subnet_get(del_idx);
2341*042d53a7SEvalZero if (!sub) {
2342*042d53a7SEvalZero /* This could be a retry of a previous attempt that had its
2343*042d53a7SEvalZero * response lost, so pretend that it was a success.
2344*042d53a7SEvalZero */
2345*042d53a7SEvalZero status = STATUS_SUCCESS;
2346*042d53a7SEvalZero goto send_status;
2347*042d53a7SEvalZero }
2348*042d53a7SEvalZero
2349*042d53a7SEvalZero /* The key that the message was encrypted with cannot be removed.
2350*042d53a7SEvalZero * The NetKey List must contain a minimum of one NetKey.
2351*042d53a7SEvalZero */
2352*042d53a7SEvalZero if (ctx->net_idx == del_idx) {
2353*042d53a7SEvalZero status = STATUS_CANNOT_REMOVE;
2354*042d53a7SEvalZero goto send_status;
2355*042d53a7SEvalZero }
2356*042d53a7SEvalZero
2357*042d53a7SEvalZero bt_mesh_subnet_del(sub, true);
2358*042d53a7SEvalZero status = STATUS_SUCCESS;
2359*042d53a7SEvalZero
2360*042d53a7SEvalZero send_status:
2361*042d53a7SEvalZero send_net_key_status(model, ctx, del_idx, status);
2362*042d53a7SEvalZero }
2363*042d53a7SEvalZero
net_key_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2364*042d53a7SEvalZero static void net_key_get(struct bt_mesh_model *model,
2365*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2366*042d53a7SEvalZero struct os_mbuf *buf)
2367*042d53a7SEvalZero {
2368*042d53a7SEvalZero struct os_mbuf *msg =
2369*042d53a7SEvalZero NET_BUF_SIMPLE(2 + 4 +
2370*042d53a7SEvalZero IDX_LEN(MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)));
2371*042d53a7SEvalZero u16_t prev, i;
2372*042d53a7SEvalZero
2373*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NET_KEY_LIST);
2374*042d53a7SEvalZero
2375*042d53a7SEvalZero prev = BT_MESH_KEY_UNUSED;
2376*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
2377*042d53a7SEvalZero struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
2378*042d53a7SEvalZero
2379*042d53a7SEvalZero if (sub->net_idx == BT_MESH_KEY_UNUSED) {
2380*042d53a7SEvalZero continue;
2381*042d53a7SEvalZero }
2382*042d53a7SEvalZero
2383*042d53a7SEvalZero if (prev == BT_MESH_KEY_UNUSED) {
2384*042d53a7SEvalZero prev = sub->net_idx;
2385*042d53a7SEvalZero continue;
2386*042d53a7SEvalZero }
2387*042d53a7SEvalZero
2388*042d53a7SEvalZero key_idx_pack(msg, prev, sub->net_idx);
2389*042d53a7SEvalZero prev = BT_MESH_KEY_UNUSED;
2390*042d53a7SEvalZero }
2391*042d53a7SEvalZero
2392*042d53a7SEvalZero if (prev != BT_MESH_KEY_UNUSED) {
2393*042d53a7SEvalZero net_buf_simple_add_le16(msg, prev);
2394*042d53a7SEvalZero }
2395*042d53a7SEvalZero
2396*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2397*042d53a7SEvalZero BT_ERR("Unable to send NetKey List");
2398*042d53a7SEvalZero }
2399*042d53a7SEvalZero
2400*042d53a7SEvalZero os_mbuf_free_chain(msg);
2401*042d53a7SEvalZero }
2402*042d53a7SEvalZero
node_identity_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2403*042d53a7SEvalZero static void node_identity_get(struct bt_mesh_model *model,
2404*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2405*042d53a7SEvalZero struct os_mbuf *buf)
2406*042d53a7SEvalZero {
2407*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2408*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
2409*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2410*042d53a7SEvalZero u8_t node_id;
2411*042d53a7SEvalZero u16_t idx;
2412*042d53a7SEvalZero
2413*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
2414*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
2415*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
2416*042d53a7SEvalZero
2417*042d53a7SEvalZero idx = net_buf_simple_pull_le16(buf);
2418*042d53a7SEvalZero if (idx > 0xfff) {
2419*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
2420*042d53a7SEvalZero goto done;
2421*042d53a7SEvalZero }
2422*042d53a7SEvalZero
2423*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_STATUS);
2424*042d53a7SEvalZero
2425*042d53a7SEvalZero sub = bt_mesh_subnet_get(idx);
2426*042d53a7SEvalZero if (!sub) {
2427*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_INVALID_NETKEY);
2428*042d53a7SEvalZero node_id = 0x00;
2429*042d53a7SEvalZero } else {
2430*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_SUCCESS);
2431*042d53a7SEvalZero node_id = sub->node_id;
2432*042d53a7SEvalZero }
2433*042d53a7SEvalZero
2434*042d53a7SEvalZero net_buf_simple_add_le16(msg, idx);
2435*042d53a7SEvalZero net_buf_simple_add_u8(msg, node_id);
2436*042d53a7SEvalZero
2437*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2438*042d53a7SEvalZero BT_ERR("Unable to send Node Identity Status");
2439*042d53a7SEvalZero }
2440*042d53a7SEvalZero
2441*042d53a7SEvalZero done:
2442*042d53a7SEvalZero os_mbuf_free_chain(msg);
2443*042d53a7SEvalZero }
2444*042d53a7SEvalZero
node_identity_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2445*042d53a7SEvalZero static void node_identity_set(struct bt_mesh_model *model,
2446*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2447*042d53a7SEvalZero struct os_mbuf *buf)
2448*042d53a7SEvalZero {
2449*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2450*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
2451*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2452*042d53a7SEvalZero u8_t node_id;
2453*042d53a7SEvalZero u16_t idx;
2454*042d53a7SEvalZero
2455*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
2456*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
2457*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
2458*042d53a7SEvalZero
2459*042d53a7SEvalZero idx = net_buf_simple_pull_le16(buf);
2460*042d53a7SEvalZero if (idx > 0xfff) {
2461*042d53a7SEvalZero BT_WARN("Invalid NetKeyIndex 0x%04x", idx);
2462*042d53a7SEvalZero goto done;
2463*042d53a7SEvalZero }
2464*042d53a7SEvalZero
2465*042d53a7SEvalZero node_id = net_buf_simple_pull_u8(buf);
2466*042d53a7SEvalZero if (node_id != 0x00 && node_id != 0x01) {
2467*042d53a7SEvalZero BT_WARN("Invalid Node ID value 0x%02x", node_id);
2468*042d53a7SEvalZero goto done;
2469*042d53a7SEvalZero }
2470*042d53a7SEvalZero
2471*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_STATUS);
2472*042d53a7SEvalZero
2473*042d53a7SEvalZero sub = bt_mesh_subnet_get(idx);
2474*042d53a7SEvalZero if (!sub) {
2475*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_INVALID_NETKEY);
2476*042d53a7SEvalZero net_buf_simple_add_le16(msg, idx);
2477*042d53a7SEvalZero net_buf_simple_add_u8(msg, node_id);
2478*042d53a7SEvalZero } else {
2479*042d53a7SEvalZero net_buf_simple_add_u8(msg, STATUS_SUCCESS);
2480*042d53a7SEvalZero net_buf_simple_add_le16(msg, idx);
2481*042d53a7SEvalZero
2482*042d53a7SEvalZero /* Section 4.2.11.1: "When the GATT Proxy state is set to
2483*042d53a7SEvalZero * 0x00, the Node Identity state for all subnets shall be set
2484*042d53a7SEvalZero * to 0x00 and shall not be changed."
2485*042d53a7SEvalZero */
2486*042d53a7SEvalZero if (MYNEWT_VAL(BLE_MESH_GATT_PROXY) &&
2487*042d53a7SEvalZero bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
2488*042d53a7SEvalZero if (node_id) {
2489*042d53a7SEvalZero bt_mesh_proxy_identity_start(sub);
2490*042d53a7SEvalZero } else {
2491*042d53a7SEvalZero bt_mesh_proxy_identity_stop(sub);
2492*042d53a7SEvalZero }
2493*042d53a7SEvalZero bt_mesh_adv_update();
2494*042d53a7SEvalZero }
2495*042d53a7SEvalZero
2496*042d53a7SEvalZero net_buf_simple_add_u8(msg, sub->node_id);
2497*042d53a7SEvalZero }
2498*042d53a7SEvalZero
2499*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2500*042d53a7SEvalZero BT_ERR("Unable to send Node Identity Status");
2501*042d53a7SEvalZero }
2502*042d53a7SEvalZero
2503*042d53a7SEvalZero done:
2504*042d53a7SEvalZero os_mbuf_free_chain(msg);
2505*042d53a7SEvalZero
2506*042d53a7SEvalZero }
2507*042d53a7SEvalZero
create_mod_app_status(struct os_mbuf * msg,struct bt_mesh_model * mod,bool vnd,u16_t elem_addr,u16_t app_idx,u8_t status,u8_t * mod_id)2508*042d53a7SEvalZero static void create_mod_app_status(struct os_mbuf *msg,
2509*042d53a7SEvalZero struct bt_mesh_model *mod, bool vnd,
2510*042d53a7SEvalZero u16_t elem_addr, u16_t app_idx,
2511*042d53a7SEvalZero u8_t status, u8_t *mod_id)
2512*042d53a7SEvalZero {
2513*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_MOD_APP_STATUS);
2514*042d53a7SEvalZero
2515*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
2516*042d53a7SEvalZero net_buf_simple_add_le16(msg, elem_addr);
2517*042d53a7SEvalZero net_buf_simple_add_le16(msg, app_idx);
2518*042d53a7SEvalZero
2519*042d53a7SEvalZero if (vnd) {
2520*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, 4), mod_id, 4);
2521*042d53a7SEvalZero } else {
2522*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, 2), mod_id, 2);
2523*042d53a7SEvalZero }
2524*042d53a7SEvalZero }
2525*042d53a7SEvalZero
mod_app_bind(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2526*042d53a7SEvalZero static void mod_app_bind(struct bt_mesh_model *model,
2527*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2528*042d53a7SEvalZero struct os_mbuf *buf)
2529*042d53a7SEvalZero {
2530*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
2531*042d53a7SEvalZero u16_t elem_addr, key_app_idx;
2532*042d53a7SEvalZero struct bt_mesh_model *mod;
2533*042d53a7SEvalZero struct bt_mesh_elem *elem;
2534*042d53a7SEvalZero u8_t *mod_id, status;
2535*042d53a7SEvalZero bool vnd;
2536*042d53a7SEvalZero
2537*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
2538*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
2539*042d53a7SEvalZero BT_WARN("Prohibited element address");
2540*042d53a7SEvalZero goto done;
2541*042d53a7SEvalZero }
2542*042d53a7SEvalZero
2543*042d53a7SEvalZero key_app_idx = net_buf_simple_pull_le16(buf);
2544*042d53a7SEvalZero mod_id = buf->om_data;
2545*042d53a7SEvalZero
2546*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
2547*042d53a7SEvalZero if (!elem) {
2548*042d53a7SEvalZero mod = NULL;
2549*042d53a7SEvalZero vnd = (buf->om_len == 4);
2550*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
2551*042d53a7SEvalZero goto send_status;
2552*042d53a7SEvalZero }
2553*042d53a7SEvalZero
2554*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
2555*042d53a7SEvalZero if (!mod) {
2556*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
2557*042d53a7SEvalZero goto send_status;
2558*042d53a7SEvalZero }
2559*042d53a7SEvalZero
2560*042d53a7SEvalZero /* Configuration Server only allows device key based access */
2561*042d53a7SEvalZero if (model == mod) {
2562*042d53a7SEvalZero BT_ERR("Client tried to bind AppKey to Configuration Model");
2563*042d53a7SEvalZero status = STATUS_CANNOT_BIND;
2564*042d53a7SEvalZero goto send_status;
2565*042d53a7SEvalZero }
2566*042d53a7SEvalZero
2567*042d53a7SEvalZero status = mod_bind(mod, key_app_idx);
2568*042d53a7SEvalZero
2569*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) {
2570*042d53a7SEvalZero bt_test_mesh_model_bound(ctx->addr, mod, key_app_idx);
2571*042d53a7SEvalZero }
2572*042d53a7SEvalZero
2573*042d53a7SEvalZero send_status:
2574*042d53a7SEvalZero BT_DBG("status 0x%02x", status);
2575*042d53a7SEvalZero create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status,
2576*042d53a7SEvalZero mod_id);
2577*042d53a7SEvalZero
2578*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2579*042d53a7SEvalZero BT_ERR("Unable to send Model App Bind Status response");
2580*042d53a7SEvalZero }
2581*042d53a7SEvalZero
2582*042d53a7SEvalZero done:
2583*042d53a7SEvalZero os_mbuf_free_chain(msg);
2584*042d53a7SEvalZero
2585*042d53a7SEvalZero }
2586*042d53a7SEvalZero
mod_app_unbind(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2587*042d53a7SEvalZero static void mod_app_unbind(struct bt_mesh_model *model,
2588*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2589*042d53a7SEvalZero struct os_mbuf *buf)
2590*042d53a7SEvalZero {
2591*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
2592*042d53a7SEvalZero u16_t elem_addr, key_app_idx;
2593*042d53a7SEvalZero struct bt_mesh_model *mod;
2594*042d53a7SEvalZero struct bt_mesh_elem *elem;
2595*042d53a7SEvalZero u8_t *mod_id, status;
2596*042d53a7SEvalZero bool vnd;
2597*042d53a7SEvalZero
2598*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
2599*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
2600*042d53a7SEvalZero BT_WARN("Prohibited element address");
2601*042d53a7SEvalZero goto done;
2602*042d53a7SEvalZero }
2603*042d53a7SEvalZero
2604*042d53a7SEvalZero key_app_idx = net_buf_simple_pull_le16(buf);
2605*042d53a7SEvalZero mod_id = buf->om_data;
2606*042d53a7SEvalZero
2607*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
2608*042d53a7SEvalZero if (!elem) {
2609*042d53a7SEvalZero mod = NULL;
2610*042d53a7SEvalZero vnd = (buf->om_len == 4);
2611*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
2612*042d53a7SEvalZero goto send_status;
2613*042d53a7SEvalZero }
2614*042d53a7SEvalZero
2615*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
2616*042d53a7SEvalZero if (!mod) {
2617*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
2618*042d53a7SEvalZero goto send_status;
2619*042d53a7SEvalZero }
2620*042d53a7SEvalZero
2621*042d53a7SEvalZero status = mod_unbind(mod, key_app_idx, true);
2622*042d53a7SEvalZero
2623*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) {
2624*042d53a7SEvalZero bt_test_mesh_model_unbound(ctx->addr, mod, key_app_idx);
2625*042d53a7SEvalZero }
2626*042d53a7SEvalZero
2627*042d53a7SEvalZero send_status:
2628*042d53a7SEvalZero BT_DBG("status 0x%02x", status);
2629*042d53a7SEvalZero create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status,
2630*042d53a7SEvalZero mod_id);
2631*042d53a7SEvalZero
2632*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2633*042d53a7SEvalZero BT_ERR("Unable to send Model App Unbind Status response");
2634*042d53a7SEvalZero }
2635*042d53a7SEvalZero
2636*042d53a7SEvalZero done:
2637*042d53a7SEvalZero os_mbuf_free_chain(msg);
2638*042d53a7SEvalZero }
2639*042d53a7SEvalZero
2640*042d53a7SEvalZero #define KEY_LIST_LEN (MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) * 2)
2641*042d53a7SEvalZero
mod_app_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2642*042d53a7SEvalZero static void mod_app_get(struct bt_mesh_model *model,
2643*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2644*042d53a7SEvalZero struct os_mbuf *buf)
2645*042d53a7SEvalZero {
2646*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + KEY_LIST_LEN + 4);
2647*042d53a7SEvalZero struct bt_mesh_model *mod;
2648*042d53a7SEvalZero struct bt_mesh_elem *elem;
2649*042d53a7SEvalZero u8_t *mod_id, status;
2650*042d53a7SEvalZero u16_t elem_addr;
2651*042d53a7SEvalZero bool vnd;
2652*042d53a7SEvalZero
2653*042d53a7SEvalZero elem_addr = net_buf_simple_pull_le16(buf);
2654*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
2655*042d53a7SEvalZero BT_WARN("Prohibited element address");
2656*042d53a7SEvalZero goto done;
2657*042d53a7SEvalZero }
2658*042d53a7SEvalZero
2659*042d53a7SEvalZero mod_id = buf->om_data;
2660*042d53a7SEvalZero
2661*042d53a7SEvalZero BT_DBG("elem_addr 0x%04x", elem_addr);
2662*042d53a7SEvalZero
2663*042d53a7SEvalZero elem = bt_mesh_elem_find(elem_addr);
2664*042d53a7SEvalZero if (!elem) {
2665*042d53a7SEvalZero mod = NULL;
2666*042d53a7SEvalZero vnd = (buf->om_len == 4);
2667*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
2668*042d53a7SEvalZero goto send_list;
2669*042d53a7SEvalZero }
2670*042d53a7SEvalZero
2671*042d53a7SEvalZero mod = get_model(elem, buf, &vnd);
2672*042d53a7SEvalZero if (!mod) {
2673*042d53a7SEvalZero status = STATUS_INVALID_MODEL;
2674*042d53a7SEvalZero goto send_list;
2675*042d53a7SEvalZero }
2676*042d53a7SEvalZero
2677*042d53a7SEvalZero status = STATUS_SUCCESS;
2678*042d53a7SEvalZero
2679*042d53a7SEvalZero send_list:
2680*042d53a7SEvalZero if (vnd) {
2681*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_VND_MOD_APP_LIST);
2682*042d53a7SEvalZero } else {
2683*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_SIG_MOD_APP_LIST);
2684*042d53a7SEvalZero }
2685*042d53a7SEvalZero
2686*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
2687*042d53a7SEvalZero net_buf_simple_add_le16(msg, elem_addr);
2688*042d53a7SEvalZero
2689*042d53a7SEvalZero if (vnd) {
2690*042d53a7SEvalZero net_buf_simple_add_mem(msg, mod_id, 4);
2691*042d53a7SEvalZero } else {
2692*042d53a7SEvalZero net_buf_simple_add_mem(msg, mod_id, 2);
2693*042d53a7SEvalZero }
2694*042d53a7SEvalZero
2695*042d53a7SEvalZero if (mod) {
2696*042d53a7SEvalZero int i;
2697*042d53a7SEvalZero
2698*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
2699*042d53a7SEvalZero if (mod->keys[i] != BT_MESH_KEY_UNUSED) {
2700*042d53a7SEvalZero net_buf_simple_add_le16(msg, mod->keys[i]);
2701*042d53a7SEvalZero }
2702*042d53a7SEvalZero }
2703*042d53a7SEvalZero }
2704*042d53a7SEvalZero
2705*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2706*042d53a7SEvalZero BT_ERR("Unable to send Model Application List message");
2707*042d53a7SEvalZero }
2708*042d53a7SEvalZero
2709*042d53a7SEvalZero done:
2710*042d53a7SEvalZero os_mbuf_free_chain(msg);
2711*042d53a7SEvalZero }
2712*042d53a7SEvalZero
node_reset(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2713*042d53a7SEvalZero static void node_reset(struct bt_mesh_model *model,
2714*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2715*042d53a7SEvalZero struct os_mbuf *buf)
2716*042d53a7SEvalZero {
2717*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2718*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
2719*042d53a7SEvalZero
2720*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
2721*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
2722*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
2723*042d53a7SEvalZero
2724*042d53a7SEvalZero
2725*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_NODE_RESET_STATUS);
2726*042d53a7SEvalZero
2727*042d53a7SEvalZero /* Send the response first since we wont have any keys left to
2728*042d53a7SEvalZero * send it later.
2729*042d53a7SEvalZero */
2730*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2731*042d53a7SEvalZero BT_ERR("Unable to send Node Reset Status");
2732*042d53a7SEvalZero }
2733*042d53a7SEvalZero
2734*042d53a7SEvalZero bt_mesh_reset();
2735*042d53a7SEvalZero os_mbuf_free_chain(msg);
2736*042d53a7SEvalZero }
2737*042d53a7SEvalZero
send_friend_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx)2738*042d53a7SEvalZero static void send_friend_status(struct bt_mesh_model *model,
2739*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx)
2740*042d53a7SEvalZero {
2741*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2742*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
2743*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
2744*042d53a7SEvalZero
2745*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_FRIEND_STATUS);
2746*042d53a7SEvalZero net_buf_simple_add_u8(msg, cfg->frnd);
2747*042d53a7SEvalZero
2748*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2749*042d53a7SEvalZero BT_ERR("Unable to send Friend Status");
2750*042d53a7SEvalZero }
2751*042d53a7SEvalZero os_mbuf_free_chain(msg);
2752*042d53a7SEvalZero }
2753*042d53a7SEvalZero
friend_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2754*042d53a7SEvalZero static void friend_get(struct bt_mesh_model *model,
2755*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2756*042d53a7SEvalZero struct os_mbuf *buf)
2757*042d53a7SEvalZero {
2758*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
2759*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
2760*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
2761*042d53a7SEvalZero
2762*042d53a7SEvalZero send_friend_status(model, ctx);
2763*042d53a7SEvalZero }
2764*042d53a7SEvalZero
friend_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2765*042d53a7SEvalZero static void friend_set(struct bt_mesh_model *model,
2766*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2767*042d53a7SEvalZero struct os_mbuf *buf)
2768*042d53a7SEvalZero {
2769*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
2770*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2771*042d53a7SEvalZero
2772*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
2773*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
2774*042d53a7SEvalZero bt_hex(buf->om_data, buf->om_len));
2775*042d53a7SEvalZero
2776*042d53a7SEvalZero if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) {
2777*042d53a7SEvalZero BT_WARN("Invalid Friend value 0x%02x", buf->om_data[0]);
2778*042d53a7SEvalZero return;
2779*042d53a7SEvalZero }
2780*042d53a7SEvalZero
2781*042d53a7SEvalZero if (!cfg) {
2782*042d53a7SEvalZero BT_WARN("No Configuration Server context available");
2783*042d53a7SEvalZero goto send_status;
2784*042d53a7SEvalZero }
2785*042d53a7SEvalZero
2786*042d53a7SEvalZero BT_DBG("Friend 0x%02x -> 0x%02x", cfg->frnd, buf->om_data[0]);
2787*042d53a7SEvalZero
2788*042d53a7SEvalZero if (cfg->frnd == buf->om_data[0]) {
2789*042d53a7SEvalZero goto send_status;
2790*042d53a7SEvalZero }
2791*042d53a7SEvalZero
2792*042d53a7SEvalZero if (MYNEWT_VAL(BLE_MESH_FRIEND)) {
2793*042d53a7SEvalZero cfg->frnd = buf->om_data[0];
2794*042d53a7SEvalZero
2795*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
2796*042d53a7SEvalZero bt_mesh_store_cfg();
2797*042d53a7SEvalZero }
2798*042d53a7SEvalZero
2799*042d53a7SEvalZero if (cfg->frnd == BT_MESH_FRIEND_DISABLED) {
2800*042d53a7SEvalZero bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY);
2801*042d53a7SEvalZero }
2802*042d53a7SEvalZero }
2803*042d53a7SEvalZero
2804*042d53a7SEvalZero sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
2805*042d53a7SEvalZero if ((cfg->hb_pub.feat & BT_MESH_FEAT_FRIEND) && sub) {
2806*042d53a7SEvalZero hb_send(model);
2807*042d53a7SEvalZero }
2808*042d53a7SEvalZero
2809*042d53a7SEvalZero send_status:
2810*042d53a7SEvalZero send_friend_status(model, ctx);
2811*042d53a7SEvalZero }
2812*042d53a7SEvalZero
lpn_timeout_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2813*042d53a7SEvalZero static void lpn_timeout_get(struct bt_mesh_model *model,
2814*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2815*042d53a7SEvalZero struct os_mbuf *buf)
2816*042d53a7SEvalZero {
2817*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2818*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4);
2819*042d53a7SEvalZero struct bt_mesh_friend *frnd;
2820*042d53a7SEvalZero u16_t lpn_addr;
2821*042d53a7SEvalZero s32_t timeout;
2822*042d53a7SEvalZero
2823*042d53a7SEvalZero lpn_addr = net_buf_simple_pull_le16(buf);
2824*042d53a7SEvalZero
2825*042d53a7SEvalZero BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x lpn_addr 0x%02x",
2826*042d53a7SEvalZero ctx->net_idx, ctx->app_idx, ctx->addr, lpn_addr);
2827*042d53a7SEvalZero
2828*042d53a7SEvalZero /* check if it's the address of the Low Power Node? */
2829*042d53a7SEvalZero if (!BT_MESH_ADDR_IS_UNICAST(lpn_addr)) {
2830*042d53a7SEvalZero BT_WARN("Invalid LPNAddress; ignoring msg");
2831*042d53a7SEvalZero goto done;
2832*042d53a7SEvalZero }
2833*042d53a7SEvalZero
2834*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_LPN_TIMEOUT_STATUS);
2835*042d53a7SEvalZero net_buf_simple_add_le16(msg, lpn_addr);
2836*042d53a7SEvalZero
2837*042d53a7SEvalZero if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
2838*042d53a7SEvalZero timeout = 0;
2839*042d53a7SEvalZero goto send_rsp;
2840*042d53a7SEvalZero }
2841*042d53a7SEvalZero
2842*042d53a7SEvalZero frnd = bt_mesh_friend_find(BT_MESH_KEY_ANY, lpn_addr, true, true);
2843*042d53a7SEvalZero if (!frnd) {
2844*042d53a7SEvalZero timeout = 0;
2845*042d53a7SEvalZero goto send_rsp;
2846*042d53a7SEvalZero }
2847*042d53a7SEvalZero
2848*042d53a7SEvalZero timeout = k_delayed_work_remaining_get(&frnd->timer) / 100;
2849*042d53a7SEvalZero
2850*042d53a7SEvalZero send_rsp:
2851*042d53a7SEvalZero net_buf_simple_add_u8(msg, timeout);
2852*042d53a7SEvalZero net_buf_simple_add_u8(msg, timeout >> 8);
2853*042d53a7SEvalZero net_buf_simple_add_u8(msg, timeout >> 16);
2854*042d53a7SEvalZero
2855*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2856*042d53a7SEvalZero BT_ERR("Unable to send LPN PollTimeout Status");
2857*042d53a7SEvalZero }
2858*042d53a7SEvalZero
2859*042d53a7SEvalZero done:
2860*042d53a7SEvalZero os_mbuf_free_chain(msg);
2861*042d53a7SEvalZero }
2862*042d53a7SEvalZero
send_krp_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,u16_t idx,u8_t phase,u8_t status)2863*042d53a7SEvalZero static void send_krp_status(struct bt_mesh_model *model,
2864*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
2865*042d53a7SEvalZero u16_t idx, u8_t phase, u8_t status)
2866*042d53a7SEvalZero {
2867*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
2868*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
2869*042d53a7SEvalZero
2870*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_KRP_STATUS);
2871*042d53a7SEvalZero
2872*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
2873*042d53a7SEvalZero net_buf_simple_add_le16(msg, idx);
2874*042d53a7SEvalZero net_buf_simple_add_u8(msg, phase);
2875*042d53a7SEvalZero
2876*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
2877*042d53a7SEvalZero BT_ERR("Unable to send Key Refresh State Status");
2878*042d53a7SEvalZero }
2879*042d53a7SEvalZero
2880*042d53a7SEvalZero os_mbuf_free_chain(msg);
2881*042d53a7SEvalZero }
2882*042d53a7SEvalZero
krp_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2883*042d53a7SEvalZero static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
2884*042d53a7SEvalZero struct os_mbuf *buf)
2885*042d53a7SEvalZero {
2886*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2887*042d53a7SEvalZero u16_t idx;
2888*042d53a7SEvalZero
2889*042d53a7SEvalZero idx = net_buf_simple_pull_le16(buf);
2890*042d53a7SEvalZero if (idx > 0xfff) {
2891*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
2892*042d53a7SEvalZero return;
2893*042d53a7SEvalZero }
2894*042d53a7SEvalZero
2895*042d53a7SEvalZero BT_DBG("idx 0x%04x", idx);
2896*042d53a7SEvalZero
2897*042d53a7SEvalZero sub = bt_mesh_subnet_get(idx);
2898*042d53a7SEvalZero if (!sub) {
2899*042d53a7SEvalZero send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY);
2900*042d53a7SEvalZero } else {
2901*042d53a7SEvalZero send_krp_status(model, ctx, idx, sub->kr_phase,
2902*042d53a7SEvalZero STATUS_SUCCESS);
2903*042d53a7SEvalZero }
2904*042d53a7SEvalZero }
2905*042d53a7SEvalZero
krp_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)2906*042d53a7SEvalZero static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
2907*042d53a7SEvalZero struct os_mbuf *buf)
2908*042d53a7SEvalZero {
2909*042d53a7SEvalZero struct bt_mesh_subnet *sub;
2910*042d53a7SEvalZero u8_t phase;
2911*042d53a7SEvalZero u16_t idx;
2912*042d53a7SEvalZero
2913*042d53a7SEvalZero idx = net_buf_simple_pull_le16(buf);
2914*042d53a7SEvalZero phase = net_buf_simple_pull_u8(buf);
2915*042d53a7SEvalZero
2916*042d53a7SEvalZero if (idx > 0xfff) {
2917*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
2918*042d53a7SEvalZero return;
2919*042d53a7SEvalZero }
2920*042d53a7SEvalZero
2921*042d53a7SEvalZero BT_DBG("idx 0x%04x transition 0x%02x", idx, phase);
2922*042d53a7SEvalZero
2923*042d53a7SEvalZero sub = bt_mesh_subnet_get(idx);
2924*042d53a7SEvalZero if (!sub) {
2925*042d53a7SEvalZero send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY);
2926*042d53a7SEvalZero return;
2927*042d53a7SEvalZero }
2928*042d53a7SEvalZero
2929*042d53a7SEvalZero BT_DBG("%u -> %u", sub->kr_phase, phase);
2930*042d53a7SEvalZero
2931*042d53a7SEvalZero if (phase < BT_MESH_KR_PHASE_2 || phase > BT_MESH_KR_PHASE_3 ||
2932*042d53a7SEvalZero (sub->kr_phase == BT_MESH_KR_NORMAL &&
2933*042d53a7SEvalZero phase == BT_MESH_KR_PHASE_2)) {
2934*042d53a7SEvalZero BT_WARN("Prohibited transition %u -> %u", sub->kr_phase, phase);
2935*042d53a7SEvalZero return;
2936*042d53a7SEvalZero }
2937*042d53a7SEvalZero
2938*042d53a7SEvalZero if (sub->kr_phase == BT_MESH_KR_PHASE_1 &&
2939*042d53a7SEvalZero phase == BT_MESH_KR_PHASE_2) {
2940*042d53a7SEvalZero sub->kr_phase = BT_MESH_KR_PHASE_2;
2941*042d53a7SEvalZero sub->kr_flag = 1;
2942*042d53a7SEvalZero bt_mesh_net_beacon_update(sub);
2943*042d53a7SEvalZero } else if ((sub->kr_phase == BT_MESH_KR_PHASE_1 ||
2944*042d53a7SEvalZero sub->kr_phase == BT_MESH_KR_PHASE_2) &&
2945*042d53a7SEvalZero phase == BT_MESH_KR_PHASE_3) {
2946*042d53a7SEvalZero bt_mesh_net_revoke_keys(sub);
2947*042d53a7SEvalZero if ((MYNEWT_VAL(BLE_MESH_LOW_POWER)) ||
2948*042d53a7SEvalZero (MYNEWT_VAL(BLE_MESH_FRIEND))) {
2949*042d53a7SEvalZero friend_cred_refresh(ctx->net_idx);
2950*042d53a7SEvalZero }
2951*042d53a7SEvalZero sub->kr_phase = BT_MESH_KR_NORMAL;
2952*042d53a7SEvalZero sub->kr_flag = 0;
2953*042d53a7SEvalZero bt_mesh_net_beacon_update(sub);
2954*042d53a7SEvalZero }
2955*042d53a7SEvalZero
2956*042d53a7SEvalZero send_krp_status(model, ctx, idx, sub->kr_phase, STATUS_SUCCESS);
2957*042d53a7SEvalZero }
2958*042d53a7SEvalZero
hb_log(u16_t val)2959*042d53a7SEvalZero static u8_t hb_log(u16_t val)
2960*042d53a7SEvalZero {
2961*042d53a7SEvalZero if (!val) {
2962*042d53a7SEvalZero return 0x00;
2963*042d53a7SEvalZero } else if (val == 0xffff) {
2964*042d53a7SEvalZero return 0xff;
2965*042d53a7SEvalZero } else {
2966*042d53a7SEvalZero return 32 - __builtin_clz(val);
2967*042d53a7SEvalZero }
2968*042d53a7SEvalZero }
2969*042d53a7SEvalZero
hb_pub_count_log(u16_t val)2970*042d53a7SEvalZero static u8_t hb_pub_count_log(u16_t val)
2971*042d53a7SEvalZero {
2972*042d53a7SEvalZero if (!val) {
2973*042d53a7SEvalZero return 0x00;
2974*042d53a7SEvalZero } else if (val == 0x01) {
2975*042d53a7SEvalZero return 0x01;
2976*042d53a7SEvalZero } else if (val == 0xffff) {
2977*042d53a7SEvalZero return 0xff;
2978*042d53a7SEvalZero } else {
2979*042d53a7SEvalZero return 32 - __builtin_clz(val - 1) + 1;
2980*042d53a7SEvalZero }
2981*042d53a7SEvalZero }
2982*042d53a7SEvalZero
hb_pwr2(u8_t val,u8_t sub)2983*042d53a7SEvalZero static u16_t hb_pwr2(u8_t val, u8_t sub)
2984*042d53a7SEvalZero {
2985*042d53a7SEvalZero if (!val) {
2986*042d53a7SEvalZero return 0x0000;
2987*042d53a7SEvalZero } else if (val == 0xff || val == 0x11) {
2988*042d53a7SEvalZero return 0xffff;
2989*042d53a7SEvalZero } else {
2990*042d53a7SEvalZero return (1 << (val - sub));
2991*042d53a7SEvalZero }
2992*042d53a7SEvalZero }
2993*042d53a7SEvalZero
2994*042d53a7SEvalZero struct hb_pub_param {
2995*042d53a7SEvalZero u16_t dst;
2996*042d53a7SEvalZero u8_t count_log;
2997*042d53a7SEvalZero u8_t period_log;
2998*042d53a7SEvalZero u8_t ttl;
2999*042d53a7SEvalZero u16_t feat;
3000*042d53a7SEvalZero u16_t net_idx;
3001*042d53a7SEvalZero } __packed;
3002*042d53a7SEvalZero
hb_pub_send_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,u8_t status,struct hb_pub_param * orig_msg)3003*042d53a7SEvalZero static void hb_pub_send_status(struct bt_mesh_model *model,
3004*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx, u8_t status,
3005*042d53a7SEvalZero struct hb_pub_param *orig_msg)
3006*042d53a7SEvalZero {
3007*042d53a7SEvalZero /* Needed size: opcode (1 byte) + msg + MIC */
3008*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(1 + 10 + 4);
3009*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
3010*042d53a7SEvalZero
3011*042d53a7SEvalZero BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status);
3012*042d53a7SEvalZero
3013*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_HEARTBEAT_PUB_STATUS);
3014*042d53a7SEvalZero
3015*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
3016*042d53a7SEvalZero
3017*042d53a7SEvalZero if (orig_msg) {
3018*042d53a7SEvalZero memcpy(net_buf_simple_add(msg, sizeof(*orig_msg)), orig_msg,
3019*042d53a7SEvalZero sizeof(*orig_msg));
3020*042d53a7SEvalZero goto send;
3021*042d53a7SEvalZero }
3022*042d53a7SEvalZero
3023*042d53a7SEvalZero net_buf_simple_add_le16(msg, cfg->hb_pub.dst);
3024*042d53a7SEvalZero net_buf_simple_add_u8(msg, hb_pub_count_log(cfg->hb_pub.count));
3025*042d53a7SEvalZero net_buf_simple_add_u8(msg, cfg->hb_pub.period);
3026*042d53a7SEvalZero net_buf_simple_add_u8(msg, cfg->hb_pub.ttl);
3027*042d53a7SEvalZero net_buf_simple_add_le16(msg, cfg->hb_pub.feat);
3028*042d53a7SEvalZero net_buf_simple_add_le16(msg, cfg->hb_pub.net_idx);
3029*042d53a7SEvalZero
3030*042d53a7SEvalZero send:
3031*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
3032*042d53a7SEvalZero BT_ERR("Unable to send Heartbeat Publication Status");
3033*042d53a7SEvalZero }
3034*042d53a7SEvalZero
3035*042d53a7SEvalZero os_mbuf_free_chain(msg);
3036*042d53a7SEvalZero }
3037*042d53a7SEvalZero
heartbeat_pub_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)3038*042d53a7SEvalZero static void heartbeat_pub_get(struct bt_mesh_model *model,
3039*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
3040*042d53a7SEvalZero struct os_mbuf *buf)
3041*042d53a7SEvalZero {
3042*042d53a7SEvalZero BT_DBG("src 0x%04x", ctx->addr);
3043*042d53a7SEvalZero
3044*042d53a7SEvalZero hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL);
3045*042d53a7SEvalZero }
3046*042d53a7SEvalZero
heartbeat_pub_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)3047*042d53a7SEvalZero static void heartbeat_pub_set(struct bt_mesh_model *model,
3048*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
3049*042d53a7SEvalZero struct os_mbuf *buf)
3050*042d53a7SEvalZero {
3051*042d53a7SEvalZero struct hb_pub_param *param = (void *)buf->om_data;
3052*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
3053*042d53a7SEvalZero u16_t dst, feat, idx;
3054*042d53a7SEvalZero u8_t status;
3055*042d53a7SEvalZero
3056*042d53a7SEvalZero BT_DBG("src 0x%04x", ctx->addr);
3057*042d53a7SEvalZero
3058*042d53a7SEvalZero dst = sys_le16_to_cpu(param->dst);
3059*042d53a7SEvalZero /* All other address types but virtual are valid */
3060*042d53a7SEvalZero if (BT_MESH_ADDR_IS_VIRTUAL(dst)) {
3061*042d53a7SEvalZero status = STATUS_INVALID_ADDRESS;
3062*042d53a7SEvalZero goto failed;
3063*042d53a7SEvalZero }
3064*042d53a7SEvalZero
3065*042d53a7SEvalZero if (param->count_log > 0x11 && param->count_log != 0xff) {
3066*042d53a7SEvalZero status = STATUS_CANNOT_SET;
3067*042d53a7SEvalZero goto failed;
3068*042d53a7SEvalZero }
3069*042d53a7SEvalZero
3070*042d53a7SEvalZero if (param->period_log > 0x10) {
3071*042d53a7SEvalZero status = STATUS_CANNOT_SET;
3072*042d53a7SEvalZero goto failed;
3073*042d53a7SEvalZero }
3074*042d53a7SEvalZero
3075*042d53a7SEvalZero if (param->ttl > BT_MESH_TTL_MAX && param->ttl != BT_MESH_TTL_DEFAULT) {
3076*042d53a7SEvalZero BT_ERR("Invalid TTL value 0x%02x", param->ttl);
3077*042d53a7SEvalZero return;
3078*042d53a7SEvalZero }
3079*042d53a7SEvalZero
3080*042d53a7SEvalZero feat = sys_le16_to_cpu(param->feat);
3081*042d53a7SEvalZero
3082*042d53a7SEvalZero idx = sys_le16_to_cpu(param->net_idx);
3083*042d53a7SEvalZero if (idx > 0xfff) {
3084*042d53a7SEvalZero BT_ERR("Invalid NetKeyIndex 0x%04x", idx);
3085*042d53a7SEvalZero return;
3086*042d53a7SEvalZero }
3087*042d53a7SEvalZero
3088*042d53a7SEvalZero if (!bt_mesh_subnet_get(idx)) {
3089*042d53a7SEvalZero status = STATUS_INVALID_NETKEY;
3090*042d53a7SEvalZero goto failed;
3091*042d53a7SEvalZero }
3092*042d53a7SEvalZero
3093*042d53a7SEvalZero cfg->hb_pub.dst = dst;
3094*042d53a7SEvalZero cfg->hb_pub.period = param->period_log;
3095*042d53a7SEvalZero cfg->hb_pub.feat = feat & BT_MESH_FEAT_SUPPORTED;
3096*042d53a7SEvalZero cfg->hb_pub.net_idx = idx;
3097*042d53a7SEvalZero
3098*042d53a7SEvalZero if (dst == BT_MESH_ADDR_UNASSIGNED) {
3099*042d53a7SEvalZero hb_pub_disable(cfg);
3100*042d53a7SEvalZero } else {
3101*042d53a7SEvalZero /* 2^(n-1) */
3102*042d53a7SEvalZero cfg->hb_pub.count = hb_pwr2(param->count_log, 1);
3103*042d53a7SEvalZero cfg->hb_pub.ttl = param->ttl;
3104*042d53a7SEvalZero
3105*042d53a7SEvalZero BT_DBG("period %u ms", hb_pwr2(param->period_log, 1) * 1000);
3106*042d53a7SEvalZero
3107*042d53a7SEvalZero /* The first Heartbeat message shall be published as soon
3108*042d53a7SEvalZero * as possible after the Heartbeat Publication Period state
3109*042d53a7SEvalZero * has been configured for periodic publishing.
3110*042d53a7SEvalZero */
3111*042d53a7SEvalZero if (param->period_log && param->count_log) {
3112*042d53a7SEvalZero k_work_submit(&cfg->hb_pub.timer.work);
3113*042d53a7SEvalZero } else {
3114*042d53a7SEvalZero k_delayed_work_cancel(&cfg->hb_pub.timer);
3115*042d53a7SEvalZero }
3116*042d53a7SEvalZero }
3117*042d53a7SEvalZero
3118*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
3119*042d53a7SEvalZero bt_mesh_store_hb_pub();
3120*042d53a7SEvalZero }
3121*042d53a7SEvalZero
3122*042d53a7SEvalZero hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL);
3123*042d53a7SEvalZero
3124*042d53a7SEvalZero return;
3125*042d53a7SEvalZero
3126*042d53a7SEvalZero failed:
3127*042d53a7SEvalZero hb_pub_send_status(model, ctx, status, param);
3128*042d53a7SEvalZero }
3129*042d53a7SEvalZero
hb_sub_send_status(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,u8_t status)3130*042d53a7SEvalZero static void hb_sub_send_status(struct bt_mesh_model *model,
3131*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx, u8_t status)
3132*042d53a7SEvalZero {
3133*042d53a7SEvalZero /* Needed size: opcode (2 bytes) + msg + MIC */
3134*042d53a7SEvalZero struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
3135*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
3136*042d53a7SEvalZero u16_t period;
3137*042d53a7SEvalZero s64_t uptime;
3138*042d53a7SEvalZero
3139*042d53a7SEvalZero BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status);
3140*042d53a7SEvalZero
3141*042d53a7SEvalZero uptime = k_uptime_get();
3142*042d53a7SEvalZero if (uptime > cfg->hb_sub.expiry) {
3143*042d53a7SEvalZero period = 0;
3144*042d53a7SEvalZero } else {
3145*042d53a7SEvalZero period = (cfg->hb_sub.expiry - uptime) / 1000;
3146*042d53a7SEvalZero }
3147*042d53a7SEvalZero
3148*042d53a7SEvalZero bt_mesh_model_msg_init(msg, OP_HEARTBEAT_SUB_STATUS);
3149*042d53a7SEvalZero
3150*042d53a7SEvalZero net_buf_simple_add_u8(msg, status);
3151*042d53a7SEvalZero
3152*042d53a7SEvalZero net_buf_simple_add_le16(msg, cfg->hb_sub.src);
3153*042d53a7SEvalZero net_buf_simple_add_le16(msg, cfg->hb_sub.dst);
3154*042d53a7SEvalZero
3155*042d53a7SEvalZero net_buf_simple_add_u8(msg, hb_log(period));
3156*042d53a7SEvalZero net_buf_simple_add_u8(msg, hb_log(cfg->hb_sub.count));
3157*042d53a7SEvalZero net_buf_simple_add_u8(msg, cfg->hb_sub.min_hops);
3158*042d53a7SEvalZero net_buf_simple_add_u8(msg, cfg->hb_sub.max_hops);
3159*042d53a7SEvalZero
3160*042d53a7SEvalZero
3161*042d53a7SEvalZero if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
3162*042d53a7SEvalZero BT_ERR("Unable to send Heartbeat Subscription Status");
3163*042d53a7SEvalZero }
3164*042d53a7SEvalZero
3165*042d53a7SEvalZero os_mbuf_free_chain(msg);
3166*042d53a7SEvalZero }
3167*042d53a7SEvalZero
heartbeat_sub_get(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)3168*042d53a7SEvalZero static void heartbeat_sub_get(struct bt_mesh_model *model,
3169*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
3170*042d53a7SEvalZero struct os_mbuf *buf)
3171*042d53a7SEvalZero {
3172*042d53a7SEvalZero BT_DBG("src 0x%04x", ctx->addr);
3173*042d53a7SEvalZero
3174*042d53a7SEvalZero hb_sub_send_status(model, ctx, STATUS_SUCCESS);
3175*042d53a7SEvalZero }
3176*042d53a7SEvalZero
heartbeat_sub_set(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct os_mbuf * buf)3177*042d53a7SEvalZero static void heartbeat_sub_set(struct bt_mesh_model *model,
3178*042d53a7SEvalZero struct bt_mesh_msg_ctx *ctx,
3179*042d53a7SEvalZero struct os_mbuf *buf)
3180*042d53a7SEvalZero {
3181*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
3182*042d53a7SEvalZero u16_t sub_src, sub_dst;
3183*042d53a7SEvalZero u8_t sub_period;
3184*042d53a7SEvalZero s32_t period_ms;
3185*042d53a7SEvalZero
3186*042d53a7SEvalZero BT_DBG("src 0x%04x", ctx->addr);
3187*042d53a7SEvalZero
3188*042d53a7SEvalZero sub_src = net_buf_simple_pull_le16(buf);
3189*042d53a7SEvalZero sub_dst = net_buf_simple_pull_le16(buf);
3190*042d53a7SEvalZero sub_period = net_buf_simple_pull_u8(buf);
3191*042d53a7SEvalZero
3192*042d53a7SEvalZero BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x",
3193*042d53a7SEvalZero sub_src, sub_dst, sub_period);
3194*042d53a7SEvalZero
3195*042d53a7SEvalZero if (sub_src != BT_MESH_ADDR_UNASSIGNED &&
3196*042d53a7SEvalZero !BT_MESH_ADDR_IS_UNICAST(sub_src)) {
3197*042d53a7SEvalZero BT_WARN("Prohibited source address");
3198*042d53a7SEvalZero return;
3199*042d53a7SEvalZero }
3200*042d53a7SEvalZero
3201*042d53a7SEvalZero if (BT_MESH_ADDR_IS_VIRTUAL(sub_dst) || BT_MESH_ADDR_IS_RFU(sub_dst) ||
3202*042d53a7SEvalZero (BT_MESH_ADDR_IS_UNICAST(sub_dst) &&
3203*042d53a7SEvalZero sub_dst != bt_mesh_primary_addr())) {
3204*042d53a7SEvalZero BT_WARN("Prohibited destination address");
3205*042d53a7SEvalZero return;
3206*042d53a7SEvalZero }
3207*042d53a7SEvalZero
3208*042d53a7SEvalZero if (sub_period > 0x11) {
3209*042d53a7SEvalZero BT_WARN("Prohibited subscription period 0x%02x", sub_period);
3210*042d53a7SEvalZero return;
3211*042d53a7SEvalZero }
3212*042d53a7SEvalZero
3213*042d53a7SEvalZero if (sub_src == BT_MESH_ADDR_UNASSIGNED ||
3214*042d53a7SEvalZero sub_dst == BT_MESH_ADDR_UNASSIGNED ||
3215*042d53a7SEvalZero sub_period == 0x00) {
3216*042d53a7SEvalZero /* Only an explicit address change to unassigned should
3217*042d53a7SEvalZero * trigger clearing of the values according to
3218*042d53a7SEvalZero * MESH/NODE/CFG/HBS/BV-02-C.
3219*042d53a7SEvalZero */
3220*042d53a7SEvalZero if (sub_src == BT_MESH_ADDR_UNASSIGNED ||
3221*042d53a7SEvalZero sub_dst == BT_MESH_ADDR_UNASSIGNED) {
3222*042d53a7SEvalZero cfg->hb_sub.src = BT_MESH_ADDR_UNASSIGNED;
3223*042d53a7SEvalZero cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED;
3224*042d53a7SEvalZero cfg->hb_sub.min_hops = BT_MESH_TTL_MAX;
3225*042d53a7SEvalZero cfg->hb_sub.max_hops = 0;
3226*042d53a7SEvalZero cfg->hb_sub.count = 0;
3227*042d53a7SEvalZero }
3228*042d53a7SEvalZero
3229*042d53a7SEvalZero period_ms = 0;
3230*042d53a7SEvalZero } else {
3231*042d53a7SEvalZero cfg->hb_sub.src = sub_src;
3232*042d53a7SEvalZero cfg->hb_sub.dst = sub_dst;
3233*042d53a7SEvalZero cfg->hb_sub.min_hops = BT_MESH_TTL_MAX;
3234*042d53a7SEvalZero cfg->hb_sub.max_hops = 0;
3235*042d53a7SEvalZero cfg->hb_sub.count = 0;
3236*042d53a7SEvalZero period_ms = hb_pwr2(sub_period, 1) * 1000;
3237*042d53a7SEvalZero }
3238*042d53a7SEvalZero
3239*042d53a7SEvalZero /* Let the transport layer know it needs to handle this address */
3240*042d53a7SEvalZero bt_mesh_set_hb_sub_dst(cfg->hb_sub.dst);
3241*042d53a7SEvalZero
3242*042d53a7SEvalZero BT_DBG("period_ms %u", period_ms);
3243*042d53a7SEvalZero
3244*042d53a7SEvalZero if (period_ms) {
3245*042d53a7SEvalZero cfg->hb_sub.expiry = k_uptime_get() + period_ms;
3246*042d53a7SEvalZero } else {
3247*042d53a7SEvalZero cfg->hb_sub.expiry = 0;
3248*042d53a7SEvalZero }
3249*042d53a7SEvalZero
3250*042d53a7SEvalZero hb_sub_send_status(model, ctx, STATUS_SUCCESS);
3251*042d53a7SEvalZero
3252*042d53a7SEvalZero /* MESH/NODE/CFG/HBS/BV-01-C expects the MinHops to be 0x7f after
3253*042d53a7SEvalZero * disabling subscription, but 0x00 for subsequent Get requests.
3254*042d53a7SEvalZero */
3255*042d53a7SEvalZero if (!period_ms) {
3256*042d53a7SEvalZero cfg->hb_sub.min_hops = 0;
3257*042d53a7SEvalZero }
3258*042d53a7SEvalZero }
3259*042d53a7SEvalZero
3260*042d53a7SEvalZero const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = {
3261*042d53a7SEvalZero { OP_DEV_COMP_DATA_GET, 1, dev_comp_data_get },
3262*042d53a7SEvalZero { OP_APP_KEY_ADD, 19, app_key_add },
3263*042d53a7SEvalZero { OP_APP_KEY_UPDATE, 19, app_key_update },
3264*042d53a7SEvalZero { OP_APP_KEY_DEL, 3, app_key_del },
3265*042d53a7SEvalZero { OP_APP_KEY_GET, 2, app_key_get },
3266*042d53a7SEvalZero { OP_BEACON_GET, 0, beacon_get },
3267*042d53a7SEvalZero { OP_BEACON_SET, 1, beacon_set },
3268*042d53a7SEvalZero { OP_DEFAULT_TTL_GET, 0, default_ttl_get },
3269*042d53a7SEvalZero { OP_DEFAULT_TTL_SET, 1, default_ttl_set },
3270*042d53a7SEvalZero { OP_GATT_PROXY_GET, 0, gatt_proxy_get },
3271*042d53a7SEvalZero { OP_GATT_PROXY_SET, 1, gatt_proxy_set },
3272*042d53a7SEvalZero { OP_NET_TRANSMIT_GET, 0, net_transmit_get },
3273*042d53a7SEvalZero { OP_NET_TRANSMIT_SET, 1, net_transmit_set },
3274*042d53a7SEvalZero { OP_RELAY_GET, 0, relay_get },
3275*042d53a7SEvalZero { OP_RELAY_SET, 2, relay_set },
3276*042d53a7SEvalZero { OP_MOD_PUB_GET, 4, mod_pub_get },
3277*042d53a7SEvalZero { OP_MOD_PUB_SET, 11, mod_pub_set },
3278*042d53a7SEvalZero { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set },
3279*042d53a7SEvalZero { OP_MOD_SUB_ADD, 6, mod_sub_add },
3280*042d53a7SEvalZero { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add },
3281*042d53a7SEvalZero { OP_MOD_SUB_DEL, 6, mod_sub_del },
3282*042d53a7SEvalZero { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del },
3283*042d53a7SEvalZero { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite },
3284*042d53a7SEvalZero { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite },
3285*042d53a7SEvalZero { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all },
3286*042d53a7SEvalZero { OP_MOD_SUB_GET, 4, mod_sub_get },
3287*042d53a7SEvalZero { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd },
3288*042d53a7SEvalZero { OP_NET_KEY_ADD, 18, net_key_add },
3289*042d53a7SEvalZero { OP_NET_KEY_UPDATE, 18, net_key_update },
3290*042d53a7SEvalZero { OP_NET_KEY_DEL, 2, net_key_del },
3291*042d53a7SEvalZero { OP_NET_KEY_GET, 0, net_key_get },
3292*042d53a7SEvalZero { OP_NODE_IDENTITY_GET, 2, node_identity_get },
3293*042d53a7SEvalZero { OP_NODE_IDENTITY_SET, 3, node_identity_set },
3294*042d53a7SEvalZero { OP_MOD_APP_BIND, 6, mod_app_bind },
3295*042d53a7SEvalZero { OP_MOD_APP_UNBIND, 6, mod_app_unbind },
3296*042d53a7SEvalZero { OP_SIG_MOD_APP_GET, 4, mod_app_get },
3297*042d53a7SEvalZero { OP_VND_MOD_APP_GET, 6, mod_app_get },
3298*042d53a7SEvalZero { OP_NODE_RESET, 0, node_reset },
3299*042d53a7SEvalZero { OP_FRIEND_GET, 0, friend_get },
3300*042d53a7SEvalZero { OP_FRIEND_SET, 1, friend_set },
3301*042d53a7SEvalZero { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get },
3302*042d53a7SEvalZero { OP_KRP_GET, 2, krp_get },
3303*042d53a7SEvalZero { OP_KRP_SET, 3, krp_set },
3304*042d53a7SEvalZero { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get },
3305*042d53a7SEvalZero { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set },
3306*042d53a7SEvalZero { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get },
3307*042d53a7SEvalZero { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set },
3308*042d53a7SEvalZero BT_MESH_MODEL_OP_END,
3309*042d53a7SEvalZero };
3310*042d53a7SEvalZero
hb_publish(struct ble_npl_event * work)3311*042d53a7SEvalZero static void hb_publish(struct ble_npl_event *work)
3312*042d53a7SEvalZero {
3313*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = ble_npl_event_get_arg(work);
3314*042d53a7SEvalZero struct bt_mesh_model *model = cfg->model;
3315*042d53a7SEvalZero struct bt_mesh_subnet *sub;
3316*042d53a7SEvalZero u16_t period_ms;
3317*042d53a7SEvalZero
3318*042d53a7SEvalZero BT_DBG("hb_pub.count: %u", cfg->hb_pub.count);
3319*042d53a7SEvalZero
3320*042d53a7SEvalZero sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
3321*042d53a7SEvalZero if (!sub) {
3322*042d53a7SEvalZero BT_ERR("No matching subnet for idx 0x%02x",
3323*042d53a7SEvalZero cfg->hb_pub.net_idx);
3324*042d53a7SEvalZero cfg->hb_pub.dst = BT_MESH_ADDR_UNASSIGNED;
3325*042d53a7SEvalZero return;
3326*042d53a7SEvalZero }
3327*042d53a7SEvalZero
3328*042d53a7SEvalZero if (cfg->hb_pub.count == 0) {
3329*042d53a7SEvalZero return;
3330*042d53a7SEvalZero }
3331*042d53a7SEvalZero
3332*042d53a7SEvalZero period_ms = hb_pwr2(cfg->hb_pub.period, 1) * 1000;
3333*042d53a7SEvalZero if (period_ms && cfg->hb_pub.count > 1) {
3334*042d53a7SEvalZero k_delayed_work_submit(&cfg->hb_pub.timer, period_ms);
3335*042d53a7SEvalZero }
3336*042d53a7SEvalZero
3337*042d53a7SEvalZero hb_send(model);
3338*042d53a7SEvalZero
3339*042d53a7SEvalZero if (cfg->hb_pub.count != 0xffff) {
3340*042d53a7SEvalZero cfg->hb_pub.count--;
3341*042d53a7SEvalZero }
3342*042d53a7SEvalZero }
3343*042d53a7SEvalZero
conf_is_valid(struct bt_mesh_cfg_srv * cfg)3344*042d53a7SEvalZero static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg)
3345*042d53a7SEvalZero {
3346*042d53a7SEvalZero if (cfg->relay > 0x02) {
3347*042d53a7SEvalZero return false;
3348*042d53a7SEvalZero }
3349*042d53a7SEvalZero
3350*042d53a7SEvalZero if (cfg->beacon > 0x01) {
3351*042d53a7SEvalZero return false;
3352*042d53a7SEvalZero }
3353*042d53a7SEvalZero
3354*042d53a7SEvalZero if (cfg->default_ttl > BT_MESH_TTL_MAX) {
3355*042d53a7SEvalZero return false;
3356*042d53a7SEvalZero }
3357*042d53a7SEvalZero
3358*042d53a7SEvalZero return true;
3359*042d53a7SEvalZero }
3360*042d53a7SEvalZero
bt_mesh_cfg_srv_init(struct bt_mesh_model * model,bool primary)3361*042d53a7SEvalZero int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary)
3362*042d53a7SEvalZero {
3363*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = model->user_data;
3364*042d53a7SEvalZero
3365*042d53a7SEvalZero if (!cfg) {
3366*042d53a7SEvalZero BT_ERR("No Configuration Server context provided");
3367*042d53a7SEvalZero return -EINVAL;
3368*042d53a7SEvalZero }
3369*042d53a7SEvalZero
3370*042d53a7SEvalZero if (!conf_is_valid(cfg)) {
3371*042d53a7SEvalZero BT_ERR("Invalid values in configuration");
3372*042d53a7SEvalZero return -EINVAL;
3373*042d53a7SEvalZero }
3374*042d53a7SEvalZero
3375*042d53a7SEvalZero /* Configuration Model security is device-key based */
3376*042d53a7SEvalZero model->keys[0] = BT_MESH_KEY_DEV;
3377*042d53a7SEvalZero
3378*042d53a7SEvalZero if (!(MYNEWT_VAL(BLE_MESH_RELAY))) {
3379*042d53a7SEvalZero cfg->relay = BT_MESH_RELAY_NOT_SUPPORTED;
3380*042d53a7SEvalZero }
3381*042d53a7SEvalZero
3382*042d53a7SEvalZero if (!(MYNEWT_VAL(BLE_MESH_FRIEND))) {
3383*042d53a7SEvalZero cfg->frnd = BT_MESH_FRIEND_NOT_SUPPORTED;
3384*042d53a7SEvalZero }
3385*042d53a7SEvalZero
3386*042d53a7SEvalZero if (!(MYNEWT_VAL(BLE_MESH_GATT_PROXY))) {
3387*042d53a7SEvalZero cfg->gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED;
3388*042d53a7SEvalZero }
3389*042d53a7SEvalZero
3390*042d53a7SEvalZero k_delayed_work_init(&cfg->hb_pub.timer, hb_publish);
3391*042d53a7SEvalZero k_delayed_work_add_arg(&cfg->hb_pub.timer, cfg);
3392*042d53a7SEvalZero cfg->hb_pub.net_idx = BT_MESH_KEY_UNUSED;
3393*042d53a7SEvalZero cfg->hb_sub.expiry = 0;
3394*042d53a7SEvalZero
3395*042d53a7SEvalZero cfg->model = model;
3396*042d53a7SEvalZero
3397*042d53a7SEvalZero conf = cfg;
3398*042d53a7SEvalZero
3399*042d53a7SEvalZero return 0;
3400*042d53a7SEvalZero }
3401*042d53a7SEvalZero
mod_reset(struct bt_mesh_model * mod,struct bt_mesh_elem * elem,bool vnd,bool primary,void * user_data)3402*042d53a7SEvalZero static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
3403*042d53a7SEvalZero bool vnd, bool primary, void *user_data)
3404*042d53a7SEvalZero {
3405*042d53a7SEvalZero /* Clear model state that isn't otherwise cleared. E.g. AppKey
3406*042d53a7SEvalZero * binding and model publication is cleared as a consequence
3407*042d53a7SEvalZero * of removing all app keys, however model subscription clearing
3408*042d53a7SEvalZero * must be taken care of here.
3409*042d53a7SEvalZero */
3410*042d53a7SEvalZero
3411*042d53a7SEvalZero mod_sub_list_clear(mod);
3412*042d53a7SEvalZero
3413*042d53a7SEvalZero if (IS_ENABLED(BT_SETTINGS)) {
3414*042d53a7SEvalZero bt_mesh_store_mod_sub(mod);
3415*042d53a7SEvalZero }
3416*042d53a7SEvalZero }
3417*042d53a7SEvalZero
bt_mesh_cfg_reset(void)3418*042d53a7SEvalZero void bt_mesh_cfg_reset(void)
3419*042d53a7SEvalZero {
3420*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = conf;
3421*042d53a7SEvalZero int i;
3422*042d53a7SEvalZero
3423*042d53a7SEvalZero if (!cfg) {
3424*042d53a7SEvalZero return;
3425*042d53a7SEvalZero }
3426*042d53a7SEvalZero
3427*042d53a7SEvalZero bt_mesh_set_hb_sub_dst(BT_MESH_ADDR_UNASSIGNED);
3428*042d53a7SEvalZero
3429*042d53a7SEvalZero cfg->hb_sub.src = BT_MESH_ADDR_UNASSIGNED;
3430*042d53a7SEvalZero cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED;
3431*042d53a7SEvalZero cfg->hb_sub.expiry = 0;
3432*042d53a7SEvalZero
3433*042d53a7SEvalZero /* Delete all net keys, which also takes care of all app keys which
3434*042d53a7SEvalZero * are associated with each net key.
3435*042d53a7SEvalZero */
3436*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
3437*042d53a7SEvalZero struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
3438*042d53a7SEvalZero
3439*042d53a7SEvalZero if (sub->net_idx != BT_MESH_KEY_UNUSED) {
3440*042d53a7SEvalZero bt_mesh_subnet_del(sub, true);
3441*042d53a7SEvalZero }
3442*042d53a7SEvalZero }
3443*042d53a7SEvalZero
3444*042d53a7SEvalZero bt_mesh_model_foreach(mod_reset, NULL);
3445*042d53a7SEvalZero
3446*042d53a7SEvalZero memset(labels, 0, sizeof(labels));
3447*042d53a7SEvalZero }
3448*042d53a7SEvalZero
bt_mesh_heartbeat(u16_t src,u16_t dst,u8_t hops,u16_t feat)3449*042d53a7SEvalZero void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat)
3450*042d53a7SEvalZero {
3451*042d53a7SEvalZero struct bt_mesh_cfg_srv *cfg = conf;
3452*042d53a7SEvalZero
3453*042d53a7SEvalZero if (!cfg) {
3454*042d53a7SEvalZero BT_WARN("No configuaration server context available");
3455*042d53a7SEvalZero return;
3456*042d53a7SEvalZero }
3457*042d53a7SEvalZero
3458*042d53a7SEvalZero if (src != cfg->hb_sub.src || dst != cfg->hb_sub.dst) {
3459*042d53a7SEvalZero BT_WARN("No subscription for received heartbeat");
3460*042d53a7SEvalZero return;
3461*042d53a7SEvalZero }
3462*042d53a7SEvalZero
3463*042d53a7SEvalZero if (k_uptime_get() > cfg->hb_sub.expiry) {
3464*042d53a7SEvalZero BT_WARN("Heartbeat subscription period expired");
3465*042d53a7SEvalZero return;
3466*042d53a7SEvalZero }
3467*042d53a7SEvalZero
3468*042d53a7SEvalZero cfg->hb_sub.min_hops = min(cfg->hb_sub.min_hops, hops);
3469*042d53a7SEvalZero cfg->hb_sub.max_hops = max(cfg->hb_sub.max_hops, hops);
3470*042d53a7SEvalZero
3471*042d53a7SEvalZero if (cfg->hb_sub.count < 0xffff) {
3472*042d53a7SEvalZero cfg->hb_sub.count++;
3473*042d53a7SEvalZero }
3474*042d53a7SEvalZero
3475*042d53a7SEvalZero BT_DBG("src 0x%04x dst 0x%04x hops %u min %u max %u count %u", src,
3476*042d53a7SEvalZero dst, hops, cfg->hb_sub.min_hops, cfg->hb_sub.max_hops,
3477*042d53a7SEvalZero cfg->hb_sub.count);
3478*042d53a7SEvalZero
3479*042d53a7SEvalZero if (cfg->hb_sub.func) {
3480*042d53a7SEvalZero cfg->hb_sub.func(hops, feat);
3481*042d53a7SEvalZero }
3482*042d53a7SEvalZero }
3483*042d53a7SEvalZero
bt_mesh_net_transmit_get(void)3484*042d53a7SEvalZero u8_t bt_mesh_net_transmit_get(void)
3485*042d53a7SEvalZero {
3486*042d53a7SEvalZero if (conf) {
3487*042d53a7SEvalZero return conf->net_transmit;
3488*042d53a7SEvalZero }
3489*042d53a7SEvalZero
3490*042d53a7SEvalZero return 0;
3491*042d53a7SEvalZero }
3492*042d53a7SEvalZero
bt_mesh_relay_get(void)3493*042d53a7SEvalZero u8_t bt_mesh_relay_get(void)
3494*042d53a7SEvalZero {
3495*042d53a7SEvalZero if (conf) {
3496*042d53a7SEvalZero return conf->relay;
3497*042d53a7SEvalZero }
3498*042d53a7SEvalZero
3499*042d53a7SEvalZero return BT_MESH_RELAY_NOT_SUPPORTED;
3500*042d53a7SEvalZero }
3501*042d53a7SEvalZero
bt_mesh_friend_get(void)3502*042d53a7SEvalZero u8_t bt_mesh_friend_get(void)
3503*042d53a7SEvalZero {
3504*042d53a7SEvalZero BT_DBG("conf %p conf->frnd 0x%02x", conf, conf->frnd);
3505*042d53a7SEvalZero
3506*042d53a7SEvalZero if (conf) {
3507*042d53a7SEvalZero return conf->frnd;
3508*042d53a7SEvalZero }
3509*042d53a7SEvalZero
3510*042d53a7SEvalZero return BT_MESH_FRIEND_NOT_SUPPORTED;
3511*042d53a7SEvalZero }
3512*042d53a7SEvalZero
bt_mesh_relay_retransmit_get(void)3513*042d53a7SEvalZero u8_t bt_mesh_relay_retransmit_get(void)
3514*042d53a7SEvalZero {
3515*042d53a7SEvalZero if (conf) {
3516*042d53a7SEvalZero return conf->relay_retransmit;
3517*042d53a7SEvalZero }
3518*042d53a7SEvalZero
3519*042d53a7SEvalZero return 0;
3520*042d53a7SEvalZero }
3521*042d53a7SEvalZero
bt_mesh_beacon_get(void)3522*042d53a7SEvalZero u8_t bt_mesh_beacon_get(void)
3523*042d53a7SEvalZero {
3524*042d53a7SEvalZero if (conf) {
3525*042d53a7SEvalZero return conf->beacon;
3526*042d53a7SEvalZero }
3527*042d53a7SEvalZero
3528*042d53a7SEvalZero return BT_MESH_BEACON_DISABLED;
3529*042d53a7SEvalZero }
3530*042d53a7SEvalZero
bt_mesh_gatt_proxy_get(void)3531*042d53a7SEvalZero u8_t bt_mesh_gatt_proxy_get(void)
3532*042d53a7SEvalZero {
3533*042d53a7SEvalZero if (conf) {
3534*042d53a7SEvalZero return conf->gatt_proxy;
3535*042d53a7SEvalZero }
3536*042d53a7SEvalZero
3537*042d53a7SEvalZero return BT_MESH_GATT_PROXY_NOT_SUPPORTED;
3538*042d53a7SEvalZero }
3539*042d53a7SEvalZero
bt_mesh_default_ttl_get(void)3540*042d53a7SEvalZero u8_t bt_mesh_default_ttl_get(void)
3541*042d53a7SEvalZero {
3542*042d53a7SEvalZero if (conf) {
3543*042d53a7SEvalZero return conf->default_ttl;
3544*042d53a7SEvalZero }
3545*042d53a7SEvalZero
3546*042d53a7SEvalZero return DEFAULT_TTL;
3547*042d53a7SEvalZero }
3548*042d53a7SEvalZero
bt_mesh_label_uuid_get(u16_t addr)3549*042d53a7SEvalZero u8_t *bt_mesh_label_uuid_get(u16_t addr)
3550*042d53a7SEvalZero {
3551*042d53a7SEvalZero int i;
3552*042d53a7SEvalZero
3553*042d53a7SEvalZero BT_DBG("addr 0x%04x", addr);
3554*042d53a7SEvalZero
3555*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(labels); i++) {
3556*042d53a7SEvalZero if (labels[i].addr == addr) {
3557*042d53a7SEvalZero BT_DBG("Found Label UUID for 0x%04x: %s", addr,
3558*042d53a7SEvalZero bt_hex(labels[i].uuid, 16));
3559*042d53a7SEvalZero return labels[i].uuid;
3560*042d53a7SEvalZero }
3561*042d53a7SEvalZero }
3562*042d53a7SEvalZero
3563*042d53a7SEvalZero BT_WARN("No matching Label UUID for 0x%04x", addr);
3564*042d53a7SEvalZero
3565*042d53a7SEvalZero return NULL;
3566*042d53a7SEvalZero }
3567*042d53a7SEvalZero
bt_mesh_hb_pub_get(void)3568*042d53a7SEvalZero struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void)
3569*042d53a7SEvalZero {
3570*042d53a7SEvalZero if (!conf) {
3571*042d53a7SEvalZero return NULL;
3572*042d53a7SEvalZero }
3573*042d53a7SEvalZero
3574*042d53a7SEvalZero return &conf->hb_pub;
3575*042d53a7SEvalZero }
3576*042d53a7SEvalZero
bt_mesh_cfg_get(void)3577*042d53a7SEvalZero struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void)
3578*042d53a7SEvalZero {
3579*042d53a7SEvalZero return conf;
3580*042d53a7SEvalZero }
3581*042d53a7SEvalZero
bt_mesh_subnet_del(struct bt_mesh_subnet * sub,bool store)3582*042d53a7SEvalZero void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store)
3583*042d53a7SEvalZero {
3584*042d53a7SEvalZero int i;
3585*042d53a7SEvalZero
3586*042d53a7SEvalZero BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store);
3587*042d53a7SEvalZero
3588*042d53a7SEvalZero if (conf && conf->hb_pub.net_idx == sub->net_idx) {
3589*042d53a7SEvalZero hb_pub_disable(conf);
3590*042d53a7SEvalZero
3591*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
3592*042d53a7SEvalZero bt_mesh_store_hb_pub();
3593*042d53a7SEvalZero }
3594*042d53a7SEvalZero }
3595*042d53a7SEvalZero
3596*042d53a7SEvalZero /* Delete any app keys bound to this NetKey index */
3597*042d53a7SEvalZero for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) {
3598*042d53a7SEvalZero struct bt_mesh_app_key *key = &bt_mesh.app_keys[i];
3599*042d53a7SEvalZero
3600*042d53a7SEvalZero if (key->net_idx == sub->net_idx) {
3601*042d53a7SEvalZero bt_mesh_app_key_del(key, store);
3602*042d53a7SEvalZero }
3603*042d53a7SEvalZero }
3604*042d53a7SEvalZero
3605*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
3606*042d53a7SEvalZero bt_mesh_friend_clear_net_idx(sub->net_idx);
3607*042d53a7SEvalZero }
3608*042d53a7SEvalZero
3609*042d53a7SEvalZero if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
3610*042d53a7SEvalZero bt_mesh_clear_subnet(sub);
3611*042d53a7SEvalZero }
3612*042d53a7SEvalZero
3613*042d53a7SEvalZero memset(sub, 0, sizeof(*sub));
3614*042d53a7SEvalZero sub->net_idx = BT_MESH_KEY_UNUSED;
3615*042d53a7SEvalZero }
3616