xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/cfg_srv.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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