| /* |
| * |
| * BlueZ - Bluetooth protocol stack for Linux |
| * |
| * Copyright (C) 2012 Texas Instruments, Inc. |
| * Copyright (C) 2015 Google Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdbool.h> |
| #include <errno.h> |
| |
| #include <glib.h> |
| |
| #include "lib/bluetooth.h" |
| #include "lib/sdp.h" |
| #include "lib/uuid.h" |
| |
| #include "src/plugin.h" |
| #include "src/adapter.h" |
| #include "src/device.h" |
| #include "src/profile.h" |
| #include "src/service.h" |
| #include "attrib/gattrib.h" |
| #include "src/shared/util.h" |
| #include "src/shared/queue.h" |
| #include "src/shared/gatt-db.h" |
| #include "src/shared/gatt-client.h" |
| #include "attrib/att.h" |
| #include "src/log.h" |
| |
| #define PNP_ID_SIZE 7 |
| |
| static void read_pnpid_cb(bool success, uint8_t att_ecode, const uint8_t *value, |
| uint16_t length, void *user_data) |
| { |
| struct btd_device *device = user_data; |
| |
| if (!success) { |
| error("Error reading PNP_ID value: %s", |
| att_ecode2str(att_ecode)); |
| return; |
| } |
| |
| if (length < PNP_ID_SIZE) { |
| error("Error reading PNP_ID: Invalid pdu length received"); |
| return; |
| } |
| |
| btd_device_set_pnpid(device, value[0], get_le16(&value[1]), |
| get_le16(&value[3]), get_le16(&value[5])); |
| } |
| |
| static void handle_pnpid(struct btd_device *device, uint16_t value_handle) |
| { |
| struct bt_gatt_client *client = btd_device_get_gatt_client(device); |
| |
| if (!bt_gatt_client_read_value(client, value_handle, |
| read_pnpid_cb, device, NULL)) |
| DBG("Failed to send request to read pnpid"); |
| } |
| |
| static void handle_characteristic(struct gatt_db_attribute *attr, |
| void *user_data) |
| { |
| struct btd_device *device = user_data; |
| uint16_t value_handle; |
| bt_uuid_t uuid, pnpid_uuid; |
| |
| bt_string_to_uuid(&pnpid_uuid, PNPID_UUID); |
| |
| if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL, |
| NULL, &uuid)) { |
| error("Failed to obtain characteristic data"); |
| return; |
| } |
| |
| if (bt_uuid_cmp(&pnpid_uuid, &uuid) == 0) |
| handle_pnpid(device, value_handle); |
| else { |
| char uuid_str[MAX_LEN_UUID_STR]; |
| |
| bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str)); |
| DBG("Unsupported characteristic: %s", uuid_str); |
| } |
| } |
| |
| static void foreach_deviceinfo_service(struct gatt_db_attribute *attr, |
| void *user_data) |
| { |
| struct btd_device *device = user_data; |
| |
| gatt_db_service_foreach_char(attr, handle_characteristic, device); |
| } |
| |
| static int deviceinfo_driver_probe(struct btd_service *service) |
| { |
| return 0; |
| } |
| |
| static void deviceinfo_driver_remove(struct btd_service *service) |
| { |
| } |
| |
| |
| static int deviceinfo_driver_accept(struct btd_service *service) |
| { |
| struct btd_device *device = btd_service_get_device(service); |
| struct gatt_db *db = btd_device_get_gatt_db(device); |
| char addr[18]; |
| bt_uuid_t deviceinfo_uuid; |
| |
| ba2str(device_get_address(device), addr); |
| DBG("deviceinfo profile accept (%s)", addr); |
| |
| /* Handle the device info service */ |
| bt_string_to_uuid(&deviceinfo_uuid, DEVICE_INFORMATION_UUID); |
| gatt_db_foreach_service(db, &deviceinfo_uuid, |
| foreach_deviceinfo_service, device); |
| |
| return 0; |
| } |
| |
| static struct btd_profile deviceinfo_profile = { |
| .name = "deviceinfo", |
| .remote_uuid = DEVICE_INFORMATION_UUID, |
| .external = true, |
| .device_probe = deviceinfo_driver_probe, |
| .device_remove = deviceinfo_driver_remove, |
| .accept = deviceinfo_driver_accept, |
| }; |
| |
| static int deviceinfo_init(void) |
| { |
| return btd_profile_register(&deviceinfo_profile); |
| } |
| |
| static void deviceinfo_exit(void) |
| { |
| btd_profile_unregister(&deviceinfo_profile); |
| } |
| |
| BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, |
| deviceinfo_init, deviceinfo_exit) |