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>
25 #include <syspopup_caller.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"
37 #define BT_APP_AUTHENTICATION_TIMEOUT 35
38 #define BT_APP_AUTHORIZATION_TIMEOUT 15
40 #define HFP_AUDIO_GATEWAY_UUID "0000111f-0000-1000-8000-00805f9b34fb"
41 #define A2DP_UUID "0000110D-0000-1000-8000-00805F9B34FB"
42 #define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
43 #define OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
44 #define FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
45 #define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb"
46 #define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
47 #define MAP_UUID "00001132-0000-1000-8000-00805f9b34fb"
49 #define BT_AGENT_OBJECT "/org/bluez/agent/frwk_agent"
50 #define BT_AGENT_INTERFACE "org.bluez.Agent"
51 #define BT_AGENT_SIGNAL_RFCOMM_AUTHORIZE "RfcommAuthorize"
52 #define BT_AGENT_SIGNAL_OBEX_AUTHORIZE "ObexAuthorize"
54 #define BT_PIN_MAX_LENGTH 16
55 #define BT_PASSKEY_MAX_LENGTH 6
57 #define BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS 200
59 static int __bt_agent_is_auto_response(uint32_t dev_class, const gchar *address,
61 static gboolean __bt_agent_is_hid_keyboard(uint32_t dev_class);
62 static int __bt_agent_generate_passkey(char *passkey, int size);
64 static void __bt_agent_release_memory(void)
66 /* Release Malloc Memory*/
69 /* Release Stack Memory*/
73 static gboolean __bt_agent_system_popup_timer_cb(gpointer user_data)
76 bundle *b = (bundle *) user_data;
79 BT_DBG("There is some problem with the user data..popup can not be created\n");
82 ret = syspopup_launch("bt-syspopup", b);
85 BT_DBG("Sorry Can not launch popup\n");
87 BT_DBG("Hurray Popup launched \n");
93 static int __launch_system_popup(bt_agent_event_type_t event_type,
94 const char *device_name,
97 const char *agent_path)
101 char event_str[BT_MAX_EVENT_STR_LENGTH + 1];
103 BT_DBG("_bt_agent_launch_system_popup +");
109 bundle_add(b, "device-name", device_name);
110 bundle_add(b, "passkey", passkey);
111 bundle_add(b, "file", filename);
112 bundle_add(b, "agent-path", agent_path);
114 switch (event_type) {
115 case BT_AGENT_EVENT_PIN_REQUEST:
116 g_strlcpy(event_str, "pin-request", sizeof(event_str));
119 case BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST:
120 g_strlcpy(event_str, "passkey-confirm-request",
124 case BT_AGENT_EVENT_PASSKEY_REQUEST:
125 g_strlcpy(event_str, "passkey-request", sizeof(event_str));
128 case BT_AGENT_EVENT_PASSKEY_DISPLAY_REQUEST:
129 g_strlcpy(event_str, "passkey-display-request",
133 case BT_AGENT_EVENT_AUTHORIZE_REQUEST:
134 g_strlcpy(event_str, "authorize-request",
138 case BT_AGENT_EVENT_CONFIRM_MODE_REQUEST:
139 g_strlcpy(event_str, "confirm-mode-request",
143 case BT_AGENT_EVENT_FILE_RECEIVED:
144 g_strlcpy(event_str, "file-received", sizeof(event_str));
147 case BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST:
148 g_strlcpy(event_str, "keyboard-passkey-request",
152 case BT_AGENT_EVENT_TERMINATE:
153 g_strlcpy(event_str, "terminate", sizeof(event_str));
156 case BT_AGENT_EVENT_EXCHANGE_REQUEST:
157 g_strlcpy(event_str, "exchange-request", sizeof(event_str));
160 case BT_AGENT_EVENT_PBAP_REQUEST:
161 g_strlcpy(event_str, "phonebook-request", sizeof(event_str));
164 case BT_AGENT_EVENT_MAP_REQUEST:
165 g_strlcpy(event_str, "message-request", sizeof(event_str));
174 bundle_add(b, "event-type", event_str);
176 ret = syspopup_launch("bt-syspopup", b);
178 BT_DBG("Popup launch failed...retry %d\n", ret);
179 g_timeout_add(BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS,
180 (GSourceFunc) __bt_agent_system_popup_timer_cb,
186 BT_DBG("_bt_agent_launch_system_popup -%d", ret);
190 static gboolean __pincode_request(GapAgent *agent, DBusGProxy *device)
192 uint32_t device_class;
193 GHashTable *hash = NULL;
195 const gchar *address;
197 GError *error = NULL;
201 dbus_g_proxy_call(device, "GetProperties", &error,
203 dbus_g_type_get_map("GHashTable",
204 G_TYPE_STRING, G_TYPE_VALUE),
205 &hash, G_TYPE_INVALID);
207 BT_DBG("error in GetBasicProperties [%s]\n", error->message);
209 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
214 value = g_hash_table_lookup(hash, "Class");
215 device_class = value ? g_value_get_uint(value) : 0;
217 value = g_hash_table_lookup(hash, "Address");
218 address = value ? g_value_get_string(value) : NULL;
220 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
224 value = g_hash_table_lookup(hash, "Name");
225 name = value ? g_value_get_string(value) : NULL;
229 if (__bt_agent_is_auto_response(device_class, address, name)) {
230 /* Use Fixed PIN "0000" for basic pairing*/
231 _bt_set_autopair_status_in_bonding_info(TRUE);
232 gap_agent_reply_pin_code(agent, GAP_AGENT_ACCEPT, "0000",
234 } else if (__bt_agent_is_hid_keyboard(device_class)) {
235 char str_passkey[7] = { 0 };
237 __bt_agent_generate_passkey(str_passkey, sizeof(str_passkey));
239 gap_agent_reply_pin_code(agent, GAP_AGENT_ACCEPT,
242 __launch_system_popup(BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST,
243 name, str_passkey, NULL,
244 _gap_agent_get_path(agent));
246 __launch_system_popup(BT_AGENT_EVENT_PIN_REQUEST, name, NULL,
247 NULL, _gap_agent_get_path(agent));
251 g_hash_table_destroy(hash);
252 __bt_agent_release_memory();
259 static gboolean __passkey_request(GapAgent *agent, DBusGProxy *device)
261 uint32_t device_class;
262 GHashTable *hash = NULL;
264 const gchar *address;
266 GError *error = NULL;
270 dbus_g_proxy_call(device, "GetProperties", &error,
272 dbus_g_type_get_map("GHashTable",
273 G_TYPE_STRING, G_TYPE_VALUE),
274 &hash, G_TYPE_INVALID);
276 BT_DBG("error in GetBasicProperties [%s]\n", error->message);
278 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
283 value = g_hash_table_lookup(hash, "Class");
284 device_class = value ? g_value_get_uint(value) : 0;
286 value = g_hash_table_lookup(hash, "Address");
287 address = value ? g_value_get_string(value) : NULL;
289 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
293 value = g_hash_table_lookup(hash, "Name");
294 name = value ? g_value_get_string(value) : NULL;
298 __launch_system_popup(BT_AGENT_EVENT_PASSKEY_REQUEST, name, NULL, NULL,
299 _gap_agent_get_path(agent));
302 __bt_agent_release_memory();
303 g_hash_table_destroy(hash);
309 static gboolean __display_request(GapAgent *agent, DBusGProxy *device,
312 GHashTable *hash = NULL;
314 const gchar *address;
316 GError *error = NULL;
321 dbus_g_proxy_call(device, "GetProperties", &error,
323 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
325 &hash, G_TYPE_INVALID);
327 BT_DBG("error in GetBasicProperties [%s]\n", error->message);
329 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
334 value = g_hash_table_lookup(hash, "Address");
335 address = value ? g_value_get_string(value) : NULL;
337 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
341 value = g_hash_table_lookup(hash, "Name");
342 name = value ? g_value_get_string(value) : NULL;
346 str_passkey = g_strdup_printf("%d", passkey);
348 __launch_system_popup(BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST, name,
350 _gap_agent_get_path(agent));
355 __bt_agent_release_memory();
356 g_hash_table_destroy(hash);
362 static gboolean __confirm_request(GapAgent *agent, DBusGProxy *device,
365 uint32_t device_class;
366 GHashTable *hash = NULL;
368 const gchar *address;
370 GError *error = NULL;
373 BT_DBG("+ passkey[%.6d]\n", passkey);
375 snprintf(str_passkey, sizeof(str_passkey), "%.6d", passkey);
377 dbus_g_proxy_call(device, "GetProperties", &error,
379 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
381 &hash, G_TYPE_INVALID);
383 BT_DBG("error in GetBasicProperties [%s]\n", error->message);
385 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
390 value = g_hash_table_lookup(hash, "Class");
391 device_class = value ? g_value_get_uint(value) : 0;
393 value = g_hash_table_lookup(hash, "Address");
394 address = value ? g_value_get_string(value) : NULL;
396 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
400 value = g_hash_table_lookup(hash, "Name");
401 name = value ? g_value_get_string(value) : NULL;
405 __launch_system_popup(BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST, name,
407 _gap_agent_get_path(agent));
410 __bt_agent_release_memory();
411 g_hash_table_destroy(hash);
418 static gboolean __pairing_cancel_request(GapAgent *agent, const char *address)
420 BT_DBG("On Going Pairing is cancelled by remote\n");
422 gap_agent_reply_pin_code(agent, GAP_AGENT_CANCEL, "", NULL);
424 syspopup_destroy_all();
426 __bt_agent_release_memory();
431 static gboolean __authorize_request(GapAgent *agent, DBusGProxy *device,
434 GHashTable *hash = NULL;
436 const gchar *address;
440 GError *error = NULL;
441 int result = BLUETOOTH_ERROR_NONE;
442 int request_type = BT_AGENT_EVENT_AUTHORIZE_REQUEST;
446 if (!strcasecmp(uuid, HFP_AUDIO_GATEWAY_UUID) ||
447 !strcasecmp(uuid, A2DP_UUID) ||
448 !strcasecmp(uuid, AVRCP_TARGET_UUID)) {
449 BT_DBG("Auto accept authorization for audio device (HFP, A2DP, AVRCP) [%s]", uuid);
450 gap_agent_reply_authorize(agent, GAP_AGENT_ACCEPT,
456 dbus_g_proxy_call(device, "GetProperties", &error, G_TYPE_INVALID,
457 dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
459 &hash, G_TYPE_INVALID);
461 BT_DBG("error in GetBasicProperties [%s]\n", error->message);
463 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "",
468 value = g_hash_table_lookup(hash, "Address");
469 address = value ? g_value_get_string(value) : NULL;
471 gap_agent_reply_pin_code(agent, GAP_AGENT_REJECT, "", NULL);
475 value = g_hash_table_lookup(hash, "Alias");
476 name = value ? g_value_get_string(value) : NULL;
480 value = g_hash_table_lookup(hash, "Trusted");
481 trust = value ? g_value_get_boolean(value) : 0;
483 value = g_hash_table_lookup(hash, "Paired");
484 paired = value ? g_value_get_boolean(value) : 0;
485 if ((paired == FALSE) && (trust == FALSE)) {
486 BT_DBG("No paired & No trusted device");
487 gap_agent_reply_authorize(agent,
488 GAP_AGENT_REJECT, NULL);
492 BT_DBG("Authorization request for device [%s] Service:[%s]\n", address,
495 if (strcasecmp(uuid, OPP_UUID) == 0 &&
496 _gap_agent_exist_osp_server(agent, BT_OBEX_SERVER,
498 _bt_send_event(BT_OPP_SERVER_EVENT,
499 BLUETOOTH_EVENT_OBEX_SERVER_CONNECTION_AUTHORIZE,
500 DBUS_TYPE_INT32, &result,
501 DBUS_TYPE_STRING, &address,
502 DBUS_TYPE_STRING, &name,
508 if (_gap_agent_exist_osp_server(agent, BT_RFCOMM_SERVER,
509 (char *)uuid) == TRUE) {
510 bt_rfcomm_server_info_t *server_info;
512 server_info = _bt_rfcomm_get_server_info_using_uuid((char *)uuid);
513 retv_if(server_info == NULL, TRUE);
514 retv_if(server_info->server_type != BT_CUSTOM_SERVER, TRUE);
516 _bt_send_event(BT_RFCOMM_SERVER_EVENT,
517 BLUETOOTH_EVENT_RFCOMM_AUTHORIZE,
518 DBUS_TYPE_INT32, &result,
519 DBUS_TYPE_STRING, &address,
520 DBUS_TYPE_STRING, &uuid,
521 DBUS_TYPE_STRING, &name,
522 DBUS_TYPE_INT16, &server_info->control_fd,
528 if (!strcasecmp(uuid, OPP_UUID))
529 request_type = BT_AGENT_EVENT_EXCHANGE_REQUEST;
530 else if (!strcasecmp(uuid, PBAP_UUID))
531 request_type = BT_AGENT_EVENT_PBAP_REQUEST;
532 else if (!strcasecmp(uuid, MAP_UUID))
533 request_type = BT_AGENT_EVENT_MAP_REQUEST;
536 BT_DBG("Trusted device, so authorize\n");
537 gap_agent_reply_authorize(agent,
538 GAP_AGENT_ACCEPT, NULL);
540 __launch_system_popup(request_type, name, NULL, NULL,
541 _gap_agent_get_path(agent));
545 __bt_agent_release_memory();
546 g_hash_table_destroy(hash);
553 static gboolean __authorization_cancel_request(GapAgent *agent,
556 BT_DBG("On Going Authorization is cancelled by remote\n");
558 gap_agent_reply_authorize(agent, GAP_AGENT_CANCEL, NULL);
560 syspopup_destroy_all();
562 __bt_agent_release_memory();
567 void _bt_destroy_agent(void *agent)
572 _gap_agent_reset_dbus(agent);
574 g_object_unref(agent);
577 void* _bt_create_agent(const char *path, gboolean adapter)
579 GAP_AGENT_FUNC_CB func_cb;
580 DBusGProxy *adapter_proxy;
583 adapter_proxy = _bt_get_adapter_proxy();
587 func_cb.pincode_func = __pincode_request;
588 func_cb.display_func = __display_request;
589 func_cb.passkey_func = __passkey_request;
590 func_cb.confirm_func = __confirm_request;
591 func_cb.authorize_func = __authorize_request;
592 func_cb.pairing_cancel_func = __pairing_cancel_request;
593 func_cb.authorization_cancel_func = __authorization_cancel_request;
595 agent = _gap_agent_new();
597 _gap_agent_setup_dbus(agent, &func_cb, path, adapter_proxy);
600 if (!_gap_agent_register(agent)) {
601 _bt_destroy_agent(agent);
609 gboolean _bt_agent_register_osp_server(const gint type, const char *uuid)
611 void *agent = _bt_get_adapter_agent();
615 return _gap_agent_register_osp_server(agent, type, uuid);
619 gboolean _bt_agent_unregister_osp_server(const gint type, const char *uuid)
621 void *agent = _bt_get_adapter_agent();
625 return _gap_agent_unregister_osp_server(agent, type, uuid);
628 gboolean _bt_agent_reply_authorize(gboolean accept)
632 void *agent = _bt_get_adapter_agent();
636 accept_val = accept ? GAP_AGENT_ACCEPT : GAP_AGENT_REJECT;
638 return gap_agent_reply_authorize(agent, accept_val, NULL);
641 gboolean _bt_agent_is_canceled(void *agent)
643 return _gap_agent_is_canceled(agent);
646 static gboolean __bt_agent_is_hid_keyboard(uint32_t dev_class)
648 switch ((dev_class & 0x1f00) >> 8) {
650 switch ((dev_class & 0xc0) >> 6) {
652 /* input-keyboard" */
661 static gboolean __bt_agent_find_device_by_address_exactname(char *buffer,
667 pch = strtok_r(buffer, "= ,", &last);
672 while ((pch = strtok_r(NULL, ",", &last))) {
673 if (0 == g_strcmp0(pch, address)) {
674 BT_DBG("Match found\n");
681 static gboolean __bt_agent_find_device_by_partial_name(char *buffer,
682 const char *partial_name)
687 pch = strtok_r(buffer, "= ,", &last);
692 while ((pch = strtok_r(NULL, ",", &last))) {
693 if (g_str_has_prefix(partial_name, pch)) {
694 BT_DBG("Match found\n");
701 static gboolean __bt_agent_is_device_blacklist(const char *address,
713 fp = fopen(BT_AGENT_AUTO_PAIR_BLACKLIST_FILE, "r");
716 BT_DBG("fopen failed \n");
720 fseek(fp, 0, SEEK_END);
723 BT_DBG("size is not a positive number");
730 buffer = g_malloc0(sizeof(char) * size);
731 result = fread((char *)buffer, 1, size, fp);
733 if (result != size) {
734 BT_DBG("Read Error\n");
739 BT_DBG("Buffer = %s\n", buffer);
741 lines = g_strsplit_set(buffer, BT_AGENT_NEW_LINE, 0);
745 BT_DBG("No lines in the file \n");
749 for (i = 0; lines[i] != NULL; i++) {
750 if (g_str_has_prefix(lines[i], "AddressBlacklist"))
751 if (__bt_agent_find_device_by_address_exactname(
754 if (g_str_has_prefix(lines[i], "ExactNameBlacklist"))
755 if (__bt_agent_find_device_by_address_exactname(
758 if (g_str_has_prefix(lines[i], "PartialNameBlacklist"))
759 if (__bt_agent_find_device_by_partial_name(lines[i],
767 BT_DBG("Found the device\n");
772 static gboolean __bt_agent_is_auto_response(uint32_t dev_class,
773 const gchar *address, const gchar *name)
775 gboolean is_headset = FALSE;
776 char lap_address[BT_LOWER_ADDRESS_LENGTH];
778 BT_DBG("bt_agent_is_headset_class, %d +", dev_class);
783 switch ((dev_class & 0x1f00) >> 8) {
785 switch ((dev_class & 0xfc) >> 2) {
796 case 0x0c: /* Video Camera */
797 case 0x0d: /* Camcorder */
800 /* Other audio device */
810 /* Get the LAP(Lower Address part) */
811 g_strlcpy(lap_address, address, sizeof(lap_address));
813 BT_DBG("Device address = %s\n", address);
814 BT_DBG("Address 3 byte = %s\n", lap_address);
816 if (__bt_agent_is_device_blacklist(lap_address, name)) {
817 BT_DBG("Device is black listed\n");
824 static int __bt_agent_generate_passkey(char *passkey, int size)
829 unsigned int value = 0;
837 random_fd = open("/dev/urandom", O_RDONLY);
842 for (i = 0; i < size - 1; i++) {
843 len = read(random_fd, &value, sizeof(value));
844 passkey[i] = '0' + (value % 10);
849 passkey[size - 1] = '\0';
851 BT_DBG("passkey: %s", passkey);