cc514cb451f78083c20536f77f6264ba444b42b0
[platform/core/connectivity/bluetooth-frwk.git] / bt-otp / bt-otpserver.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dlog.h>
19 #include <gio/gio.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <time.h>
25 #include <sys/stat.h>
26 #include <langinfo.h>
27 #include <inttypes.h>
28 #include <errno.h>
29
30 #include "bt-otpserver.h"
31 #include "bluetooth-api.h"
32
33
34 #undef LOG_TAG
35 #define LOG_TAG "BLUETOOTH_OTP"
36
37 #define BT_INFO(fmt, arg...) SLOGI(fmt, ##arg)
38 #define BT_ERR(fmt, arg...) SLOGE(fmt, ##arg)
39 #define BT_DBG(fmt, arg...) SLOGD(fmt, ##arg)
40
41 /* OTP object paths */
42 char *otp_obj_path = NULL;
43 char *otp_feature_obj_path = NULL;
44 char *otp_object_name_obj_path = NULL;
45 char *otp_object_type_obj_path = NULL;
46 char *otp_object_size_obj_path = NULL;
47 char *otp_object_first_created_obj_path = NULL;
48 char *otp_object_last_modified_obj_path = NULL;
49 char *otp_object_id_obj_path = NULL;
50 char *otp_object_prop_obj_path = NULL;
51 char *otp_oacp_obj_path = NULL;
52 char *otp_olcp_obj_path = NULL;
53 char *otp_oacp_desc_obj_path = NULL;
54 char *otp_olcp_desc_obj_path = NULL;
55
56 static GMainLoop *main_loop;
57 GDBusNodeInfo *otp_node_info = NULL;
58 static GDBusConnection *conn;
59 static GDBusConnection *g_conn;
60
61 static int property_sub_id = -1;
62 static int adapter_sub_id = -1;
63 static guint g_owner_id = 0;
64
65 struct otp_char_info {
66         gchar *char_path;
67         gchar *char_value;
68         int value_length;
69 };
70
71 struct indicate_info {
72         uint8_t resp_opcode;
73         uint8_t req_opcode;
74         uint8_t result_code;
75         uint8_t *resp_param;
76 };
77
78 /* Object metadata */
79 struct object_metadata {
80         gchar *name;
81         gchar *type;
82         uint32_t curr_size;
83         uint32_t alloc_size;
84         time_t first_created;
85         time_t last_modified;
86         uint64_t id;
87         uint32_t props;
88 };
89
90 static struct object_metadata *selected_object;
91 static uint64_t object_id = OBJECT_START_ID;
92 static GSList *otp_object_list = NULL;
93 static GSList *otp_char_list = NULL;
94 static guint obj_curr_index;
95 static int adv_handle = 0;
96 static gboolean OLCP_indicate = FALSE;
97 char *directory = NULL;
98
99 static const gchar otp_introspection_xml[] =
100 "<node name='/'>"
101 "       <interface name='org.projectx.otp_service'>"
102 "               <method name='enable'>"
103 "                       <arg type='s' name='directory'/>"
104 "                       <arg type='i' name='status' direction='out'/>"
105 "               </method>"
106 "               <method name='disable'>"
107 "                       <arg type='i' name='status' direction='out'/>"
108 "               </method>"
109 "       </interface>"
110 "</node>";
111
112 void _bt_otp_deinit_event_receiver(void);
113 void _bt_otp_unregister_interface(void);
114
115 static void delete_all_objects(void)
116 {
117         GSList *tmp = NULL;
118         for (tmp = otp_object_list; tmp != NULL; tmp = tmp->next) {
119                 if (tmp->data) {
120                         struct object_metadata *obj_info = tmp->data;
121                         if (obj_info->name)
122                                 g_free(obj_info->name);
123                         if (obj_info->type)
124                                 g_free(obj_info->type);
125                         otp_object_list = g_slist_delete_link(otp_object_list, tmp->data);
126                 }
127         }
128         g_slist_free(otp_object_list);
129         otp_object_list = NULL;
130 }
131
132 static void delete_all_characterisitc(void)
133 {
134         GSList *tmp = NULL;
135         for (tmp = otp_char_list; tmp != NULL; tmp = tmp->next) {
136                 if (tmp->data) {
137                         struct otp_char_info *char_info = tmp->data;
138                         if (char_info->char_path)
139                                 g_free(char_info->char_path);
140                         if (char_info->char_value)
141                                 g_free(char_info->char_value);
142                         otp_char_list = g_slist_delete_link(otp_char_list, tmp->data);
143                 }
144         }
145         g_slist_free(otp_char_list);
146         otp_char_list = NULL;
147 }
148
149 void _bt_otp_exit(void)
150 {
151         int ret;
152         BT_DBG("");
153
154         if (otp_char_list)
155                 delete_all_characterisitc();
156
157         if (otp_object_list)
158                 delete_all_objects();
159
160         ret = bluetooth_gatt_deinit();
161         if (ret != BLUETOOTH_ERROR_NONE)
162                 BT_ERR("Failed to Deinit GATT %d", ret);
163
164         _bt_otp_deinit_event_receiver();
165
166         _bt_otp_unregister_interface();
167
168         /* TODO: Advertising is not getting stopped by this API.
169          * This is because OTP_SERVER_DEINIT dbus call is blocking
170          * BT_SET_ADVERTISING_DATA dbus call. But now advertisment
171          * is stopped because of terminated process logic.
172          */
173         ret = bluetooth_set_advertising(adv_handle, FALSE);
174         if (ret != BLUETOOTH_ERROR_NONE)
175                 BT_ERR("Failed to stop ADV %d", ret);
176
177         if (main_loop != NULL) {
178                 g_main_loop_quit(main_loop);
179         }
180 }
181
182 static void _bt_otp_set_char_value(const char *obj_path,
183                                 const char *value, int value_length)
184 {
185         GSList *tmp = NULL;
186
187         if (!value)
188                 return;
189         for (tmp = otp_char_list; tmp != NULL; tmp = tmp->next) {
190                 if (tmp->data) {
191                         struct otp_char_info *char_info = tmp->data;
192                         if (!g_strcmp0(char_info->char_path, obj_path)) {
193                                 char_info->char_value = g_try_realloc(char_info->char_value, value_length);
194                                 if (char_info->char_value) {
195                                         memcpy(char_info->char_value, value, value_length);
196                                         char_info->value_length = value_length;
197                                 }
198                                 return;
199                         }
200                 }
201         }
202         return;
203 }
204
205 int add_new_characteristic(const char *char_uuid, bt_gatt_permission_t perms,
206                 bt_gatt_characteristic_property_t props, char **obj_path)
207 {
208         int ret = BLUETOOTH_ERROR_NONE;
209         struct otp_char_info *char_info = NULL;
210
211         ret = bluetooth_gatt_add_new_characteristic(otp_obj_path,
212                                         char_uuid, perms, props, obj_path);
213         if (ret != BLUETOOTH_ERROR_NONE) {
214                 BT_ERR("Failed to add new char %d", ret);
215                 return ret;
216         }
217
218         char_info = g_new0(struct otp_char_info, 1);
219         char_info->char_path = g_strdup(*obj_path);
220         otp_char_list = g_slist_append(otp_char_list, char_info);
221
222         return ret;
223 }
224
225 static char *_otp_convert_uuid_to_uuid128(const char *uuid)
226 {
227         int len;
228         char *uuid128;
229
230         len = strlen(uuid);
231
232         switch (len) {
233         case 4:
234                 /* UUID 16bits */
235                 uuid128 = g_strdup_printf("0000%s-0000-1000-8000-00805f9b34fb",
236                                                                         uuid);
237                 break;
238
239         case 8:
240                 /* UUID 32bits */
241                 uuid128 = g_strdup_printf("%s-0000-1000-8000-00805f9b34fb",
242                                                                         uuid);
243                 break;
244
245         case 36:
246                 /* UUID 128bits */
247                 uuid128 = strdup(uuid);
248                 break;
249
250         default:
251                 return NULL;
252         }
253
254         return uuid128;
255 }
256
257 int _bt_otp_prepare_ots(void)
258 {
259         BT_DBG("+");
260         int ret = BLUETOOTH_ERROR_NONE;
261         char *service_uuid;
262         char *char_uuid;
263         char *desc_uuid;
264         bt_gatt_characteristic_property_t props;
265         bt_gatt_permission_t perms;
266         char supp_feat[OTP_FEATURE_LENGTH] = { 0x08, 0x00, 0x00, 0x00,
267                                                 0x80, 0x00, 0x00, 0x00 };
268
269         ret = bluetooth_gatt_init();
270         if (ret != BLUETOOTH_ERROR_NONE) {
271                 BT_ERR("Failed to Init GATT %d", ret);
272                 goto fail;
273         }
274
275         service_uuid = _otp_convert_uuid_to_uuid128(OTP_UUID);
276         ret = bluetooth_gatt_add_service(service_uuid, &otp_obj_path);
277         if (ret != BLUETOOTH_ERROR_NONE) {
278                 BT_ERR("Failed to add service %d", ret);
279                 goto fail;
280         }
281
282         /* Characteristic OTP Feature */
283         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
284         perms = BLUETOOTH_GATT_PERMISSION_READ;
285         char_uuid = _otp_convert_uuid_to_uuid128(OTP_FEATURE_UUID);
286         ret = add_new_characteristic(char_uuid, perms, props,
287                                                 &otp_feature_obj_path);
288         if (ret != BLUETOOTH_ERROR_NONE)
289                 goto fail;
290
291         ret = bluetooth_gatt_set_characteristic_value(otp_feature_obj_path,
292                                                 supp_feat, OTP_FEATURE_LENGTH);
293         if (ret != BLUETOOTH_ERROR_NONE) {
294                 BT_ERR("Failed to set char value %d", ret);
295                 return ret;
296         }
297
298         _bt_otp_set_char_value(otp_feature_obj_path, supp_feat,
299                                                 OTP_FEATURE_LENGTH);
300
301         /* Characteristic Object Name */
302         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
303         perms = BLUETOOTH_GATT_PERMISSION_READ;
304         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_NAME_UUID);
305         ret = add_new_characteristic(char_uuid, perms, props,
306                                         &otp_object_name_obj_path);
307         if (ret != BLUETOOTH_ERROR_NONE)
308                 goto fail;
309
310         /* Characteristic Object Type */
311         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
312         perms = BLUETOOTH_GATT_PERMISSION_READ;
313         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_TYPE_UUID);
314         ret = add_new_characteristic(char_uuid, perms, props,
315                                         &otp_object_type_obj_path);
316         if (ret != BLUETOOTH_ERROR_NONE)
317                 goto fail;
318
319         /* Characteristic Object Size */
320         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
321         perms = BLUETOOTH_GATT_PERMISSION_READ;
322         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_SIZE_UUID);
323         ret = add_new_characteristic(char_uuid, perms, props,
324                                         &otp_object_size_obj_path);
325         if (ret != BLUETOOTH_ERROR_NONE)
326                 goto fail;
327
328         /* Characteristic Object First-Created */
329         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
330                 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
331         perms = BLUETOOTH_GATT_PERMISSION_READ |
332                 BLUETOOTH_GATT_PERMISSION_WRITE;
333         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_FIRST_CREATED_UUID);
334         ret = add_new_characteristic(char_uuid, perms, props,
335                                         &otp_object_first_created_obj_path);
336         if (ret != BLUETOOTH_ERROR_NONE)
337                 goto fail;
338
339         /* Characteristic Object Last-Modified */
340         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
341                 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
342         perms = BLUETOOTH_GATT_PERMISSION_READ |
343                 BLUETOOTH_GATT_PERMISSION_WRITE;
344         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_LAST_MODIFIED_UUID);
345         ret = add_new_characteristic(char_uuid, perms, props,
346                                 &otp_object_last_modified_obj_path);
347         if (ret != BLUETOOTH_ERROR_NONE)
348                 goto fail;
349
350         /* Characteristic Object ID */
351         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
352         perms = BLUETOOTH_GATT_PERMISSION_READ;
353         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_ID_UUID);
354         ret = add_new_characteristic(char_uuid, perms, props,
355                                         &otp_object_id_obj_path);
356         if (ret != BLUETOOTH_ERROR_NONE)
357                 goto fail;
358
359         /* Characteristic Object Properties */
360         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
361         perms = BLUETOOTH_GATT_PERMISSION_READ;
362         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_PROP_UUID);
363         ret = add_new_characteristic(char_uuid, perms, props,
364                                         &otp_object_prop_obj_path);
365         if (ret != BLUETOOTH_ERROR_NONE)
366                 goto fail;
367
368         /* Characteristic OACP */
369         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE |
370                 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE;
371         perms = BLUETOOTH_GATT_PERMISSION_WRITE;
372         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OACP_UUID);
373         ret = add_new_characteristic(char_uuid, perms, props,
374                                                 &otp_oacp_obj_path);
375         if (ret != BLUETOOTH_ERROR_NONE)
376                 goto fail;
377
378         /* CCCD for OACP */
379         desc_uuid = _otp_convert_uuid_to_uuid128(OTP_CP_CCC_DESC_UUID);
380         perms = BLUETOOTH_GATT_PERMISSION_READ |
381                 BLUETOOTH_GATT_PERMISSION_WRITE;
382         ret = bluetooth_gatt_add_descriptor(otp_oacp_obj_path, desc_uuid,
383                                                 perms, &otp_oacp_desc_obj_path);
384         if (ret != BLUETOOTH_ERROR_NONE) {
385                 BT_ERR("Failed to add new char descriptor %d", ret);
386                 goto fail;
387         }
388
389         /* Characteristic OLCP */
390         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE |
391                 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE;
392         perms = BLUETOOTH_GATT_PERMISSION_WRITE;
393         char_uuid = _otp_convert_uuid_to_uuid128(OTP_OLCP_UUID);
394         ret = add_new_characteristic(char_uuid, perms, props,
395                                                 &otp_olcp_obj_path);
396         if (ret != BLUETOOTH_ERROR_NONE)
397                 goto fail;
398
399         /* CCCD for OLCP */
400         desc_uuid = _otp_convert_uuid_to_uuid128(OTP_CP_CCC_DESC_UUID);
401         perms = BLUETOOTH_GATT_PERMISSION_READ |
402                 BLUETOOTH_GATT_PERMISSION_WRITE;
403         ret = bluetooth_gatt_add_descriptor(otp_olcp_obj_path, desc_uuid,
404                                                 perms, &otp_olcp_desc_obj_path);
405         if (ret != BLUETOOTH_ERROR_NONE) {
406                 BT_ERR("Failed to add new char descriptor %d", ret);
407                 goto fail;
408         }
409
410         /* Register service */
411         ret = bluetooth_gatt_register_service(otp_obj_path);
412         if (ret != BLUETOOTH_ERROR_NONE) {
413                 BT_ERR("Failed to register service %d", ret);
414                 goto fail;
415         }
416
417         /* Register Application */
418         ret = bluetooth_gatt_register_application();
419         if (ret != BLUETOOTH_ERROR_NONE) {
420                 BT_ERR("Failed to register application %d", ret);
421                 goto fail;
422         }
423
424         BT_DBG("-");
425         return ret;
426
427 fail:
428         delete_all_characterisitc();
429         return ret;
430 }
431
432 int _bt_otp_set_advertising_data(void)
433 {
434         int ret;
435         BT_DBG("");
436
437         /* OTP UUID */
438         guint8 data[4]  = {0x03, 0x02, 0x25, 0x18};
439         bluetooth_advertising_data_t adv;
440
441         BT_DBG("%x %x %x %x", data[0], data[1], data[2], data[3]);
442         memcpy(adv.data, data, sizeof(data));
443         ret = bluetooth_set_advertising_data(adv_handle, &adv, sizeof(data));
444         if (ret != BLUETOOTH_ERROR_NONE) {
445                 BT_ERR("Failed to set ADV data %d", ret);
446                 return ret;
447         }
448
449         ret = bluetooth_set_advertising(adv_handle, TRUE);
450         if (ret != BLUETOOTH_ERROR_NONE) {
451                 BT_ERR("Failed to set ADV %d", ret);
452                 return ret;
453         }
454
455         return 0;
456 }
457
458 static void _bt_otp_method(GDBusConnection *connection,
459                 const gchar *sender,
460                 const gchar *object_path,
461                 const gchar *interface_name,
462                 const gchar *method_name,
463                 GVariant *parameters,
464                 GDBusMethodInvocation *invocation,
465                 gpointer user_data)
466 {
467         BT_DBG("+");
468         int status = BLUETOOTH_ERROR_NONE;
469
470         BT_DBG("Method[%s] Object Path[%s] Interface Name[%s]",
471                         method_name, object_path, interface_name);
472
473         if (g_strcmp0(method_name, "enable") == 0) {
474                 GDir *dir = NULL;
475                 GError *error = NULL;
476                 const gchar *filename = NULL;
477                 char absolute_path[ABSOLUTE_PATH_MAX_LENGTH];
478                 GSList *list = NULL, *l = NULL;
479                 struct stat st;
480                 struct object_metadata *object = NULL;
481
482                 g_variant_get(parameters, "(s)", &directory);
483                 BT_DBG("Directory = [%s]", directory);
484
485                 dir = g_dir_open(directory, 0, &error);
486                 if (!dir) {
487                         BT_ERR("Failed to open directory: %s", error->message);
488                         g_error_free(error);
489                         status = BLUETOOTH_ERROR_INVALID_DIRECTORY;
490                         goto fail;
491                 }
492
493                 while ((filename = g_dir_read_name(dir))) {
494                         list = g_slist_append(list, (gpointer) filename);
495                 }
496
497                 if (!list) {
498                         BT_DBG("No object found in given directory");
499                         status = BLUETOOTH_ERROR_NO_OBJECTS_FOUND;
500                         goto fail;
501                 }
502
503                 for (l = list; l != NULL; l = l->next) {
504                         if (!l->data) continue;
505                         snprintf(absolute_path, sizeof(absolute_path), "%s%s", directory,
506                                                         (char *)l->data);
507
508                         BT_INFO("filename: %s, absoulte_path: %s",
509                                         (char *)l->data, absolute_path);
510
511                         if (stat(absolute_path, &st) == -1) {
512                                 BT_INFO("stat failed: (%d)\n", errno);
513                                 continue;
514                         }
515
516                         object = g_new0(struct object_metadata, 1);
517
518                         object->name = g_strdup((const gchar *)l->data);
519                         object->type = _otp_convert_uuid_to_uuid128(UNSUPPORTED_OBJECT_TYPE_UUID);
520                         object->first_created = st.st_ctime;
521                         object->last_modified = st.st_ctime;
522                         object->curr_size = (uint32_t) st.st_size;
523                         object->alloc_size = (uint32_t) st.st_size;
524                         object->id = object_id;
525                         object->props = OBJECT_READ | OBJECT_WRITE;
526
527                         otp_object_list = g_slist_append(otp_object_list,
528                                                                 object);
529
530                         object_id++;
531                 }
532
533                 g_dir_close(dir);
534
535                 BT_DBG("preparing");
536                 if (_bt_otp_prepare_ots() != BLUETOOTH_ERROR_NONE) {
537                         BT_ERR("Fail to prepare OTP Proxy");
538                         status = BLUETOOTH_ERROR_INTERNAL;
539                         goto fail;
540                 }
541
542                 BT_DBG("advertsing");
543                 if (_bt_otp_set_advertising_data() != BLUETOOTH_ERROR_NONE) {
544                         BT_ERR("Fail to set advertising data");
545                         status = BLUETOOTH_ERROR_INTERNAL;
546                         goto fail;
547                 }
548 fail:
549                 g_dbus_method_invocation_return_value(invocation,
550                                                 g_variant_new("(i)", status));
551
552         } else if (g_strcmp0(method_name, "disable") == 0) {
553                 g_dbus_method_invocation_return_value(invocation,
554                                                 g_variant_new("(i)", status));
555                 _bt_otp_exit();
556         }
557         BT_DBG("-");
558 }
559
560 static const GDBusInterfaceVTable otp_method_table = {
561         _bt_otp_method,
562         NULL,
563         NULL,
564 };
565
566 static void _bt_otp_on_bus_acquired(GDBusConnection *connection,
567                                 const gchar *name, gpointer user_data)
568 {
569         guint object_id;
570         GError *error = NULL;
571
572         BT_DBG("+");
573
574         g_conn = connection;
575
576         object_id = g_dbus_connection_register_object(connection,
577                                                 BT_OTP_OBJECT_PATH,
578                                                 otp_node_info->interfaces[0],
579                                                 &otp_method_table,
580                                                 NULL, NULL, &error);
581         if (object_id == 0) {
582                 BT_ERR("Failed to register method table: %s", error->message);
583                 g_error_free(error);
584                 g_dbus_node_info_unref(otp_node_info);
585         }
586
587         BT_DBG("-");
588 }
589
590 static void _bt_otp_on_name_acquired(GDBusConnection *connection,
591                                         const gchar     *name,
592                                         gpointer user_data)
593 {
594         BT_DBG("");
595 }
596
597 static void _bt_otp_on_name_lost(GDBusConnection *connection,
598                                 const gchar     *name,
599                                 gpointer user_data)
600 {
601         BT_DBG("");
602         g_object_unref(g_conn);
603         g_conn = NULL;
604         g_dbus_node_info_unref(otp_node_info);
605         g_bus_unown_name(g_owner_id);
606 }
607
608 int _bt_otp_register_interface(void)
609 {
610         BT_DBG("+");
611         GError *error = NULL;
612         guint owner_id;
613
614         otp_node_info = g_dbus_node_info_new_for_xml(otp_introspection_xml, &error);
615         if (!otp_node_info) {
616                 BT_ERR("Failed to install: %s", error->message);
617                 return BLUETOOTH_ERROR_INTERNAL;
618         }
619
620         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
621                                 BT_OTP_SERVICE_NAME,
622                                 G_BUS_NAME_OWNER_FLAGS_NONE,
623                                 _bt_otp_on_bus_acquired,
624                                 _bt_otp_on_name_acquired,
625                                 _bt_otp_on_name_lost,
626                                 NULL, NULL);
627         g_owner_id = owner_id;
628         BT_DBG("owner_id is [%d]\n", owner_id);
629
630         BT_DBG("-");
631         return BLUETOOTH_ERROR_NONE;
632 }
633
634 void _bt_otp_unregister_interface(void)
635 {
636         BT_DBG("+");
637
638         g_object_unref(g_conn);
639         g_conn = NULL;
640         g_dbus_node_info_unref(otp_node_info);
641         g_bus_unown_name(g_owner_id);
642
643         BT_DBG("-");
644         return;
645 }
646
647
648 void convert_to_hex(struct object_metadata *object, char *type, char *value)
649 {
650         struct tm *tm = NULL;
651
652         BT_DBG("type : %s", type);
653
654         memset(value, 0, 8);
655
656         if (!g_strcmp0(type, "size")) {
657
658                 value[3] = (object->curr_size >> 24) & 0xFF;
659                 value[2] = (object->curr_size >> 16) & 0xFF;
660                 value[1] = (object->curr_size >> 8) & 0xFF;
661                 value[0] = object->curr_size & 0xFF;
662
663                 value[7] = (object->alloc_size >> 24) & 0xFF;
664                 value[6] = (object->alloc_size >> 16) & 0xFF;
665                 value[5] = (object->alloc_size >> 8) & 0xFF;
666                 value[4] = object->alloc_size & 0xFF;
667
668         } else if (!g_strcmp0(type, "date")) {
669
670                 localtime_r(&(object->first_created), tm);
671
672                 if (tm) {
673                         value[1] = ((tm->tm_year+1900) >> 8) & 0xFF;
674                         value[0] = (tm->tm_year+1900) & 0xFF;
675                         value[2] = (tm->tm_mon+1) & 0xFF;
676                         value[3] = tm->tm_mday & 0xFF;
677                         value[4] = tm->tm_hour & 0xFF;
678                         value[5] = tm->tm_min & 0xFF;
679                         value[6] = tm->tm_sec & 0xFF;
680                 }
681
682         } else if (!g_strcmp0(type, "id")) {
683
684                 value[5] = (object->id >> 48) & 0xFF;
685                 value[4] = (object->id >> 32) & 0xFF;
686                 value[3] = (object->id >> 24) & 0xFF;
687                 value[2] = (object->id >> 16) & 0xFF;
688                 value[1] = (object->id >> 8) & 0xFF;
689                 value[0] = object->id & 0xFF;
690
691         } else if (!g_strcmp0(type, "props")) {
692                 value[3] = (object->props >> 24) & 0xFF;
693                 value[2] = (object->props >> 16) & 0xFF;
694                 value[1] = (object->props >> 8) & 0xFF;
695                 value[0] = object->props & 0xFF;
696         }
697 }
698
699 void update_obj_metadata_charc_value(struct object_metadata *object)
700 {
701         /* Value can be of maximum eight bytes */
702         char value[8];
703
704         _bt_otp_set_char_value(otp_object_name_obj_path, object->name,
705                                                         strlen(object->name));
706         _bt_otp_set_char_value(otp_object_type_obj_path, object->type,
707                                                         strlen(object->type));
708
709         convert_to_hex(object, "size", value);
710         _bt_otp_set_char_value(otp_object_size_obj_path, value, 8);
711
712         convert_to_hex(object, "date", value);
713         _bt_otp_set_char_value(otp_object_first_created_obj_path, value, 7);
714         _bt_otp_set_char_value(otp_object_last_modified_obj_path, value, 7);
715
716         convert_to_hex(object, "id", value);
717         _bt_otp_set_char_value(otp_object_id_obj_path, value, 6);
718
719         convert_to_hex(object, "props", value);
720         _bt_otp_set_char_value(otp_object_prop_obj_path, value, 4);
721 }
722
723 int _bt_otp_olcp_write_cb(char *value, int len, int offset,
724                                         struct indicate_info *info)
725 {
726         int ret = OLCP_SUCCESS;
727         int opcode = value[0];
728         struct object_metadata *object;
729
730         BT_INFO("OLCP Opcode 0x%d", opcode);
731
732         if (!otp_object_list) {
733                 ret = OLCP_NO_OBJ;
734                 goto fail;
735         }
736
737         switch (opcode) {
738         case OLCP_FIRST: {
739                 object = (struct object_metadata *) g_slist_nth_data(otp_object_list, 0);
740                 if (!object) {
741                         ret = OLCP_OUT_OF_BOUNDS;
742                         goto fail;
743                 }
744                 update_obj_metadata_charc_value(object);
745                 selected_object = object;
746                 obj_curr_index = 0;
747         } break;
748         case OLCP_LAST: {
749                 len = g_slist_length(otp_object_list);
750                 object = (struct object_metadata *) g_slist_nth_data(otp_object_list, len-1);
751                 if (!object) {
752                         ret = OLCP_OUT_OF_BOUNDS;
753                         goto fail;
754                 }
755                 update_obj_metadata_charc_value(object);
756                 selected_object = object;
757                 obj_curr_index = len-1;
758         } break;
759         case OLCP_PREVIOUS: {
760                 if (obj_curr_index == 0) {
761                         ret = OLCP_OUT_OF_BOUNDS;
762                         goto fail;
763                 }
764                 object = (struct object_metadata *) g_slist_nth_data(otp_object_list, obj_curr_index-1);
765                 if (!object) {
766                         ret = OLCP_OUT_OF_BOUNDS;
767                         goto fail;
768                 }
769                 update_obj_metadata_charc_value(object);
770                 selected_object = object;
771                 obj_curr_index -= 1;
772         } break;
773         case OLCP_NEXT: {
774                 object = (struct object_metadata *) g_slist_nth_data(otp_object_list, obj_curr_index+1);
775                 if (!object) {
776                         ret = OLCP_OUT_OF_BOUNDS;
777                         goto fail;
778                 }
779                 update_obj_metadata_charc_value(object);
780                 selected_object = object;
781                 obj_curr_index += 1;
782         } break;
783         case OLCP_GOTO:
784         case OLCP_ORDER:
785         case OLCP_REQ_NO_OBJ:
786         case OLCP_CLEAR_MARKING:
787         default:
788                 ret = OLCP_OPCODE_NOT_SUPPORTED;
789                 break;
790         }
791 fail:
792         info->resp_opcode = OLCP_RESPONSE;
793         info->req_opcode = opcode;
794         info->result_code = ret;
795         info->resp_param = NULL;
796         return BLUETOOTH_ERROR_NONE;
797 }
798
799 static struct otp_char_info *otp_get_char_value(const char *path)
800 {
801         GSList *tmp = NULL;
802
803         for (tmp = otp_char_list; tmp != NULL; tmp = tmp->next) {
804                 if (tmp->data) {
805                         struct otp_char_info *char_info = tmp->data;
806                         if (!g_strcmp0(char_info->char_path, path))
807                                 return char_info;
808                 }
809         }
810
811         return NULL;
812 }
813
814 int _bt_otp_read_cb(const char *obj_path, char **value, int *len)
815 {
816         struct otp_char_info *info = NULL;
817
818         if (!obj_path) {
819                 BT_ERR("Wrong Obj path");
820                 return BLUETOOTH_ERROR_INTERNAL;
821         }
822
823         if (g_strcmp0(obj_path, otp_feature_obj_path)) {
824                 if (!selected_object) {
825                         return BLUETOOTH_ERROR_OBJECT_NOT_SELECTED;
826                 }
827         }
828
829         info = otp_get_char_value(obj_path);
830         if (info) {
831                 if (info->char_value == NULL || info->value_length == 0)
832                         return BLUETOOTH_ERROR_INTERNAL;
833
834                 *len = info->value_length;
835                 *value = (char *)malloc(sizeof(char)*(*len));
836                 memcpy(*value, info->char_value, *len);
837
838                 return BLUETOOTH_ERROR_NONE;
839         } else {
840                 return BLUETOOTH_ERROR_INTERNAL;
841         }
842 }
843
844 static void _otp_convert_address_to_hex(bluetooth_device_address_t *addr_hex,
845                                                         const char *addr_str)
846 {
847         int i = 0;
848         unsigned int addr[BLUETOOTH_ADDRESS_LENGTH] = { 0, };
849
850         if (addr_str == NULL || addr_str[0] == '\0')
851                 return;
852
853         i = sscanf(addr_str, "%X:%X:%X:%X:%X:%X", &addr[0], &addr[1],
854                                 &addr[2], &addr[3], &addr[4], &addr[5]);
855         if (i != BLUETOOTH_ADDRESS_LENGTH)
856                 BT_ERR("Invalid format string - [%s]", addr_str);
857
858         for (i = 0; i < BLUETOOTH_ADDRESS_LENGTH; i++)
859                 addr_hex->addr[i] = (unsigned char)addr[i];
860 }
861
862 static void _bt_otp_send_indication(const char *obj_path,
863                                 struct indicate_info *info,
864                                 bluetooth_device_address_t *remote_address)
865 {
866         int ret = BLUETOOTH_ERROR_NONE;
867         char value[7] = {0x00};
868
869         BT_DBG("");
870
871         value[0] = info->resp_opcode & 0xFF;
872         value[1] = info->req_opcode & 0xFF;
873         value[2] = info->result_code & 0xFF;
874         if (info->resp_param) {
875                 value[6] = (info->resp_param[3] >> 24) & 0xFF;
876                 value[5] = (info->resp_param[4] >> 16) & 0xFF;
877                 value[4] = (info->resp_param[5] >> 8) & 0xFF;
878                 value[3] = info->resp_param[6] & 0xFF;
879         }
880
881         BT_DBG("Opcode: %d", value[1]);
882
883         /* Store the status value */
884         _bt_otp_set_char_value(obj_path, value, 7);
885
886         /* Send indication */
887         ret = bluetooth_gatt_server_set_notification(obj_path, remote_address);
888         if (ret != BLUETOOTH_ERROR_NONE) {
889                 BT_ERR("_bt_otp_send_control_point_indication failed");
890                 return;
891         }
892         ret = bluetooth_gatt_update_characteristic(obj_path, value, 7);
893         if (ret != BLUETOOTH_ERROR_NONE) {
894                 BT_ERR("_bt_otp_send_control_point_indication failed");
895                 return;
896         }
897 }
898
899 void _bt_otp_gatt_char_property_changed_event(GVariant *msg,
900                                 const char *path)
901 {
902         int result = BLUETOOTH_ERROR_NONE;
903         GVariantIter value_iter;
904         const char *property = NULL;
905         const char *char_path = NULL;
906         const char *svc_handle = NULL;
907         GVariant *var = NULL;
908         GVariant *val = NULL;
909         g_variant_iter_init(&value_iter, msg);
910
911         while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &var))) {
912
913                 if (property == NULL) {
914                         BT_ERR("Property NULL");
915                         return;
916                 }
917
918                 if (!g_strcmp0(property, "WriteValue")) {
919                         int len = 0;
920                         BT_INFO("WriteValue");
921                         BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
922
923                         if (var) {
924                                 bluetooth_device_address_t addr_hex = { {0,} };
925                                 gchar *addr = NULL;
926                                 guint8 req_id = 1;
927                                 guint16 offset = 0;
928                                 char *value = NULL;
929                                 struct indicate_info info;
930                                 g_variant_get(var, "(&s&s&syq@ay)",
931                                                 &char_path, &svc_handle,
932                                                 &addr, &req_id, &offset, &val);
933
934                                 len = g_variant_get_size(val);
935
936                                 BT_DBG("Len = %d, BT_ADDR = %s", len, addr);
937
938                                 value = (char *) g_variant_get_data(val);
939                                 _otp_convert_address_to_hex(&addr_hex, addr);
940
941                                 if (len != 0) {
942                                         if (!g_strcmp0(char_path, otp_oacp_obj_path)) {
943                                                 /* TODO: Handle OACP Control
944                                                  * Point requests
945                                                  */
946                                         } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) {
947                                                 result = _bt_otp_olcp_write_cb(value, len, offset, &info);
948                                         } else {
949                                                 BT_ERR("Wrong Object Path %s", char_path);
950                                                 result = BLUETOOTH_ERROR_INTERNAL;
951                                         }
952                                         bluetooth_gatt_send_response(req_id,
953                                         BLUETOOTH_GATT_ATT_REQUEST_TYPE_WRITE,
954                                                         result, 0, NULL, 0);
955
956                                         /* Send indication for CPs */
957                                         if (!g_strcmp0(char_path, otp_oacp_obj_path)) {
958                                                 /* Handle OACP Indication */
959                                         } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) {
960                                                 if (OLCP_indicate) {
961                                                         _bt_otp_send_indication(char_path, &info, &addr_hex);
962                                                 }
963                                         }
964                                 } else {
965                                         BT_ERR("Array Len 0");
966                                 }
967                         } else {
968                                 BT_ERR("var==NULL");
969                         }
970                 } else if (!g_strcmp0(property, "ReadValue")) {
971                         gchar *addr = NULL;
972                         guint8 req_id = 1;
973                         guint16 offset = 0;
974                         char *value = NULL;
975                         int len = 0;
976                         result = BLUETOOTH_ERROR_NONE;
977
978                         BT_INFO("ReadValue");
979                         BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
980
981                         g_variant_get(var, "(&s&s&syq)", &char_path,
982                                         &svc_handle, &addr, &req_id, &offset);
983
984                         result = _bt_otp_read_cb(char_path, &value, &len);
985
986                         if (result != BLUETOOTH_ERROR_NONE) {
987                                 BT_ERR("ReadValue failed %s", char_path);
988                                 bluetooth_gatt_send_response(req_id,
989                                 BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
990                                                 result, offset, NULL, 0);
991                         } else {
992                                 bluetooth_gatt_send_response(req_id,
993                                 BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
994                                                 result, offset, value, len);
995                                 if (value)
996                                         g_free(value);
997                         }
998                 } else if (!g_strcmp0(property, "NotificationStateChanged")) {
999                         gboolean indicate = FALSE;
1000
1001                         g_variant_get(var, "(&s&sb)", &char_path,
1002                                                 &svc_handle, &indicate);
1003
1004                         BT_INFO("%s : [%s]", property,
1005                                 indicate ? "StartNotify" : "StopNotify");
1006                         BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1007
1008                         if (!g_strcmp0(char_path, otp_oacp_obj_path)) {
1009                                 /* Handle OACP notification */
1010                         } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) {
1011                                 OLCP_indicate = indicate;
1012                         }
1013                 }
1014         }
1015         return;
1016 }
1017
1018 void _bt_otp_property_event_filter(GDBusConnection *connection,
1019                                         const gchar *sender_name,
1020                                         const gchar *object_path,
1021                                         const gchar *interface_name,
1022                                         const gchar *signal_name,
1023                                         GVariant *parameters,
1024                                         gpointer user_data)
1025 {
1026         GVariant *value;
1027
1028         if (signal_name == NULL) {
1029                 BT_ERR("Wrong Signal");
1030                 return;
1031         }
1032
1033         if (g_strcmp0(signal_name, PROPERTIES_CHANGED) == 0) {
1034
1035                 g_variant_get(parameters, "(@a{sv}@as)", &value, NULL);
1036                 _bt_otp_gatt_char_property_changed_event(value, object_path);
1037         }
1038 }
1039
1040 void _bt_otp_adapter_event_filter(GDBusConnection *connection,
1041                                         const gchar *sender_name,
1042                                         const gchar *object_path,
1043                                         const gchar *interface_name,
1044                                         const gchar *signal_name,
1045                                         GVariant *parameters,
1046                                         gpointer user_data)
1047 {
1048         if (signal_name == NULL) {
1049                 BT_ERR("Wrong Signal");
1050                 return;
1051         }
1052
1053         BT_INFO("Interface %s, Signal %s", interface_name, signal_name);
1054
1055         if (g_strcmp0(interface_name, BT_OTP_INTERFACE_NAME) == 0) {
1056                 if (strcasecmp(signal_name, BLE_DISABLED) == 0) {
1057                         _bt_otp_exit();
1058                 }
1059         }
1060 }
1061
1062 int _bt_otp_init_event_receiver()
1063 {
1064         BT_DBG("+");
1065         GError *error = NULL;
1066
1067         if (conn == NULL) {
1068                 conn =  g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
1069                 if (error != NULL) {
1070                         BT_ERR("ERROR: Can't get on system bus [%s]",
1071                                                         error->message);
1072                         g_clear_error(&error);
1073                 }
1074         }
1075
1076         property_sub_id = g_dbus_connection_signal_subscribe(conn,
1077                                 NULL,
1078                                 BT_OTP_INTERFACE_NAME,
1079                                 PROPERTIES_CHANGED,
1080                                 BT_OTP_OBJECT_PATH, NULL, 0,
1081                                 _bt_otp_property_event_filter,
1082                                 NULL, NULL);
1083
1084         adapter_sub_id = g_dbus_connection_signal_subscribe(conn,
1085                                 NULL,
1086                                 BT_OTP_INTERFACE_NAME,
1087                                 BLE_DISABLED,
1088                                 BT_OTP_OBJECT_PATH, NULL, 0,
1089                                 _bt_otp_adapter_event_filter,
1090                                 NULL, NULL);
1091
1092         BT_DBG("-");
1093         return 0;
1094 }
1095
1096 void _bt_otp_deinit_event_receiver(void)
1097 {
1098         BT_DBG("+");
1099
1100         g_dbus_connection_signal_unsubscribe(conn, property_sub_id);
1101         g_dbus_connection_signal_unsubscribe(conn, adapter_sub_id);
1102         conn = NULL;
1103
1104         BT_DBG("-");
1105 }
1106
1107 static void _bt_otp_sig_handler(int sig)
1108 {
1109         BT_DBG("+");
1110         switch (sig) {
1111         case SIGTERM:
1112                 BT_DBG("caught signal - sigterm\n");
1113                 break;
1114         case SIGINT:
1115                 BT_DBG("caught signal - sigint\n");
1116                 break;
1117         case SIGKILL:
1118                 BT_DBG("caught signal - sigkill\n");
1119                 break;
1120         default:
1121                 BT_DBG("caught signal %d and ignored\n", sig);
1122                 break;
1123         }
1124         BT_DBG("-");
1125 }
1126
1127 /* OTP Service Main loop */
1128 int main(void)
1129 {
1130         struct sigaction sa;
1131         BT_ERR("Starting the bt-otp daemon");
1132
1133         memset(&sa, 0, sizeof(sa));
1134         sa.sa_handler = _bt_otp_sig_handler;
1135         sa.sa_flags = SA_SIGINFO;
1136         sigaction(SIGINT, &sa, NULL);
1137         sigaction(SIGTERM, &sa, NULL);
1138         sigaction(SIGKILL, &sa, NULL);
1139
1140         if (_bt_otp_register_interface() != BLUETOOTH_ERROR_NONE) {
1141                 BT_ERR("Fail to register otp service");
1142                 return -4;
1143         }
1144
1145         if (_bt_otp_init_event_receiver() != BLUETOOTH_ERROR_NONE) {
1146                 BT_ERR("Fail to init event reciever");
1147                 return -5;
1148         }
1149
1150         main_loop = g_main_loop_new(NULL, FALSE);
1151
1152         g_main_loop_run(main_loop);
1153
1154         BT_DBG("g_main_loop_quit called!");
1155
1156         if (main_loop != NULL) {
1157                 g_main_loop_unref(main_loop);
1158         }
1159
1160         return 0;
1161 }