mesh: Add support for meshd to use RAW channel
[platform/upstream/bluez.git] / mesh / mesh-mgmt.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2019  SILVAIR sp. z o.o. All rights reserved.
6  *
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2.1 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "lib/bluetooth.h"
25 #include "lib/mgmt.h"
26 #include "src/shared/mgmt.h"
27
28 #include "ell/queue.h"
29 #include "ell/log.h"
30 #include "ell/util.h"
31
32 #include "mesh/mesh-mgmt.h"
33
34 struct read_info_reg {
35         mesh_mgmt_read_info_func_t cb;
36         void *user_data;
37 };
38
39 struct read_info_req {
40         int index;
41         struct mesh_io *io;
42 };
43
44 static struct mgmt *mgmt_mesh;
45 static struct l_queue *read_info_regs;
46
47 static void process_read_info_req(void *data, void *user_data)
48 {
49         struct read_info_reg *reg = data;
50         int index = L_PTR_TO_UINT(user_data);
51
52         reg->cb(index, reg->user_data);
53 }
54
55 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
56 static void set_powered_complete(uint8_t status, uint16_t length,
57                                         const void *param, void *user_data)
58 {
59         int index = L_PTR_TO_UINT(user_data);
60         uint32_t settings;
61
62         if (status != MGMT_STATUS_SUCCESS) {
63                 l_error("Failed to set powered: %s (0x%02x)",
64                                                 mgmt_errstr(status), status);
65                 return;
66         }
67
68         settings = l_get_le32(param);
69
70         if (!(settings & MGMT_SETTING_POWERED)) {
71                 l_error("Controller is not powered");
72                 return;
73         }
74
75         l_debug("set powered success on index %d", index);
76         /** <TO-DO> update current settings of adapter */
77 }
78
79 bool set_powered(uint16_t mode, int index)
80 {
81         struct mgmt_mode cp;
82
83         memset(&cp, 0, sizeof(cp));
84         cp.val = mode;
85
86         /** <TO-DO> check current settings of adapter */
87         if (mgmt_send(mgmt_mesh, MGMT_OP_SET_POWERED, index, sizeof(cp), &cp,
88                                 set_powered_complete, L_UINT_TO_PTR(index), NULL) > 0)
89
90                 return true;
91
92         return false;
93 }
94 #endif
95
96 static void read_info_cb(uint8_t status, uint16_t length,
97                                         const void *param, void *user_data)
98 {
99         int index = L_PTR_TO_UINT(user_data);
100         const struct mgmt_rp_read_info *rp = param;
101         uint32_t current_settings, supported_settings;
102
103         l_debug("hci %u status 0x%02x", index, status);
104
105         if (status != MGMT_STATUS_SUCCESS) {
106                 l_error("Failed to read info for hci index %u: %s (0x%02x)",
107                                 index, mgmt_errstr(status), status);
108                 return;
109         }
110
111         if (length < sizeof(*rp)) {
112                 l_error("Read info response too short");
113                 return;
114         }
115
116         current_settings = btohl(rp->current_settings);
117         supported_settings = btohl(rp->supported_settings);
118
119         l_debug("settings: supp %8.8x curr %8.8x",
120                                         supported_settings, current_settings);
121
122         if (current_settings & MGMT_SETTING_POWERED) {
123                 l_info("Controller hci %u is in use", index);
124 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
125                 return;
126 #endif
127         }
128
129         if (!(supported_settings & MGMT_SETTING_LE)) {
130                 l_info("Controller hci %u does not support LE", index);
131                 return;
132         }
133
134         l_queue_foreach(read_info_regs, process_read_info_req,
135                                                         L_UINT_TO_PTR(index));
136 }
137
138 static void index_added(uint16_t index, uint16_t length, const void *param,
139                                                         void *user_data)
140 {
141         mgmt_send(mgmt_mesh, MGMT_OP_READ_INFO, index, 0, NULL,
142                                 read_info_cb, L_UINT_TO_PTR(index), NULL);
143 }
144
145 static void index_removed(uint16_t index, uint16_t length, const void *param,
146                                                         void *user_data)
147 {
148         l_warn("Hci dev %4.4x removed", index);
149 }
150
151 static void read_index_list_cb(uint8_t status, uint16_t length,
152                                         const void *param, void *user_data)
153 {
154         const struct mgmt_rp_read_index_list *rp = param;
155         uint16_t num;
156         int i;
157
158         if (status != MGMT_STATUS_SUCCESS) {
159                 l_error("Failed to read index list: %s (0x%02x)",
160                                                 mgmt_errstr(status), status);
161                 return;
162         }
163
164         if (length < sizeof(*rp)) {
165                 l_error("Read index list response sixe too short");
166                 return;
167         }
168
169         num = btohs(rp->num_controllers);
170
171         l_debug("Number of controllers: %u", num);
172
173         if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
174                 l_error("Incorrect packet size for index list response");
175                 return;
176         }
177
178         for (i = 0; i < num; i++) {
179                 uint16_t index;
180
181                 index = btohs(rp->index[i]);
182                 index_added(index, 0, NULL, user_data);
183         }
184 }
185
186 static bool mesh_mgmt_init(void)
187 {
188         if (!read_info_regs)
189                 read_info_regs = l_queue_new();
190
191         if (!mgmt_mesh) {
192                 mgmt_mesh = mgmt_new_default();
193
194                 if (!mgmt_mesh) {
195                         l_error("Failed to initialize mesh management");
196                         return false;
197                 }
198
199                 mgmt_register(mgmt_mesh, MGMT_EV_INDEX_ADDED,
200                                 MGMT_INDEX_NONE, index_added, NULL, NULL);
201                 mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED,
202                                 MGMT_INDEX_NONE, index_removed, NULL, NULL);
203         }
204
205         return true;
206 }
207
208 bool mesh_mgmt_list(mesh_mgmt_read_info_func_t cb, void *user_data)
209 {
210         struct read_info_reg *reg;
211
212         if (!mesh_mgmt_init())
213                 return false;
214
215         reg = l_new(struct read_info_reg, 1);
216         reg->cb = cb;
217         reg->user_data = user_data;
218
219         l_queue_push_tail(read_info_regs, reg);
220
221         /* Use MGMT to find a candidate controller */
222         l_debug("send read index_list");
223         if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INDEX_LIST,
224                                         MGMT_INDEX_NONE, 0, NULL,
225                                         read_index_list_cb, NULL, NULL) <= 0)
226                 return false;
227
228         return true;
229 }