4 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
24 #include <stacktrim.h>
26 #include <tethering.h>
28 #include "bt-internal-types.h"
29 #include "bt-service-common.h"
30 #include "bt-service-agent.h"
31 #include "bt-service-gap-agent.h"
32 #include "bt-service-adapter.h"
33 #include "bt-service-event.h"
34 #include "bt-service-rfcomm-server.h"
35 #include "bt-service-device.h"
36 #include "bt-service-audio.h"
38 #if defined(LIBNOTIFY_SUPPORT)
40 #elif defined(LIBNOTIFICATION_SUPPORT)
41 #include "bt-service-agent-notification.h"
43 #include <syspopup_caller.h>
46 #define BT_APP_AUTHENTICATION_TIMEOUT 35
47 #define BT_APP_AUTHORIZATION_TIMEOUT 15
49 #define HFP_AUDIO_GATEWAY_UUID "0000111f-0000-1000-8000-00805f9b34fb"
50 #define A2DP_UUID "0000110D-0000-1000-8000-00805F9B34FB"
51 #define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
52 #define OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
53 #define FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
54 #define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb"
55 #define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
56 #define MAP_UUID "00001132-0000-1000-8000-00805f9b34fb"
57 #define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
58 #define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
59 #define BNEP_UUID "0000000f-0000-1000-8000-00805f9b34fb"
60 #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
62 #define BT_AGENT_OBJECT "/org/bluez/agent/frwk_agent"
63 #define BT_AGENT_SIGNAL_RFCOMM_AUTHORIZE "RfcommAuthorize"
64 #define BT_AGENT_SIGNAL_OBEX_AUTHORIZE "ObexAuthorize"
66 #define BT_PIN_MAX_LENGTH 16
67 #define BT_PASSKEY_MAX_LENGTH 4
69 #define BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS 200
71 static int __bt_agent_is_auto_response(uint32_t dev_class, const gchar *address,
73 static gboolean __bt_agent_is_hid_keyboard(uint32_t dev_class);
74 static int __bt_agent_generate_passkey(char *passkey, int size);
76 static void __bt_agent_release_memory(void)
78 /* Release Malloc Memory*/
81 /* Release Stack Memory*/
85 static int __syspopup_launch(gpointer user_data)
88 bundle *b = (bundle *) user_data;
89 #if defined(LIBNOTIFY_SUPPORT)
90 ret = notify_launch(b);
91 #elif defined(LIBNOTIFICATION_SUPPORT)
92 ret = notification_launch(b);
94 ret = syspopup_launch("bt-syspopup", b);
99 static gboolean __bt_agent_system_popup_timer_cb(gpointer user_data)
102 bundle *b = (bundle *) user_data;
105 BT_DBG("There is some problem with the user data..popup can not be created\n");
108 ret = __syspopup_launch(b);
111 BT_DBG("Sorry Can not launch popup\n");
113 BT_DBG("Hurray Popup launched \n");
119 static int __launch_system_popup(bt_agent_event_type_t event_type,
120 const char *device_name,
122 const char *filename,
123 const char *agent_path)
127 char event_str[BT_MAX_EVENT_STR_LENGTH + 1];
129 BT_DBG("_bt_agent_launch_system_popup +");
135 bundle_add(b, "device-name", device_name);
136 bundle_add(b, "passkey", passkey);
137 bundle_add(b, "file", filename);
138 bundle_add(b, "agent-path", agent_path);
140 switch (event_type) {
141 case BT_AGENT_EVENT_PIN_REQUEST:
142 g_strlcpy(event_str, "pin-request", sizeof(event_str));
145 case BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST:
146 g_strlcpy(event_str, "passkey-confirm-request",
150 case BT_AGENT_EVENT_PASSKEY_REQUEST:
151 g_strlcpy(event_str, "passkey-request", sizeof(event_str));
154 case BT_AGENT_EVENT_PASSKEY_DISPLAY_REQUEST:
155 g_strlcpy(event_str, "passkey-display-request",
159 case BT_AGENT_EVENT_AUTHORIZE_REQUEST:
160 g_strlcpy(event_str, "authorize-request",
164 case BT_AGENT_EVENT_CONFIRM_MODE_REQUEST:
165 g_strlcpy(event_str, "confirm-mode-request",
169 case BT_AGENT_EVENT_FILE_RECEIVED:
170 g_strlcpy(event_str, "file-received", sizeof(event_str));
173 case BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST:
174 g_strlcpy(event_str, "keyboard-passkey-request",
178 case BT_AGENT_EVENT_TERMINATE:
179 g_strlcpy(event_str, "terminate", sizeof(event_str));
182 case BT_AGENT_EVENT_EXCHANGE_REQUEST:
183 g_strlcpy(event_str, "exchange-request", sizeof(event_str));
186 case BT_AGENT_EVENT_PBAP_REQUEST:
187 g_strlcpy(event_str, "phonebook-request", sizeof(event_str));
190 case BT_AGENT_EVENT_MAP_REQUEST:
191 g_strlcpy(event_str, "message-request", sizeof(event_str));
200 bundle_add(b, "event-type", event_str);
202 ret = __syspopup_launch(b);
204 BT_DBG("Popup launch failed...retry %d\n", ret);
205 g_timeout_add(BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS,
206 (GSourceFunc) __bt_agent_system_popup_timer_cb,
212 BT_DBG("_bt_agent_launch_system_popup -%d", ret);
216 static gboolean __pincode_request(GapAgent *agent, DBusGProxy *device)
218 uint32_t device_class;
219 GHashTable *hash = NULL;
221 const gchar *address;
223 GError *error = NULL;
227 dbus_g_proxy_call(device, "GetAll", &error,
228 G_TYPE_STRING, BT_DEVICE_INTERFACE,
230 dbus_g_type_get_map("GHashTable",
231 G_TYPE_STRING, G_TYPE_VALUE),
232 &hash, G_TYPE_INVALID);
234 BT_DBG("error in GetAll [%s]\n", error->message);
236 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
241 value = g_hash_table_lookup(hash, "Class");
242 device_class = value ? g_value_get_uint(value) : 0;
244 value = g_hash_table_lookup(hash, "Address");
245 address = value ? g_value_get_string(value) : NULL;
247 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
251 value = g_hash_table_lookup(hash, "Name");
252 name = value ? g_value_get_string(value) : NULL;
256 if (__bt_agent_is_auto_response(device_class, address, name)) {
257 /* Use Fixed PIN "0000" for basic pairing*/
258 _bt_set_autopair_status_in_bonding_info(TRUE);
259 gap_agent_reply_pin_code(agent, GAP_AGENT_ACCEPT, "0000",
261 } else if (__bt_agent_is_hid_keyboard(device_class)) {
262 char str_passkey[BT_PASSKEY_MAX_LENGTH + 1] = { 0 };
264 if (__bt_agent_generate_passkey(str_passkey,
265 BT_PASSKEY_MAX_LENGTH) != 0) {
266 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT,
271 gap_agent_reply_pin_code(agent, GAP_AGENT_ACCEPT,
274 __launch_system_popup(BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST,
275 name, str_passkey, NULL,
276 _gap_agent_get_path(agent));
278 __launch_system_popup(BT_AGENT_EVENT_PIN_REQUEST, name, NULL,
279 NULL, _gap_agent_get_path(agent));
283 g_hash_table_destroy(hash);
284 __bt_agent_release_memory();
291 static gboolean __passkey_request(GapAgent *agent, DBusGProxy *device)
293 uint32_t device_class;
294 GHashTable *hash = NULL;
296 const gchar *address;
298 GError *error = NULL;
302 dbus_g_proxy_call(device, "GetAll", &error,
303 G_TYPE_STRING, BT_DEVICE_INTERFACE,
305 dbus_g_type_get_map("GHashTable",
306 G_TYPE_STRING, G_TYPE_VALUE),
307 &hash, G_TYPE_INVALID);
309 BT_DBG("error in GetAll [%s]\n", error->message);
311 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
316 value = g_hash_table_lookup(hash, "Class");
317 device_class = value ? g_value_get_uint(value) : 0;
319 value = g_hash_table_lookup(hash, "Address");
320 address = value ? g_value_get_string(value) : NULL;
322 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
326 value = g_hash_table_lookup(hash, "Name");
327 name = value ? g_value_get_string(value) : NULL;
331 __launch_system_popup(BT_AGENT_EVENT_PASSKEY_REQUEST, name, NULL, NULL,
332 _gap_agent_get_path(agent));
335 __bt_agent_release_memory();
336 g_hash_table_destroy(hash);
342 static gboolean __display_request(GapAgent *agent, DBusGProxy *device,
345 GHashTable *hash = NULL;
347 const gchar *address;
349 GError *error = NULL;
354 dbus_g_proxy_call(device, "GetAll", &error,
355 G_TYPE_STRING, BT_DEVICE_INTERFACE,
357 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
359 &hash, G_TYPE_INVALID);
361 BT_DBG("error in GetAll [%s]\n", error->message);
363 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
368 value = g_hash_table_lookup(hash, "Address");
369 address = value ? g_value_get_string(value) : NULL;
371 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
375 value = g_hash_table_lookup(hash, "Name");
376 name = value ? g_value_get_string(value) : NULL;
380 str_passkey = g_strdup_printf("%d", passkey);
382 __launch_system_popup(BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST, name,
384 _gap_agent_get_path(agent));
389 __bt_agent_release_memory();
390 g_hash_table_destroy(hash);
396 static gboolean __confirm_request(GapAgent *agent, DBusGProxy *device,
399 uint32_t device_class;
400 GHashTable *hash = NULL;
402 const gchar *address;
404 GError *error = NULL;
407 BT_DBG("+ passkey[%.6d]\n", passkey);
409 dbus_g_proxy_call(device, "GetAll", &error,
410 G_TYPE_STRING, BT_DEVICE_INTERFACE,
412 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
413 G_TYPE_VALUE), &hash, G_TYPE_INVALID);
416 BT_DBG("error in GetAll [%s]\n", error->message);
418 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
423 value = g_hash_table_lookup(hash, "Class");
424 device_class = value ? g_value_get_uint(value) : 0;
426 value = g_hash_table_lookup(hash, "Address");
427 address = value ? g_value_get_string(value) : NULL;
429 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
433 value = g_hash_table_lookup(hash, "Name");
434 name = value ? g_value_get_string(value) : NULL;
438 snprintf(str_passkey, sizeof(str_passkey), "%.6d", passkey);
440 __launch_system_popup(BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST, name,
442 _gap_agent_get_path(agent));
444 __bt_agent_release_memory();
445 g_hash_table_destroy(hash);
452 static gboolean __pairing_cancel_request(GapAgent *agent, const char *address)
454 BT_DBG("On Going Pairing is cancelled by remote\n");
456 gap_agent_reply_pin_code(agent, GAP_AGENT_CANCEL, "", NULL);
458 #if !defined(LIBNOTIFY_SUPPORT) && !defined(LIBNOTIFICATION_SUPPORT)
459 syspopup_destroy_all();
462 __bt_agent_release_memory();
467 static gboolean __a2dp_authorize_request_check(void)
469 /* Check for existing Media device to disconnect */
470 return _bt_is_headset_type_connected(BT_AUDIO_A2DP, NULL);
473 static gboolean __authorize_request(GapAgent *agent, DBusGProxy *device,
476 GHashTable *hash = NULL;
478 const gchar *address;
483 tethering_h tethering = NULL;
484 GError *error = NULL;
486 int result = BLUETOOTH_ERROR_NONE;
487 int request_type = BT_AGENT_EVENT_AUTHORIZE_REQUEST;
491 /* Check if already Media connection exsist */
492 if (!strcasecmp(uuid, A2DP_UUID)) {
493 gboolean ret = FALSE;
495 ret = __a2dp_authorize_request_check();
498 BT_DBG("Already one A2DP device connected \n");
499 gap_agent_reply_authorize(agent, GAP_AGENT_REJECT,
504 /* Check completed */
506 if (!strcasecmp(uuid, HFP_AUDIO_GATEWAY_UUID) ||
507 !strcasecmp(uuid, A2DP_UUID) ||
508 !strcasecmp(uuid, HID_UUID) ||
509 !strcasecmp(uuid, AVRCP_TARGET_UUID)) {
510 BT_DBG("Auto accept authorization for audio device (HFP, A2DP, AVRCP) [%s]", uuid);
511 gap_agent_reply_authorize(agent, GAP_AGENT_ACCEPT,
517 if (!strcasecmp(uuid, NAP_UUID) ||
518 !strcasecmp(uuid, GN_UUID) ||
519 !strcasecmp(uuid, BNEP_UUID)) {
521 BT_DBG("Network connection request: %s", uuid);
522 ret = tethering_create(&tethering);
524 if (ret != TETHERING_ERROR_NONE) {
525 BT_ERR("Fail to create tethering: %d", ret);
529 enabled = tethering_is_enabled(tethering, TETHERING_TYPE_BT);
531 ret = tethering_destroy(tethering);
533 if (ret != TETHERING_ERROR_NONE) {
534 BT_ERR("Fail to create tethering: %d", ret);
537 if (enabled != true) {
538 BT_ERR("BT tethering is not enabled");
542 gap_agent_reply_authorize(agent, GAP_AGENT_ACCEPT,
546 gap_agent_reply_authorize(agent, GAP_AGENT_REJECT,
552 dbus_g_proxy_call(device, "GetAll", &error,
553 G_TYPE_STRING, BT_DEVICE_INTERFACE,
555 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
557 &hash, G_TYPE_INVALID);
559 BT_DBG("error in GetAll [%s]\n", error->message);
561 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
566 value = g_hash_table_lookup(hash, "Address");
567 address = value ? g_value_get_string(value) : NULL;
569 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
573 value = g_hash_table_lookup(hash, "Alias");
574 name = value ? g_value_get_string(value) : NULL;
578 value = g_hash_table_lookup(hash, "Trusted");
579 trust = value ? g_value_get_boolean(value) : 0;
581 value = g_hash_table_lookup(hash, "Paired");
582 paired = value ? g_value_get_boolean(value) : 0;
583 if ((paired == FALSE) && (trust == FALSE)) {
584 BT_DBG("No paired & No trusted device");
585 gap_agent_reply_authorize(agent,
586 GAP_AGENT_REJECT, NULL);
590 BT_DBG("Authorization request for device [%s] Service:[%s]\n", address,
593 if (strcasecmp(uuid, OPP_UUID) == 0 &&
594 _gap_agent_exist_osp_server(agent, BT_OBEX_SERVER,
596 _bt_send_event(BT_OPP_SERVER_EVENT,
597 BLUETOOTH_EVENT_OBEX_SERVER_CONNECTION_AUTHORIZE,
598 DBUS_TYPE_INT32, &result,
599 DBUS_TYPE_STRING, &address,
600 DBUS_TYPE_STRING, &name,
606 if (_gap_agent_exist_osp_server(agent, BT_RFCOMM_SERVER,
607 (char *)uuid) == TRUE) {
608 bt_rfcomm_server_info_t *server_info;
610 server_info = _bt_rfcomm_get_server_info_using_uuid((char *)uuid);
611 retv_if(server_info == NULL, TRUE);
612 retv_if(server_info->server_type != BT_CUSTOM_SERVER, TRUE);
614 _bt_send_event(BT_RFCOMM_SERVER_EVENT,
615 BLUETOOTH_EVENT_RFCOMM_AUTHORIZE,
616 DBUS_TYPE_INT32, &result,
617 DBUS_TYPE_STRING, &address,
618 DBUS_TYPE_STRING, &uuid,
619 DBUS_TYPE_STRING, &name,
620 DBUS_TYPE_INT16, &server_info->control_fd,
626 if (!strcasecmp(uuid, OPP_UUID))
627 request_type = BT_AGENT_EVENT_EXCHANGE_REQUEST;
628 else if (!strcasecmp(uuid, PBAP_UUID))
629 request_type = BT_AGENT_EVENT_PBAP_REQUEST;
630 else if (!strcasecmp(uuid, MAP_UUID))
631 request_type = BT_AGENT_EVENT_MAP_REQUEST;
634 BT_DBG("Trusted device, so authorize\n");
635 gap_agent_reply_authorize(agent,
636 GAP_AGENT_ACCEPT, NULL);
638 __launch_system_popup(request_type, name, NULL, NULL,
639 _gap_agent_get_path(agent));
643 __bt_agent_release_memory();
644 g_hash_table_destroy(hash);
651 static gboolean __authorization_cancel_request(GapAgent *agent,
654 BT_DBG("On Going Authorization is cancelled by remote\n");
656 gap_agent_reply_authorize(agent, GAP_AGENT_CANCEL, NULL);
658 #if !defined(LIBNOTIFY_SUPPORT) && !defined(LIBNOTIFICATION_SUPPORT)
659 syspopup_destroy_all();
662 __bt_agent_release_memory();
667 void _bt_destroy_agent(void *agent)
672 _gap_agent_reset_dbus(agent);
674 g_object_unref(agent);
677 void* _bt_create_agent(const char *path, gboolean adapter)
679 GAP_AGENT_FUNC_CB func_cb;
682 func_cb.pincode_func = __pincode_request;
683 func_cb.display_func = __display_request;
684 func_cb.passkey_func = __passkey_request;
685 func_cb.confirm_func = __confirm_request;
686 func_cb.authorize_func = __authorize_request;
687 func_cb.pairing_cancel_func = __pairing_cancel_request;
688 func_cb.authorization_cancel_func = __authorization_cancel_request;
690 agent = _gap_agent_new();
692 _gap_agent_setup_dbus(agent, &func_cb, path);
695 if (!_gap_agent_register(agent)) {
696 _bt_destroy_agent(agent);
704 gboolean _bt_agent_register_osp_server(const gint type, const char *uuid)
706 void *agent = _bt_get_adapter_agent();
710 return _gap_agent_register_osp_server(agent, type, uuid);
714 gboolean _bt_agent_unregister_osp_server(const gint type, const char *uuid)
716 void *agent = _bt_get_adapter_agent();
720 return _gap_agent_unregister_osp_server(agent, type, uuid);
723 gboolean _bt_agent_reply_authorize(gboolean accept)
727 void *agent = _bt_get_adapter_agent();
731 accept_val = accept ? GAP_AGENT_ACCEPT : GAP_AGENT_REJECT;
733 return gap_agent_reply_authorize(agent, accept_val, NULL);
736 gboolean _bt_agent_is_canceled(void *agent)
738 return _gap_agent_is_canceled(agent);
741 static gboolean __bt_agent_is_hid_keyboard(uint32_t dev_class)
743 switch ((dev_class & 0x1f00) >> 8) {
745 switch ((dev_class & 0xc0) >> 6) {
747 /* input-keyboard" */
756 static gboolean __bt_agent_find_device_by_address_exactname(char *buffer,
762 pch = strtok_r(buffer, "= ,", &last);
767 while ((pch = strtok_r(NULL, ",", &last))) {
768 if (0 == g_strcmp0(pch, address)) {
769 BT_DBG("Match found\n");
776 static gboolean __bt_agent_find_device_by_partial_name(char *buffer,
777 const char *partial_name)
782 pch = strtok_r(buffer, "= ,", &last);
787 while ((pch = strtok_r(NULL, ",", &last))) {
788 if (g_str_has_prefix(partial_name, pch)) {
789 BT_DBG("Match found\n");
796 static gboolean __bt_agent_is_device_blacklist(const char *address,
808 fp = fopen(BT_AGENT_AUTO_PAIR_BLACKLIST_FILE, "r");
811 BT_DBG("fopen failed \n");
815 fseek(fp, 0, SEEK_END);
818 BT_DBG("size is not a positive number");
825 buffer = g_malloc0(sizeof(char) * size);
826 result = fread((char *)buffer, 1, size, fp);
828 if (result != size) {
829 BT_DBG("Read Error\n");
834 BT_DBG("Buffer = %s\n", buffer);
836 lines = g_strsplit_set(buffer, BT_AGENT_NEW_LINE, 0);
840 BT_DBG("No lines in the file \n");
844 for (i = 0; lines[i] != NULL; i++) {
845 if (g_str_has_prefix(lines[i], "AddressBlacklist"))
846 if (__bt_agent_find_device_by_address_exactname(
849 if (g_str_has_prefix(lines[i], "ExactNameBlacklist"))
850 if (__bt_agent_find_device_by_address_exactname(
853 if (g_str_has_prefix(lines[i], "PartialNameBlacklist"))
854 if (__bt_agent_find_device_by_partial_name(lines[i],
862 BT_DBG("Found the device\n");
867 static gboolean __bt_agent_is_auto_response(uint32_t dev_class,
868 const gchar *address, const gchar *name)
870 gboolean is_headset = FALSE;
871 char lap_address[BT_LOWER_ADDRESS_LENGTH];
873 BT_DBG("bt_agent_is_headset_class, %d +", dev_class);
878 switch ((dev_class & 0x1f00) >> 8) {
880 switch ((dev_class & 0xfc) >> 2) {
891 case 0x0c: /* Video Camera */
892 case 0x0d: /* Camcorder */
895 /* Other audio device */
905 /* Get the LAP(Lower Address part) */
906 g_strlcpy(lap_address, address, sizeof(lap_address));
908 BT_DBG("Device address = %s\n", address);
909 BT_DBG("Address 3 byte = %s\n", lap_address);
911 if (__bt_agent_is_device_blacklist(lap_address, name)) {
912 BT_DBG("Device is black listed\n");
919 static int __bt_agent_generate_passkey(char *passkey, int size)
924 unsigned int value = 0;
932 random_fd = open("/dev/urandom", O_RDONLY);
937 for (i = 0; i < size; i++) {
938 len = read(random_fd, &value, sizeof(value));
939 passkey[i] = '0' + (value % 10);
944 BT_DBG("passkey: %s", passkey);