Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / android / main.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2013-2014  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  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdbool.h>
29 #include <signal.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdbool.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <unistd.h>
37
38 #include <sys/signalfd.h>
39 #if defined(ANDROID)
40 #include <sys/prctl.h>
41 #include <sys/capability.h>
42 #endif
43
44 #include <glib.h>
45
46 #include "lib/bluetooth.h"
47 #include "lib/sdp.h"
48
49 #include "src/log.h"
50 #include "src/sdpd.h"
51 #include "src/shared/util.h"
52
53 #include "ipc-common.h"
54 #include "ipc.h"
55 #include "bluetooth.h"
56 #include "socket.h"
57 #include "hidhost.h"
58 #include "hal-msg.h"
59 #include "a2dp.h"
60 #include "pan.h"
61 #include "avrcp.h"
62 #include "handsfree.h"
63 #include "gatt.h"
64 #include "health.h"
65 #include "handsfree-client.h"
66 #include "map-client.h"
67 #include "utils.h"
68
69 #define DEFAULT_VENDOR "BlueZ"
70 #define DEFAULT_MODEL "BlueZ for Android"
71 #define DEFAULT_NAME "BlueZ for Android"
72
73 #define STARTUP_GRACE_SECONDS 5
74 #define SHUTDOWN_GRACE_SECONDS 5
75
76 static char *config_vendor = NULL;
77 static char *config_model = NULL;
78 static char *config_name = NULL;
79 static char *config_serial = NULL;
80 static char *config_fw_rev = NULL;
81 static char *config_hw_rev = NULL;
82 static uint64_t config_system_id = 0;
83 static uint16_t config_pnp_source = 0x0002;     /* USB */
84 static uint16_t config_pnp_vendor = 0x1d6b;     /* Linux Foundation */
85 static uint16_t config_pnp_product = 0x0247;    /* BlueZ for Android */
86 static uint16_t config_pnp_version = 0x0000;
87
88 static guint quit_timeout = 0;
89
90 static bdaddr_t adapter_bdaddr;
91
92 static GMainLoop *event_loop;
93
94 static struct ipc *hal_ipc = NULL;
95
96 static bool services[HAL_SERVICE_ID_MAX + 1] = { false };
97
98 const char *bt_config_get_vendor(void)
99 {
100         if (config_vendor)
101                 return config_vendor;
102
103         return DEFAULT_VENDOR;
104 }
105
106 const char *bt_config_get_name(void)
107 {
108         if (config_name)
109                 return config_name;
110
111         return DEFAULT_NAME;
112 }
113
114 const char *bt_config_get_model(void)
115 {
116         if (config_model)
117                 return config_model;
118
119         return DEFAULT_MODEL;
120 }
121
122 const char *bt_config_get_serial(void)
123 {
124         return config_serial;
125 }
126
127 const char *bt_config_get_fw_rev(void)
128 {
129         return config_fw_rev;
130 }
131
132 const char *bt_config_get_hw_rev(void)
133 {
134         return config_hw_rev;
135 }
136
137 uint64_t bt_config_get_system_id(void)
138 {
139         return config_system_id;
140 }
141
142 uint16_t bt_config_get_pnp_source(void)
143 {
144         return config_pnp_source;
145 }
146
147 uint16_t bt_config_get_pnp_vendor(void)
148 {
149         return config_pnp_vendor;
150 }
151
152 uint16_t bt_config_get_pnp_product(void)
153 {
154         return config_pnp_product;
155 }
156
157 uint16_t bt_config_get_pnp_version(void)
158 {
159         return config_pnp_version;
160 }
161
162 static void service_register(const void *buf, uint16_t len)
163 {
164         const struct hal_cmd_register_module *m = buf;
165         uint8_t status;
166
167         if (m->service_id > HAL_SERVICE_ID_MAX || services[m->service_id]) {
168                 status = HAL_STATUS_FAILED;
169                 goto failed;
170         }
171
172         switch (m->service_id) {
173         case HAL_SERVICE_ID_BLUETOOTH:
174                 if (!bt_bluetooth_register(hal_ipc, m->mode)) {
175                         status = HAL_STATUS_FAILED;
176                         goto failed;
177                 }
178
179                 break;
180         case HAL_SERVICE_ID_SOCKET:
181                 bt_socket_register(hal_ipc, &adapter_bdaddr, m->mode);
182
183                 break;
184         case HAL_SERVICE_ID_HIDHOST:
185                 if (!bt_hid_register(hal_ipc, &adapter_bdaddr, m->mode)) {
186                         status = HAL_STATUS_FAILED;
187                         goto failed;
188                 }
189
190                 break;
191         case HAL_SERVICE_ID_A2DP:
192                 if (!bt_a2dp_register(hal_ipc, &adapter_bdaddr, m->mode)) {
193                         status = HAL_STATUS_FAILED;
194                         goto failed;
195                 }
196
197                 break;
198         case HAL_SERVICE_ID_PAN:
199                 if (!bt_pan_register(hal_ipc, &adapter_bdaddr, m->mode)) {
200                         status = HAL_STATUS_FAILED;
201                         goto failed;
202                 }
203
204                 break;
205         case HAL_SERVICE_ID_AVRCP:
206                 if (!bt_avrcp_register(hal_ipc, &adapter_bdaddr, m->mode)) {
207                         status = HAL_STATUS_FAILED;
208                         goto failed;
209                 }
210
211                 break;
212         case HAL_SERVICE_ID_HANDSFREE:
213                 if (!bt_handsfree_register(hal_ipc, &adapter_bdaddr, m->mode,
214                                                         m->max_clients)) {
215                         status = HAL_STATUS_FAILED;
216                         goto failed;
217                 }
218
219                 break;
220         case HAL_SERVICE_ID_GATT:
221                 if (!bt_gatt_register(hal_ipc, &adapter_bdaddr)) {
222                         status = HAL_STATUS_FAILED;
223                         goto failed;
224                 }
225
226                 break;
227         case HAL_SERVICE_ID_HEALTH:
228                 if (!bt_health_register(hal_ipc, &adapter_bdaddr, m->mode)) {
229                         status = HAL_STATUS_FAILED;
230                         goto failed;
231                 }
232
233                 break;
234         case HAL_SERVICE_ID_HANDSFREE_CLIENT:
235                 if (!bt_hf_client_register(hal_ipc, &adapter_bdaddr)) {
236                         status = HAL_STATUS_FAILED;
237                         goto failed;
238                 }
239
240                 break;
241         case HAL_SERVICE_ID_MAP_CLIENT:
242                 if (!bt_map_client_register(hal_ipc, &adapter_bdaddr,
243                                                                 m->mode)) {
244                         status = HAL_STATUS_FAILED;
245                         goto failed;
246                 }
247
248                 break;
249         default:
250                 DBG("service %u not supported", m->service_id);
251                 status = HAL_STATUS_FAILED;
252                 goto failed;
253         }
254
255         services[m->service_id] = true;
256
257         status = HAL_STATUS_SUCCESS;
258
259         info("Service ID=%u registered", m->service_id);
260
261 failed:
262         ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
263                                                                 status);
264 }
265
266 static bool unregister_service(uint8_t id)
267 {
268         if (id > HAL_SERVICE_ID_MAX || !services[id])
269                 return false;
270
271         switch (id) {
272         case HAL_SERVICE_ID_BLUETOOTH:
273                 bt_bluetooth_unregister();
274                 break;
275         case HAL_SERVICE_ID_SOCKET:
276                 bt_socket_unregister();
277                 break;
278         case HAL_SERVICE_ID_HIDHOST:
279                 bt_hid_unregister();
280                 break;
281         case HAL_SERVICE_ID_A2DP:
282                 bt_a2dp_unregister();
283                 break;
284         case HAL_SERVICE_ID_PAN:
285                 bt_pan_unregister();
286                 break;
287         case HAL_SERVICE_ID_AVRCP:
288                 bt_avrcp_unregister();
289                 break;
290         case HAL_SERVICE_ID_HANDSFREE:
291                 bt_handsfree_unregister();
292                 break;
293         case HAL_SERVICE_ID_GATT:
294                 bt_gatt_unregister();
295                 break;
296         case HAL_SERVICE_ID_HEALTH:
297                 bt_health_unregister();
298                 break;
299         case HAL_SERVICE_ID_HANDSFREE_CLIENT:
300                 bt_hf_client_unregister();
301                 break;
302         case HAL_SERVICE_ID_MAP_CLIENT:
303                 bt_map_client_unregister();
304                 break;
305         default:
306                 DBG("service %u not supported", id);
307                 return false;
308         }
309
310         services[id] = false;
311
312         return true;
313 }
314
315 static void service_unregister(const void *buf, uint16_t len)
316 {
317         const struct hal_cmd_unregister_module *m = buf;
318         uint8_t status;
319
320         if (!unregister_service(m->service_id)) {
321                 status = HAL_STATUS_FAILED;
322                 goto failed;
323         }
324
325         status = HAL_STATUS_SUCCESS;
326
327         info("Service ID=%u unregistered", m->service_id);
328
329 failed:
330         ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
331                                                                 status);
332 }
333
334 static char *get_prop(char *prop, uint16_t len, const uint8_t *val)
335 {
336         /* TODO should fail if set more than once ? */
337         free(prop);
338
339         prop = malloc0(len);
340         if (!prop)
341                 return NULL;
342
343         memcpy(prop, val, len);
344         prop[len - 1] = '\0';
345
346         return prop;
347 }
348
349 static void parse_pnp_id(uint16_t len, const uint8_t *val)
350 {
351         int result;
352         uint16_t vendor, product, version , source;
353         char *pnp;
354
355         /* version is optional */
356         version = config_pnp_version;
357
358         pnp = get_prop(NULL, len, val);
359         if (!pnp)
360                 return;
361
362         DBG("pnp_id %s", pnp);
363
364         result = sscanf(pnp, "bluetooth:%4hx:%4hx:%4hx",
365                                                 &vendor, &product, &version);
366         if (result != EOF && result >= 2) {
367                 source = 0x0001;
368                 goto done;
369         }
370
371         result = sscanf(pnp, "usb:%4hx:%4hx:%4hx", &vendor, &product, &version);
372         if (result != EOF && result >= 2) {
373                 source = 0x0002;
374                 goto done;
375         }
376
377         free(pnp);
378         return;
379 done:
380         free(pnp);
381
382         config_pnp_source = source;
383         config_pnp_vendor = vendor;
384         config_pnp_product = product;
385         config_pnp_version = version;
386 }
387
388 static void parse_system_id(uint16_t len, const uint8_t *val)
389 {
390         uint64_t res;
391         char *id;
392
393         id = get_prop(NULL, len, val);
394         if (!id)
395                 return;
396
397         res = strtoull(id, NULL, 16);
398         if (res == ULLONG_MAX && errno == ERANGE)
399                 goto done;
400
401         config_system_id = res;
402 done:
403         free(id);
404 }
405
406 static void configuration(const void *buf, uint16_t len)
407 {
408         const struct hal_cmd_configuration *cmd = buf;
409         const struct hal_config_prop *prop;
410         unsigned int i;
411
412         buf += sizeof(*cmd);
413         len -= sizeof(*cmd);
414
415         for (i = 0; i < cmd->num; i++) {
416                 prop = buf;
417
418                 if (len < sizeof(*prop) || len < sizeof(*prop) + prop->len) {
419                         error("Invalid configuration command, terminating");
420                         raise(SIGTERM);
421                         return;
422                 }
423
424                 switch (prop->type) {
425                 case HAL_CONFIG_VENDOR:
426                         config_vendor = get_prop(config_vendor, prop->len,
427                                                                 prop->val);
428                         DBG("vendor %s", config_vendor);
429                         break;
430                 case HAL_CONFIG_NAME:
431                         config_name = get_prop(config_name, prop->len,
432                                                                 prop->val);
433                         DBG("name %s", config_name);
434                         break;
435                 case HAL_CONFIG_MODEL:
436                         config_model = get_prop(config_model, prop->len,
437                                                                 prop->val);
438                         DBG("model %s", config_model);
439                         break;
440                 case HAL_CONFIG_SERIAL_NUMBER:
441                         config_serial = get_prop(config_serial, prop->len,
442                                                                 prop->val);
443                         DBG("serial %s", config_serial);
444                         break;
445                 case HAL_CONFIG_SYSTEM_ID:
446                         parse_system_id(prop->len, prop->val);
447                         break;
448                 case HAL_CONFIG_PNP_ID:
449                         parse_pnp_id(prop->len, prop->val);
450                         break;
451                 case HAL_CONFIG_FW_REV:
452                         config_fw_rev = get_prop(config_fw_rev, prop->len,
453                                                                 prop->val);
454                         DBG("fw_rev %s", config_fw_rev);
455                         break;
456                 case HAL_CONFIG_HW_REV:
457                         config_hw_rev = get_prop(config_hw_rev, prop->len,
458                                                                 prop->val);
459                         DBG("hw_rev %s", config_hw_rev);
460                         break;
461                 default:
462                         error("Invalid configuration option (%u), terminating",
463                                                                 prop->type);
464                         raise(SIGTERM);
465                         return;
466                 }
467
468                 buf += sizeof(*prop) + prop->len;
469                 len -= sizeof(*prop) + prop->len;
470         }
471
472         ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_CORE, HAL_OP_CONFIGURATION,
473                                                         HAL_STATUS_SUCCESS);
474 }
475
476 static const struct ipc_handler cmd_handlers[] = {
477         /* HAL_OP_REGISTER_MODULE */
478         { service_register, false, sizeof(struct hal_cmd_register_module) },
479         /* HAL_OP_UNREGISTER_MODULE */
480         { service_unregister, false, sizeof(struct hal_cmd_unregister_module) },
481         /* HAL_OP_CONFIGURATION */
482         { configuration, true, sizeof(struct hal_cmd_configuration) },
483 };
484
485 static void bluetooth_stopped(void)
486 {
487         g_main_loop_quit(event_loop);
488 }
489
490 static gboolean quit_eventloop(gpointer user_data)
491 {
492         g_main_loop_quit(event_loop);
493
494         quit_timeout = 0;
495
496         return FALSE;
497 }
498
499 static void stop_bluetooth(void)
500 {
501         static bool __stop = false;
502
503         if (__stop)
504                 return;
505
506         __stop = true;
507
508         if (!bt_bluetooth_stop(bluetooth_stopped)) {
509                 g_main_loop_quit(event_loop);
510                 return;
511         }
512
513         quit_timeout = g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
514                                                         quit_eventloop, NULL);
515 }
516
517 static void ipc_disconnected(void *data)
518 {
519         stop_bluetooth();
520 }
521
522 static void adapter_ready(int err, const bdaddr_t *addr)
523 {
524         if (err < 0) {
525                 error("Adapter initialization failed: %s", strerror(-err));
526                 exit(EXIT_FAILURE);
527         }
528
529         bacpy(&adapter_bdaddr, addr);
530
531         if (quit_timeout > 0) {
532                 g_source_remove(quit_timeout);
533                 quit_timeout = 0;
534         }
535
536         info("Adapter initialized");
537
538         hal_ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
539                                                 HAL_SERVICE_ID_MAX, true,
540                                                 ipc_disconnected, NULL);
541         if (!hal_ipc) {
542                 error("Failed to initialize IPC");
543                 exit(EXIT_FAILURE);
544         }
545
546         ipc_register(hal_ipc, HAL_SERVICE_ID_CORE, cmd_handlers,
547                                                 G_N_ELEMENTS(cmd_handlers));
548 }
549
550 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
551                                                         gpointer user_data)
552 {
553         static bool __terminated = false;
554         struct signalfd_siginfo si;
555         ssize_t result;
556         int fd;
557
558         if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
559                 return FALSE;
560
561         fd = g_io_channel_unix_get_fd(channel);
562
563         result = read(fd, &si, sizeof(si));
564         if (result != sizeof(si))
565                 return FALSE;
566
567         switch (si.ssi_signo) {
568         case SIGINT:
569         case SIGTERM:
570                 if (!__terminated) {
571                         info("Terminating");
572                         stop_bluetooth();
573                 }
574
575                 __terminated = true;
576                 break;
577         }
578
579         return TRUE;
580 }
581
582 static guint setup_signalfd(void)
583 {
584         GIOChannel *channel;
585         guint source;
586         sigset_t mask;
587         int fd;
588
589         sigemptyset(&mask);
590         sigaddset(&mask, SIGINT);
591         sigaddset(&mask, SIGTERM);
592
593         if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
594                 perror("Failed to set signal mask");
595                 return 0;
596         }
597
598         fd = signalfd(-1, &mask, 0);
599         if (fd < 0) {
600                 perror("Failed to create signal descriptor");
601                 return 0;
602         }
603
604         channel = g_io_channel_unix_new(fd);
605
606         g_io_channel_set_close_on_unref(channel, TRUE);
607         g_io_channel_set_encoding(channel, NULL, NULL);
608         g_io_channel_set_buffered(channel, FALSE);
609
610         source = g_io_add_watch(channel,
611                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
612                                 signal_handler, NULL);
613
614         g_io_channel_unref(channel);
615
616         return source;
617 }
618
619 static gboolean option_version = FALSE;
620 static gint option_index = -1;
621 static gboolean option_dbg = FALSE;
622 static gboolean option_mgmt_dbg = FALSE;
623
624 static GOptionEntry options[] = {
625         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
626                                 "Show version information and exit", NULL },
627         { "index", 'i', 0, G_OPTION_ARG_INT, &option_index,
628                                 "Use specified controller", "INDEX"},
629         { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_dbg,
630                                 "Enable debug logs", NULL},
631         { "mgmt-debug", 0, 0, G_OPTION_ARG_NONE, &option_mgmt_dbg,
632                                 "Enable mgmt debug logs", NULL},
633
634         { NULL }
635 };
636
637 static void cleanup_services(void)
638 {
639         int i;
640
641         DBG("");
642
643         for (i = HAL_SERVICE_ID_MAX; i > HAL_SERVICE_ID_CORE; i--)
644                 unregister_service(i);
645 }
646
647 static bool set_capabilities(void)
648 {
649 #if defined(ANDROID)
650         struct __user_cap_header_struct header;
651         struct __user_cap_data_struct cap;
652
653         header.version = _LINUX_CAPABILITY_VERSION;
654         header.pid = 0;
655
656         /*
657          * CAP_NET_ADMIN: Allow use of MGMT interface
658          * CAP_NET_BIND_SERVICE: Allow use of privileged PSM
659          * CAP_NET_RAW: Allow use of bnep ioctl calls
660          */
661         cap.effective = cap.permitted =
662                 CAP_TO_MASK(CAP_NET_RAW) |
663                 CAP_TO_MASK(CAP_NET_ADMIN) |
664                 CAP_TO_MASK(CAP_NET_BIND_SERVICE);
665         cap.inheritable = 0;
666
667         /* don't clear capabilities when dropping root */
668         if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
669                 error("%s: prctl(): %s", __func__, strerror(errno));
670                 return false;
671         }
672
673         /* Android bluetooth user UID=1002 */
674         if (setuid(1002) < 0) {
675                 error("%s: setuid(): %s", __func__, strerror(errno));
676                 return false;
677         }
678
679         /* TODO: Move to cap_set_proc once bionic support it */
680         if (capset(&header, &cap) < 0) {
681                 error("%s: capset(): %s", __func__, strerror(errno));
682                 return false;
683         }
684
685         /* TODO: Move to cap_get_proc once bionic support it */
686         if (capget(&header, &cap) < 0) {
687                 error("%s: capget(): %s", __func__, strerror(errno));
688                 return false;
689         }
690
691         DBG("Caps: eff: 0x%x, perm: 0x%x, inh: 0x%x", cap.effective,
692                                         cap.permitted, cap.inheritable);
693
694 #endif
695         return true;
696 }
697
698 static void set_version(void)
699 {
700         uint8_t major, minor;
701
702         if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
703                 return;
704
705         config_pnp_version = major << 8 | minor;
706 }
707
708 int main(int argc, char *argv[])
709 {
710         GOptionContext *context;
711         GError *err = NULL;
712         guint signal;
713
714         set_version();
715
716         context = g_option_context_new(NULL);
717         g_option_context_add_main_entries(context, options, NULL);
718
719         if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
720                 if (err != NULL) {
721                         g_printerr("%s\n", err->message);
722                         g_error_free(err);
723                 } else
724                         g_printerr("An unknown error occurred\n");
725
726                 exit(EXIT_FAILURE);
727         }
728
729         g_option_context_free(context);
730
731         if (option_version == TRUE) {
732                 printf("%s\n", VERSION);
733                 exit(EXIT_SUCCESS);
734         }
735
736         signal = setup_signalfd();
737         if (!signal)
738                 return EXIT_FAILURE;
739
740         if (option_dbg || option_mgmt_dbg)
741                 __btd_log_init("*", 0);
742         else
743                 __btd_log_init(NULL, 0);
744
745         if (!set_capabilities()) {
746                 __btd_log_cleanup();
747                 g_source_remove(signal);
748                 return EXIT_FAILURE;
749         }
750
751         quit_timeout = g_timeout_add_seconds(STARTUP_GRACE_SECONDS,
752                                                         quit_eventloop, NULL);
753         if (quit_timeout == 0) {
754                 error("Failed to init startup timeout");
755                 __btd_log_cleanup();
756                 g_source_remove(signal);
757                 return EXIT_FAILURE;
758         }
759
760         if (!bt_bluetooth_start(option_index, option_mgmt_dbg, adapter_ready)) {
761                 __btd_log_cleanup();
762                 g_source_remove(quit_timeout);
763                 g_source_remove(signal);
764                 return EXIT_FAILURE;
765         }
766
767         /* Use params: mtu = 0, flags = 0 */
768         start_sdp_server(0, 0);
769
770         DBG("Entering main loop");
771
772         event_loop = g_main_loop_new(NULL, FALSE);
773
774         g_main_loop_run(event_loop);
775
776         g_source_remove(signal);
777
778         if (quit_timeout > 0)
779                 g_source_remove(quit_timeout);
780
781         cleanup_services();
782
783         stop_sdp_server();
784         bt_bluetooth_cleanup();
785         g_main_loop_unref(event_loop);
786
787         /* If no adapter was initialized, hal_ipc is NULL */
788         if (hal_ipc) {
789                 ipc_unregister(hal_ipc, HAL_SERVICE_ID_CORE);
790                 ipc_cleanup(hal_ipc);
791         }
792
793         info("Exit");
794
795         __btd_log_cleanup();
796
797         free(config_vendor);
798         free(config_model);
799         free(config_name);
800         free(config_serial);
801         free(config_fw_rev);
802         free(config_hw_rev);
803
804         return EXIT_SUCCESS;
805 }