4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Girishashok Joshi <girish.joshi@samsung.com>
8 * Chanyeol Park <chanyeol.park@samsung.com>
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
28 #include <stacktrim.h>
29 #include <syspopup_caller.h>
31 #include "bluetooth-agent.h"
32 #include "sc_core_agent.h"
34 extern struct bt_agent_appdata *app_data;
36 #define BT_APP_AUTHENTICATION_TIMEOUT 35
37 #define BT_APP_AUTHORIZATION_TIMEOUT 15
39 #define HFP_AUDIO_GATEWAY_UUID "0000111f-0000-1000-8000-00805f9b34fb"
40 #define A2DP_UUID "0000110D-0000-1000-8000-00805F9B34FB"
42 #define BT_PIN_MAX_LENGTH 16
43 #define BT_PASSKEY_MAX_LENGTH 6
45 #define BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS 200
47 static int __bt_agent_is_auto_response(uint32_t dev_class, const gchar *address);
48 static const int __bt_agent_is_hid_keyboard(uint32_t dev_class);
50 static void __bt_agent_release_memory(void)
52 /* Release Malloc Memory*/
55 /* Release Stack Memory*/
59 static void __bt_agent_show_confirm_mode_request(const char *mode, const char *sender,
60 gboolean need_popup, void *data)
62 bt_agent_changed_mode_type_t changed_mode = 0;
64 if (strcasecmp(mode, "enable") == 0) {
65 changed_mode = BT_AGENT_CHANGED_MODE_ENABLE;
66 } else if (strcasecmp(mode, "disable") == 0) {
67 changed_mode = BT_AGENT_CHANGED_MODE_DISABLE;
69 sc_core_agent_reply_adapter_enable(_sc_core_agent_get_proxy(), changed_mode,
70 SC_CORE_AGENT_REJECT, NULL);
74 sc_core_agent_reply_adapter_enable(_sc_core_agent_get_proxy(), changed_mode,
75 SC_CORE_AGENT_ACCEPT, NULL);
78 static gboolean __bt_agent_system_popup_timer_cb(gpointer user_data)
81 bundle *b = (bundle *) user_data;
84 DBG("There is some problem with the user data..popup can not be created\n");
87 ret = syspopup_launch("bt-syspopup", b);
90 DBG("Sorry Can not launch popup\n");
93 DBG("Hurray Popup launched \n");
99 int _bt_agent_launch_system_popup(bt_agent_event_type_t event_type, const char *device_name,
100 char *passkey, const char *filename)
104 char event_str[BT_MAX_EVENT_STR_LENGTH + 1] = { 0 };
106 DBG("_bt_agent_launch_system_popup +");
110 bundle_add(b, "device-name", device_name);
111 bundle_add(b, "passkey", passkey);
112 bundle_add(b, "file", filename);
114 switch (event_type) {
115 case BT_AGENT_EVENT_PIN_REQUEST:
116 strncpy(event_str, "pin-request", BT_MAX_EVENT_STR_LENGTH);
119 case BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST:
120 strncpy(event_str, "passkey-confirm-request", BT_MAX_EVENT_STR_LENGTH);
123 case BT_AGENT_EVENT_PASSKEY_REQUEST:
124 strncpy(event_str, "passkey-request", BT_MAX_EVENT_STR_LENGTH);
127 case BT_AGENT_EVENT_PASSKEY_DISPLAY_REQUEST:
128 strncpy(event_str, "passkey-display-request", BT_MAX_EVENT_STR_LENGTH);
131 case BT_AGENT_EVENT_AUTHORIZE_REQUEST:
132 strncpy(event_str, "authorize-request", BT_MAX_EVENT_STR_LENGTH);
135 case BT_AGENT_EVENT_CONFIRM_MODE_REQUEST:
136 strncpy(event_str, "confirm-mode-request", BT_MAX_EVENT_STR_LENGTH);
139 case BT_AGENT_EVENT_FILE_RECIEVED:
140 strncpy(event_str, "file-recieved", BT_MAX_EVENT_STR_LENGTH);
143 case BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST:
144 strncpy(event_str, "keyboard-passkey-request", BT_MAX_EVENT_STR_LENGTH);
147 case BT_AGENT_EVENT_TERMINATE:
148 strncpy(event_str, "terminate", BT_MAX_EVENT_STR_LENGTH);
157 bundle_add(b, "event-type", event_str);
159 ret = syspopup_launch("bt-syspopup", b);
161 DBG("Popup launch failed...retry %d\n", ret);
162 g_timeout_add(BT_AGENT_SYSPOPUP_TIMEOUT_FOR_MULTIPLE_POPUPS,
163 (GSourceFunc) __bt_agent_system_popup_timer_cb, b);
168 DBG("_bt_agent_launch_system_popup -%d", ret);
172 static gboolean __pincode_request(DBusGProxy *device)
174 uint32_t device_class;
175 GHashTable *hash = NULL;
177 const gchar *address, *name;
178 GError *error = NULL;
182 dbus_g_proxy_call(device, "GetProperties", &error,
184 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
185 &hash, G_TYPE_INVALID);
188 value = g_hash_table_lookup(hash, "Class");
189 device_class = value ? g_value_get_uint(value) : 0;
191 value = g_hash_table_lookup(hash, "Address");
192 address = value ? g_value_get_string(value) : NULL;
194 value = g_hash_table_lookup(hash, "Name");
195 name = value ? g_value_get_string(value) : NULL;
197 if (__bt_agent_is_auto_response(device_class, address)) {
198 /* Use Fixed PIN "0000" for basic pairing*/
199 sc_core_agent_reply_pin_code(_sc_core_agent_get_proxy(),
200 SC_CORE_AGENT_ACCEPT, "0000", NULL);
201 } else if (__bt_agent_is_hid_keyboard(device_class)) {
202 char str_passkey[7] = { 0 };
204 bt_agent_generate_passkey(str_passkey, sizeof(str_passkey));
207 _bt_agent_launch_system_popup(BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST,
208 (const char *)name, str_passkey, NULL);
210 _bt_agent_launch_system_popup(BT_AGENT_EVENT_KEYBOARD_PASSKEY_REQUEST,
211 (const char *)address, str_passkey, NULL);
213 value = g_hash_table_lookup(hash, "Name");
214 name = value ? g_value_get_string(value) : NULL;
216 if (!name && !address)
217 sc_core_agent_reply_pin_code(_sc_core_agent_get_proxy(),
218 SC_CORE_AGENT_REJECT, "", NULL);
221 _bt_agent_launch_system_popup(BT_AGENT_EVENT_PIN_REQUEST,
222 (const char *)name, NULL, NULL);
224 _bt_agent_launch_system_popup(BT_AGENT_EVENT_PIN_REQUEST,
225 (const char *)address, NULL, NULL);
229 DBG("error in GetBasicProperties [%s]\n", error->message);
232 sc_core_agent_reply_pin_code(_sc_core_agent_get_proxy(), SC_CORE_AGENT_REJECT, "",
236 __bt_agent_release_memory();
243 static gboolean __passkey_request(DBusGProxy *device)
245 GHashTable *hash = NULL;
247 const gchar *address, *name;
248 GError *error = NULL;
252 dbus_g_proxy_call(device, "GetProperties", &error,
254 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
255 &hash, G_TYPE_INVALID);
258 value = g_hash_table_lookup(hash, "Address");
259 address = value ? g_value_get_string(value) : NULL;
261 value = g_hash_table_lookup(hash, "Name");
262 name = value ? g_value_get_string(value) : NULL;
264 if (!name && !address)
265 sc_core_agent_reply_passkey(_sc_core_agent_get_proxy(),
266 SC_CORE_AGENT_REJECT, "", NULL);
269 _bt_agent_launch_system_popup(BT_AGENT_EVENT_PASSKEY_REQUEST,
270 (const char *)name, NULL, NULL);
272 _bt_agent_launch_system_popup(BT_AGENT_EVENT_PASSKEY_REQUEST,
273 (const char *)address, NULL, NULL);
276 DBG("error in GetBasicProperties [%s]\n", error->message);
279 sc_core_agent_reply_passkey(_sc_core_agent_get_proxy(), SC_CORE_AGENT_REJECT, "",
283 __bt_agent_release_memory();
290 static gboolean __display_request(DBusGProxy *device, guint passkey, guint entered)
292 GHashTable *hash = NULL;
294 const gchar *address, *name;
295 GError *error = NULL;
299 dbus_g_proxy_call(device, "GetProperties", &error,
301 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
302 &hash, G_TYPE_INVALID);
305 value = g_hash_table_lookup(hash, "Address");
306 address = value ? g_value_get_string(value) : NULL;
308 value = g_hash_table_lookup(hash, "Name");
309 name = value ? g_value_get_string(value) : NULL;
311 DBG("error in GetBasicProperties [%s]\n", error->message);
316 __bt_agent_release_memory();
323 static gboolean __confirm_request(DBusGProxy *device, guint passkey)
325 GHashTable *hash = NULL;
327 const gchar *address, *name;
328 GError *error = NULL;
329 char str_passkey[7] = { 0 };
331 DBG("+ passkey[%.6d]\n", passkey);
333 snprintf(str_passkey, sizeof(str_passkey), "%.6d", passkey);
335 dbus_g_proxy_call(device, "GetProperties", &error,
337 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
338 &hash, G_TYPE_INVALID);
341 value = g_hash_table_lookup(hash, "Address");
342 address = value ? g_value_get_string(value) : NULL;
344 value = g_hash_table_lookup(hash, "Name");
345 name = value ? g_value_get_string(value) : NULL;
348 _bt_agent_launch_system_popup(BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST,
349 (const char *)name, str_passkey, NULL);
350 else if (address != NULL)
351 _bt_agent_launch_system_popup(BT_AGENT_EVENT_PASSKEY_CONFIRM_REQUEST,
352 (const char *)address, str_passkey, NULL);
354 sc_core_agent_reply_confirmation(_sc_core_agent_get_proxy(),
355 SC_CORE_AGENT_REJECT, NULL);
357 DBG("error in GetBasicProperties [%s]\n", error->message);
360 sc_core_agent_reply_confirmation(_sc_core_agent_get_proxy(), SC_CORE_AGENT_REJECT,
364 __bt_agent_release_memory();
371 static gboolean __pairing_cancel_request(const char *address)
373 DBG("On Going Pairing is cancelled by remote\n");
375 sc_core_agent_reply_pin_code(_sc_core_agent_get_proxy(), SC_CORE_AGENT_CANCEL, "", NULL);
377 _bt_agent_launch_system_popup(BT_AGENT_EVENT_TERMINATE, NULL, NULL, NULL);
379 __bt_agent_release_memory();
384 static gboolean __authorize_request(DBusGProxy *device, const char *uuid)
386 GHashTable *hash = NULL;
388 const gchar *address, *name;
389 gboolean trust = FALSE;
390 GError *error = NULL;
394 if (!strcasecmp(uuid, HFP_AUDIO_GATEWAY_UUID) || !strcasecmp(uuid, A2DP_UUID)) {
395 DBG("In case of audio device(HFP,A2DP), we authorize the request [%s]\n", uuid);
396 sc_core_agent_reply_authorize(_sc_core_agent_get_proxy(), SC_CORE_AGENT_ACCEPT,
402 dbus_g_proxy_call(device, "GetProperties", &error, G_TYPE_INVALID,
403 dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
404 &hash, G_TYPE_INVALID);
407 value = g_hash_table_lookup(hash, "Address");
408 address = value ? g_value_get_string(value) : NULL;
410 value = g_hash_table_lookup(hash, "Name");
411 name = value ? g_value_get_string(value) : NULL;
413 value = g_hash_table_lookup(hash, "Trusted");
414 trust = value ? g_value_get_boolean(value) : 0;
416 DBG("Authorization request for device [%s] Service:[%s]\n", address, uuid);
419 DBG("Trusted device, so authorize\n");
420 sc_core_agent_reply_authorize(_sc_core_agent_get_proxy(),
421 SC_CORE_AGENT_ACCEPT, NULL);
422 } else if (name != NULL)
423 _bt_agent_launch_system_popup(BT_AGENT_EVENT_AUTHORIZE_REQUEST,
424 (const char *)name, NULL, NULL);
425 else if (address != NULL)
426 _bt_agent_launch_system_popup(BT_AGENT_EVENT_AUTHORIZE_REQUEST,
427 (const char *)address, NULL, NULL);
429 sc_core_agent_reply_authorize(_sc_core_agent_get_proxy(),
430 SC_CORE_AGENT_REJECT, NULL);
432 DBG("error in GetBasicProperties [%s]\n", error->message);
435 sc_core_agent_reply_authorize(_sc_core_agent_get_proxy(), SC_CORE_AGENT_REJECT,
439 __bt_agent_release_memory();
446 static gboolean __authorization_cancel_request(const char *address)
448 DBG("On Going Authorization is cancelled by remote\n");
450 sc_core_agent_reply_authorize(_sc_core_agent_get_proxy(), SC_CORE_AGENT_CANCEL, NULL);
452 _bt_agent_launch_system_popup(BT_AGENT_EVENT_TERMINATE, NULL, NULL, NULL);
454 __bt_agent_release_memory();
459 static gboolean __confirm_mode_request(const char *mode, const char *sender, gboolean need_popup,
465 __bt_agent_show_confirm_mode_request(mode, sender, need_popup, data);
467 DBG("Wrong mode requested [%s]\n", mode);
468 sc_core_agent_reply_adapter_enable(_sc_core_agent_get_proxy(),
469 BT_AGENT_CHANGED_MODE_ENABLE,
470 SC_CORE_AGENT_REJECT, NULL);
473 __bt_agent_release_memory();
480 static gboolean __ignore_auto_pairing_request(const char *address)
484 struct bt_agent_appdata *ad = (struct bt_agent_appdata *)app_data;
489 /* To input the pin code, if headset does not have '0000' pin code */
490 ad->ignore_auto_pairing = 1;
491 memset(ad->bonding_addr, 0x00, BT_AGENT_ADDR_SIZE + 1);
492 strncpy(ad->bonding_addr, address, BT_AGENT_ADDR_SIZE);
499 void _bt_agent_register(DBusGProxy *adapter_proxy)
501 SC_CORE_AGENT_FUNC_CB func_cb = { 0 };
503 func_cb.pincode_func = __pincode_request;
504 func_cb.display_func = __display_request;
505 func_cb.passkey_func = __passkey_request;
506 func_cb.confirm_func = __confirm_request;
507 func_cb.authorize_func = __authorize_request;
508 func_cb.pairing_cancel_func = __pairing_cancel_request;
509 func_cb.authorization_cancel_func = __authorization_cancel_request;
510 func_cb.confirm_mode_func = __confirm_mode_request;
511 func_cb.ignore_auto_pairing_func = __ignore_auto_pairing_request;
513 if (_sc_core_agent_add(adapter_proxy, &func_cb) < 0) {
514 if (adapter_proxy == NULL) {
517 ERR("Agent register failed, Agent finish.\n");
520 DBG("Agent registered.\n");
523 static const int __bt_agent_is_hid_keyboard(uint32_t dev_class)
527 switch ((dev_class & 0x1f00) >> 8) {
529 switch ((dev_class & 0xc0) >> 6) {
531 /* input-keyboard";*/
538 DBG("is_keyboard: %d\n", is_keyboard);
543 static int __bt_agent_is_auto_response(uint32_t dev_class, const gchar *address)
545 DBG("bt_agent_is_headset_class, %d +", dev_class);
547 int is_headset = 0, ret = 0;
548 struct bt_agent_appdata *ad = (struct bt_agent_appdata *)app_data;
553 switch ((dev_class & 0x1f00) >> 8) {
555 switch ((dev_class & 0xfc) >> 2) {
566 case 0x0c: /* Video Camera */
567 case 0x0d: /* Camcorder */
570 /* Other audio device */
578 if (ad->ignore_auto_pairing == 0 || (strcmp(address, ad->bonding_addr) != 0))
582 ad->ignore_auto_pairing = 0;
583 memset(ad->bonding_addr, 0x00, BT_AGENT_ADDR_SIZE + 1);
588 int bt_agent_generate_passkey(char *passkey, int size)
592 unsigned int value = 0;
600 random_fd = open("/dev/urandom", O_RDONLY);
605 for (i = 0; i < size - 1; i++) {
606 read(random_fd, &value, sizeof(value));
607 passkey[i] = '0' + (value % 10);
612 passkey[size - 1] = '\0';
614 DBG("passkey: %s", passkey);