mesh: Add support for meshd to use RAW channel
[platform/upstream/bluez.git] / mesh / main.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2017-2019  Intel Corporation. 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 <getopt.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <ctype.h>
28
29 #include <sys/stat.h>
30 #include <ell/ell.h>
31
32 #include "lib/bluetooth.h"
33 #include "lib/mgmt.h"
34
35 #include "mesh/mesh.h"
36 #include "mesh/crypto.h"
37 #include "mesh/dbus.h"
38 #include "mesh/mesh-io.h"
39
40 static const char *config_dir;
41 static const char *mesh_conf_fname;
42 static enum mesh_io_type io_type;
43 static void *io_opts;
44 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
45 bool use_raw = false;
46 #endif
47
48 static const struct option main_options[] = {
49         { "io",         required_argument,      NULL, 'i' },
50         { "config",     optional_argument,      NULL, 'c' },
51         { "nodetach",   no_argument,            NULL, 'n' },
52         { "debug",      no_argument,            NULL, 'd' },
53         { "dbus-debug", no_argument,            NULL, 'b' },
54 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
55         { "use_raw",    no_argument,            NULL, 'r' },
56 #endif
57         { "help",       no_argument,            NULL, 'h' },
58         { }
59 };
60
61 static void usage(void)
62 {
63         fprintf(stderr,
64                 "Usage:\n"
65                "\tbluetooth-meshd [options]\n");
66         fprintf(stderr,
67                 "Options:\n"
68                "\t--io <io>         Use specified io (default: generic)\n"
69                "\t--config          Configuration directory\n"
70                "\t--nodetach        Run in foreground\n"
71                "\t--debug           Enable debug output\n"
72                "\t--dbus-debug      Enable D-Bus debugging\n"
73                "\t--help            Show %s information\n", __func__);
74         fprintf(stderr,
75                "io:\n"
76                "\t([hci]<index> | generic[:[hci]<index>])\n"
77                "\t\tUse generic HCI io on interface hci<index>, or the first\n"
78                "\t\tavailable one\n");
79 }
80
81 static void do_debug(const char *str, void *user_data)
82 {
83         const char *prefix = user_data;
84
85         l_info("%s%s", prefix, str);
86 }
87
88 static void mesh_ready_callback(void *user_data, bool success)
89 {
90         struct l_dbus *dbus = user_data;
91
92         if (!success) {
93                 l_error("Failed to start mesh");
94                 l_main_quit();
95                 return;
96         }
97
98         if (!dbus_init(dbus)) {
99                 l_error("Failed to initialize mesh D-Bus resources");
100                 l_main_quit();
101         }
102 }
103
104 static void request_name_callback(struct l_dbus *dbus, bool success,
105                                         bool queued, void *user_data)
106 {
107         l_info("Request name %s",
108                 success ? "success": "failed");
109
110         if (!success) {
111                 l_main_quit();
112                 return;
113         }
114
115         if (!mesh_init(config_dir, mesh_conf_fname, io_type, io_opts,
116                                         mesh_ready_callback, dbus)) {
117                 l_error("Failed to initialize mesh");
118                 l_main_quit();
119         }
120 }
121
122 static void ready_callback(void *user_data)
123 {
124         struct l_dbus *dbus = user_data;
125
126         l_info("D-Bus ready");
127         l_dbus_name_acquire(dbus, BLUEZ_MESH_NAME, false, false, false,
128                                                 request_name_callback, NULL);
129 }
130
131 static void disconnect_callback(void *user_data)
132 {
133         l_main_quit();
134 }
135
136 static void signal_handler(uint32_t signo, void *user_data)
137 {
138         static bool terminated;
139
140         if (terminated)
141                 return;
142
143         l_info("Terminating");
144         l_main_quit();
145         terminated = true;
146 }
147
148 static bool parse_io(const char *optarg, enum mesh_io_type *type, void **opts)
149 {
150         if (strstr(optarg, "generic") == optarg) {
151 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
152                 struct mesh_io_opts *m_io_opts = l_new(struct mesh_io_opts, 1);
153                 int *index = &(m_io_opts->index);
154                 m_io_opts->use_raw = use_raw;
155                 *opts = m_io_opts;
156 #else
157                 int *index = l_new(int, 1);
158                 *opts = index;
159 #endif
160                 *type = MESH_IO_TYPE_GENERIC;
161
162                 optarg += strlen("generic");
163                 if (!*optarg) {
164                         *index = MGMT_INDEX_NONE;
165                         return true;
166                 }
167
168                 if (*optarg != ':')
169                         return false;
170
171                 optarg++;
172
173                 if (sscanf(optarg, "hci%d", index) == 1)
174                         return true;
175
176                 if (sscanf(optarg, "%d", index) == 1)
177                         return true;
178
179                 return false;
180         }
181
182         return false;
183 }
184
185 int main(int argc, char *argv[])
186 {
187         int status;
188         bool detached = true;
189         bool dbus_debug = false;
190         struct l_dbus *dbus = NULL;
191         char *io = NULL;
192         int hci_index;
193
194         if (!l_main_init())
195                 return -1;
196
197         l_log_set_stderr();
198
199         if (!mesh_crypto_check_avail()) {
200                 l_error("Mesh Crypto functions unavailable");
201                 status = l_main_run_with_signal(signal_handler, NULL);
202                 goto done;
203         }
204
205         for (;;) {
206                 int opt;
207
208 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
209                 opt = getopt_long(argc, argv, "i:c:f:ndbhr", main_options, NULL);
210 #else
211                 opt = getopt_long(argc, argv, "i:c:f:ndbh", main_options, NULL);
212 #endif
213                 if (opt < 0)
214                         break;
215
216                 switch (opt) {
217                 case 'i':
218                         if (sscanf(optarg, "hci%d", &hci_index) == 1 ||
219                                         sscanf(optarg, "%d", &hci_index) == 1)
220                                 io = l_strdup_printf("generic:%s", optarg);
221                         else
222                                 io = l_strdup(optarg);
223                         break;
224                 case 'n':
225                         detached = false;
226                         break;
227                 case 'd':
228                         l_debug_enable("*");
229                         break;
230                 case 'c':
231                         config_dir = optarg;
232                         break;
233                 case 'f':
234                         mesh_conf_fname = optarg;
235                         break;
236                 case 'b':
237                         dbus_debug = true;
238                         break;
239 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
240                 case 'r':
241                         use_raw = true;
242                         break;
243 #endif
244                 case 'h':
245                         usage();
246                         status = EXIT_SUCCESS;
247                         goto done;
248                 default:
249                         usage();
250                         status = EXIT_FAILURE;
251                         goto done;
252                 }
253         }
254
255         if (!io)
256                 io = l_strdup_printf("generic");
257
258         if (!parse_io(io, &io_type, &io_opts)) {
259                 l_error("Invalid io: %s", io);
260                 status = EXIT_FAILURE;
261                 goto done;
262         }
263
264         l_free(io);
265         io = NULL;
266
267         if (!detached)
268                 umask(0077);
269
270         dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
271         if (!dbus) {
272                 l_error("unable to connect to D-Bus");
273                 status = EXIT_FAILURE;
274                 goto done;
275         }
276
277         if (dbus_debug)
278                 l_dbus_set_debug(dbus, do_debug, "[DBUS] ", NULL);
279         l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
280         l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
281
282         if (!l_dbus_object_manager_enable(dbus, "/")) {
283                 l_error("Failed to enable Object Manager");
284                 status = EXIT_FAILURE;
285                 goto done;
286         }
287
288         status = l_main_run_with_signal(signal_handler, NULL);
289
290 done:
291         if (io)
292                 l_free(io);
293
294         if (io_opts)
295                 l_free(io_opts);
296
297         mesh_cleanup();
298         l_dbus_destroy(dbus);
299         l_main_exit();
300
301         return status;
302 }