1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/mesh.h>
8 
9 #include "foundation.h"
10 #include "subnet.h"
11 #include "solicitation.h"
12 
13 #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(bt_mesh_sol_pdu_rpl_srv);
16 
sol_rpl_status_rsp(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,uint16_t range,uint8_t len)17 static void sol_rpl_status_rsp(struct bt_mesh_model *mod,
18 			       struct bt_mesh_msg_ctx *ctx,
19 			       uint16_t range,
20 			       uint8_t len)
21 {
22 	BT_MESH_MODEL_BUF_DEFINE(buf, OP_SOL_PDU_RPL_ITEM_STATUS, 2 + (len < 2 ? 0 : 1));
23 
24 	bt_mesh_model_msg_init(&buf, OP_SOL_PDU_RPL_ITEM_STATUS);
25 
26 	net_buf_simple_add_le16(&buf, range);
27 
28 	if (len >= 2) {
29 		net_buf_simple_add_u8(&buf, len);
30 	}
31 
32 	bt_mesh_model_send(mod, ctx, &buf, NULL, NULL);
33 }
34 
item_clear(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf,bool acked)35 static int item_clear(struct bt_mesh_model *mod,
36 		      struct bt_mesh_msg_ctx *ctx,
37 		      struct net_buf_simple *buf,
38 		      bool acked)
39 {
40 	uint16_t primary, range;
41 	uint8_t len = 0;
42 
43 	LOG_DBG("");
44 
45 	if (buf->len > 3) {
46 		return -EMSGSIZE;
47 	}
48 
49 	range = net_buf_simple_pull_le16(buf);
50 	primary = range >> 1;
51 
52 	LOG_DBG("Start address: 0x%02x, %d", primary, buf->len);
53 	if (range & BIT(0)) {
54 		if (buf->len == 0) {
55 			return -EMSGSIZE;
56 		}
57 
58 		len = net_buf_simple_pull_u8(buf);
59 
60 		if (len < 2) {
61 			return -EINVAL;
62 		}
63 	}
64 
65 	if ((primary + len)  > 0x8000 || primary == 0) {
66 		LOG_WRN("Range outside unicast address range or equal to 0");
67 		return -EINVAL;
68 	}
69 
70 	for (int i = 0; i < len || i == 0; i++) {
71 		bt_mesh_srpl_entry_clear(primary + i);
72 	}
73 
74 	if (acked) {
75 		sol_rpl_status_rsp(mod, ctx, range, len);
76 	}
77 
78 	return 0;
79 }
80 
handle_item_clear(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)81 static int handle_item_clear(struct bt_mesh_model *mod,
82 			    struct bt_mesh_msg_ctx *ctx,
83 			    struct net_buf_simple *buf)
84 {
85 	return item_clear(mod, ctx, buf, true);
86 }
87 
handle_item_clear_unacked(struct bt_mesh_model * mod,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)88 static int handle_item_clear_unacked(struct bt_mesh_model *mod,
89 				     struct bt_mesh_msg_ctx *ctx,
90 				     struct net_buf_simple *buf)
91 {
92 	return item_clear(mod, ctx, buf, false);
93 }
94 
95 const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_srv_op[] = {
96 	{ OP_SOL_PDU_RPL_ITEM_CLEAR, BT_MESH_LEN_MIN(2), handle_item_clear },
97 	{ OP_SOL_PDU_RPL_ITEM_CLEAR_UNACKED, BT_MESH_LEN_MIN(2), handle_item_clear_unacked },
98 
99 	BT_MESH_MODEL_OP_END
100 };
101 
sol_pdu_rpl_srv_init(struct bt_mesh_model * mod)102 static int sol_pdu_rpl_srv_init(struct bt_mesh_model *mod)
103 {
104 	if (!bt_mesh_model_in_primary(mod)) {
105 		LOG_ERR("Solicitation PDU RPL Configuration server not in primary element");
106 		return -EINVAL;
107 	}
108 
109 	return 0;
110 }
111 
112 const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_srv_cb = {
113 	.init = sol_pdu_rpl_srv_init,
114 };
115