1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/mesh.h>
8 
9 #include "msg.h"
10 
11 #define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(bt_mesh_msg);
14 
bt_mesh_model_msg_init(struct net_buf_simple * msg,uint32_t opcode)15 void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode)
16 {
17 	net_buf_simple_init(msg, 0);
18 
19 	switch (BT_MESH_MODEL_OP_LEN(opcode)) {
20 	case 1:
21 		net_buf_simple_add_u8(msg, opcode);
22 		break;
23 	case 2:
24 		net_buf_simple_add_be16(msg, opcode);
25 		break;
26 	case 3:
27 		net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
28 		/* Using LE for the CID since the model layer is defined as
29 		 * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3
30 		 * will declare the opcode in this way.
31 		 */
32 		net_buf_simple_add_le16(msg, opcode & 0xffff);
33 		break;
34 	default:
35 		LOG_WRN("Unknown opcode format");
36 		break;
37 	}
38 }
39 
bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx * ack)40 void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack)
41 {
42 	ack->op = 0U;
43 	ack->user_data = NULL;
44 	ack->dst = BT_MESH_ADDR_UNASSIGNED;
45 }
46 
bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx * ack,uint32_t op,uint16_t dst,void * user_data)47 int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack,
48 				uint32_t op, uint16_t dst, void *user_data)
49 {
50 	if (ack->op) {
51 		LOG_WRN("Another synchronous operation pending");
52 		return -EBUSY;
53 	}
54 
55 	ack->op = op;
56 	ack->user_data = user_data;
57 	ack->dst = dst;
58 
59 	return 0;
60 }
61 
bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx * ack,k_timeout_t timeout)62 int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, k_timeout_t timeout)
63 {
64 	int err;
65 
66 	err = k_sem_take(&ack->sem, timeout);
67 	bt_mesh_msg_ack_ctx_clear(ack);
68 
69 	if (err == -EAGAIN) {
70 		return -ETIMEDOUT;
71 	}
72 
73 	return err;
74 }
75 
bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx * ack,uint32_t op,uint16_t addr,void ** user_data)76 bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack,
77 			       uint32_t op, uint16_t addr, void **user_data)
78 {
79 	if (ack->op != op || (BT_MESH_ADDR_IS_UNICAST(ack->dst) && ack->dst != addr)) {
80 		return false;
81 	}
82 
83 	if (user_data != NULL) {
84 		*user_data = ack->user_data;
85 	}
86 
87 	return true;
88 }
89 
bt_mesh_msg_send(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf)90 int bt_mesh_msg_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
91 		     struct net_buf_simple *buf)
92 {
93 	if (!ctx && !model->pub) {
94 		return -ENOTSUP;
95 	}
96 
97 	if (ctx) {
98 		return bt_mesh_model_send(model, ctx, buf, NULL, 0);
99 	}
100 
101 	net_buf_simple_reset(model->pub->msg);
102 	net_buf_simple_add_mem(model->pub->msg, buf->data, buf->len);
103 
104 	return bt_mesh_model_publish(model);
105 }
106 
bt_mesh_msg_ackd_send(const struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf,const struct bt_mesh_msg_rsp_ctx * rsp)107 int bt_mesh_msg_ackd_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
108 			  struct net_buf_simple *buf, const struct bt_mesh_msg_rsp_ctx *rsp)
109 {
110 	int err;
111 
112 	if (rsp) {
113 		err = bt_mesh_msg_ack_ctx_prepare(rsp->ack, rsp->op,
114 						  ctx ? ctx->addr : model->pub->addr,
115 						  rsp->user_data);
116 		if (err) {
117 			return err;
118 		}
119 	}
120 
121 	err = bt_mesh_msg_send(model, ctx, buf);
122 
123 	if (!rsp) {
124 		return err;
125 	}
126 
127 	if (!err) {
128 		return bt_mesh_msg_ack_ctx_wait(rsp->ack, K_MSEC(rsp->timeout));
129 	}
130 
131 	bt_mesh_msg_ack_ctx_clear(rsp->ack);
132 
133 	return err;
134 }
135